2015-01-01 6 views
9

私はclangを使用してLLVM IRを生成し、次にJITコンパイルしてホストアプリケーションから実行するプロジェクトに取り組んでいます。 JITコードは、例外をスローする可能性があるホストアプリケーション内のいくつかの関数を呼び出します。例外がJITコードを介してスローされ、ホストアプリケーションに戻ってくることが予想されます。 AFAIKこれはLLVMで動作するはずですが、残念ながら私のテストアプリケーションは常に "intのインスタンスを投げた後に呼び出された"終了でクラッシュします。簡単な例を挙げておきます。LLVM JIT:JITコードによるC++例外をホストアプリケーションに戻す

私はLLVM IRに次の簡単なプログラムをコンパイルするために打ち鳴らす3.5を使用し

./clang -O0 -S -emit-llvm test.cpp -c 

extern void test() ; 

extern "C" void exec(void*) { 
     test(); 
} 

結果がtest.ll

; ModuleID = 'test.cpp' 
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 
target triple = "x86_64-unknown-linux-gnu" 

; Function Attrs: uwtable 
define void @exec(i8*) #0 { 
    %2 = alloca i8*, align 8 
    store i8* %0, i8** %2, align 8 
    call void @_Z4testv() 
    ret void 
} 

declare void @_Z4testv() #1 

attributes #0 = { uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } 
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } 

!llvm.ident = !{!0} 

!0 = metadata !{metadata !"clang version 3.5.0 (224841)"} 

私のホストアプリケーションの外観ですこのように:

static void test() { 
    throw 1; 
} 

int main(int, const char **) { 
    llvm::InitializeNativeTarget(); 
    llvm::InitializeNativeTargetAsmPrinter(); 
    llvm::InitializeNativeTargetAsmParser(); 

    llvm::LLVMContext &Context = llvm::getGlobalContext(); 
    llvm::SMDiagnostic Err; 
    llvm::Module *Mod = llvm::ParseIRFile("test.ll", Err, Context); 

    llvm::ExecutionEngine* m_EE = llvm::EngineBuilder(Mod) 
      .setEngineKind(llvm::EngineKind::JIT) 
      .create(); 

    llvm::Function* f = Mod->getFunction("_Z4testv"); 
    m_EE->addGlobalMapping(f, reinterpret_cast<void*>(test)); 

    f = Mod->getFunction("exec"); 

    void* poi = m_EE->getPointerToFunction(f); 
    void (*exec)(void*) = reinterpret_cast<void (*)(void*)>(poi); 

    try { 
     exec(NULL); 
    } catch (...) { 
     std::cout << "catched exception" << std::endl; 
    } 

    return 0; 
} 

私はcmakeでコンパイルしたLLVM 3.5を使用します。私はLLVM_ENABLE_EH = ONとLLVM_ENABLE_RTTI = ONに設定しました。 LLVMをコンパイルするときに何かが恋しくなったり、ホストアプリケーションのコードが間違っていましたか?

ありがとうございます!

答えて

6

最後に動作しますが、ここでは問題を解決するために必要ないくつかのことがあります。

MCJIT.hが含まれていることを確認することが重要です。それ以外の場合はMCJITはリンクされません。残念ながら、MCJIT.hが明示的に要求されていないにもかかわらずLLVMが黙って古いJIT実装に戻ります。 :

llvm::EngineBuilder factory(Mod); 
factory.setEngineKind(llvm::EngineKind::JIT); 
factory.setUseMCJIT(true); 

のみMCJITはpropper例外処理をサポートしています。私はMCJITでは動作しません

Execution::Engine::addGlobalMapping() 

を使用し、問題の例では

。外部関数は、完全な例に続き

llvm::sys::DynamicLibrary::AddSymbol() 

経由reqisteredする必要があります。

Opts.JITEmitDebugInfo = true; 
を:

static void test() { 
    throw 1; 
} 

int main(int, const char **) { 
    llvm::InitializeNativeTarget(); 
    llvm::InitializeNativeTargetAsmPrinter(); 
    llvm::InitializeNativeTargetAsmParser(); 

    llvm::LLVMContext &Context = llvm::getGlobalContext(); 
    llvm::SMDiagnostic Err; 
    llvm::Module *Mod = llvm::ParseIRFile("test.ll", Err, Context); 

    std::unique_ptr<llvm::RTDyldMemoryManager> MemMgr(new llvm::SectionMemoryManager()); 

    // Build engine with JIT 
    std::string err; 
    llvm::EngineBuilder factory(Mod); 
    factory.setErrorStr(&err); 
    factory.setEngineKind(llvm::EngineKind::JIT); 
    factory.setUseMCJIT(true); 
    factory.setMCJITMemoryManager(MemMgr.release()); 
    llvm::ExecutionEngine *m_EE = factory.create(); 

    llvm::sys::DynamicLibrary::AddSymbol("_Z4testv", reinterpret_cast<void*>(test)); 

    llvm::Function* f = Mod->getFunction("exec"); 

    m_EE->finalizeObject(); 

    void* poi = m_EE->getPointerToFunction(f); 
    void (*exec)(void*) = reinterpret_cast<void (*)(void*)>(poi); 

    try { 
     exec(NULL); 
    } catch (int e) { 
     std::cout << "catched " << e << std::endl; 
    } 
    return 0; 
} 

また、あなたは今も追加することにより、JITコードのデバッグシンボルを取得することができます

関連する問題