gpt4 book ai didi

c++ - LLVM 即时编译 : pass C++ exception through JIT code back to host application

转载 作者:可可西里 更新时间:2023-11-01 16:11:18 26 4
gpt4 key购买 nike

我正在开发一个项目,我使用 clang 生成一些 LLVM IR,然后在我的主机应用程序中进行 JIT 编译和运行。 JIT 代码调用宿主应用程序中的某些函数可能会引发异常。我希望通过 JIT 代码抛出异常并在主机应用程序中捕获。据我所知,这应该与 LLVM 一起使用,但不幸的是,我的测试应用程序总是因“在抛出‘int’实例后调用终止”而崩溃。让我举个简单的例子。

我使用 clang 3.5 将以下简单程序编译成 LLVM IR:

extern void test() ;

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

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

结果为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 时是否遗漏了什么,或者我的主机应用程序代码是否有误?

谢谢!

最佳答案

它终于起作用了,这里有一些解决问题所必需的东西。

首先确保包含 MCJIT.h 很重要,否则 MCJIT 不会被链接。不幸的是,如果 MCJIT.h 没有被包含,即使 MCJIT 已被明确请求,LLVM 也会默默地退回到旧的 JIT 实现:

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

只有 MCJIT 支持适当的异常处理。

在我用的题中的例子中

Execution::Engine::addGlobalMapping()

不适用于 MCJIT。必须通过

重新注册外部函数
llvm::sys::DynamicLibrary::AddSymbol()

下面是完整的例子:

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 代码的调试符号,方法是添加:

Opts.JITEmitDebugInfo = true;

关于c++ - LLVM 即时编译 : pass C++ exception through JIT code back to host application,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27731637/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com