LLVM IR和C/C++函数相互调用时的注意事项

以下叙述,主要针对LLVM 3.6。

一、从C/C++调用LLVM IR函数
主要有两种办法。
1、通过llvm::ExecutionEngine::runFunction()调用。
    存在的问题:可以直接调用llvm::Function,但目前LLVM项目没有实现参数传递,只提供了接口,因此我们只能调用无参函数
2、通过llvm::ExecutionEngine::getPointerToFunction()即时编译为本机代码,并获得一个指向C函数的void *指针。然后,可以将其转换为合适的C/C++函数指针,进行调用。
    存在的问题:LLVM指令被编译为ELF格式,而不是COFF格式,导致在Windows平台加载时错误" Incompatible object format "。
    为解决这一问题,需要在系统三元组(Triple)后加“-elf”。参见: http://comments.gmane.org/gmane.comp.compilers.llvm.devel/82330
二、从LLVM IR调用 C/C++函数
    主要有三种办法。
   1、将被调用函数声明为动态链接导出函数,LLVM自动在执行时解析并调用。  
    这是官方“标准”的做法。
    存在的问题:windows平台可执行文件中的函数一般不会被导出,不能通过这一机制解析。
    解决办法是,通过llvm::sys::DynamicLibrary::AddSymbol()显示注册函数。LLVM在查找外部函数时,首先查找通过AddSymbol注册的函数,然后才通过系统调用查找可执行文件或动态链接库中的符号。
    2、通过llvm::ExecutionEngine::addGlobalMapping()将被调用的C/C++函数指针注册为LLVM中的全局变量。
    这样做的好处是,被调用函数不需要声明为动态链接库的导出函数,只要知道函数指针就可以。
    存在的问题:MCJIT对addGlobalMapping的支持不完善,实际运行时会报错。参见: http://llvm.1065342.n5.nabble.com/Weird-problems-on-calling-an-external-function-from-MCJIT-on-Windows-mingw-td67478.html
    解决办法同1,通过AddSymbol()来实现。
    3、通过自定义的内存分配器来直接解析函数。
    原理同addGlobalMapping类似,这一方法我没有验证,有空可以试验一下。
以下是一个简单的C++代码示例,使用LLVM框架中的API生成系统调用IR: ```c++ #include <llvm/IR/LLVMContext.h> #include <llvm/IR/Module.h> #include <llvm/IR/IRBuilder.h> using namespace llvm; int main() { LLVMContext context; Module module("syscall_module", context); IRBuilder<> builder(context); // Define the function signature Type *syscall_args[] = {builder.getInt64Ty(), builder.getInt64PtrTy()}; FunctionType *syscall_type = FunctionType::get(builder.getInt64Ty(), syscall_args, false); // Declare the function in the module Function *syscall_func = Function::Create(syscall_type, Function::ExternalLinkage, "syscall", &module); // Create a basic block to contain the instructions BasicBlock *entry = BasicBlock::Create(context, "entry", syscall_func); // Add instructions to the basic block Value *syscall_num = builder.getInt64(1); Value *syscall_args_ptr = builder.getInt64PtrTy()->getPointerTo(builder.getInt64(0)); Value *syscall_result = builder.CreateCall(syscall_func, {syscall_num, syscall_args_ptr}); // Add return instruction to the basic block builder.CreateRet(syscall_result); // Print the IR code to stdout module.print(outs(), nullptr); return 0; } ``` 该代码创建了一个名为`syscall_module`的LLVM模块,并在其中声明了一个名为`syscall`的外部函数。接下来,它创建了一个名为`entry`的基本块,并在其中添加了一个调用`syscall`函数的指令,该指令传递了系统调用号和参数指针。最后,它添加了一个`ret`指令,将系统调用结果作为函数返回值。 输出的IR代码类似于以下内容: ``` ; ModuleID = 'syscall_module' source_filename = "syscall_module" define i64 @syscall(i64, i64*) { entry: %0 = call i64 @syscall(i64 1, i64* null) ret i64 %0 } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值