You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在LLVM JIT编译函数中调用预编译C函数?求纯C实现方案

可行

在纯C环境下,完全可以实现从LLVM JIT编译的函数中调用预编译的C函数,核心是通过LLVM C API提供的LLVMAddGlobalMapping函数完成符号映射,对应C++版本的llvm::ExecutionEngine::addGlobalMapping功能。

实现步骤

  • 定义非静态的预编译C函数(确保符号可被链接器和LLVM识别)
  • 使用LLVM C API构建包含目标调用逻辑的IR模块,需提前在模块中声明预编译函数的签名
  • 创建ExecutionEngine实例后,通过LLVMAddGlobalMapping将IR中的函数符号与预编译C函数的实际地址绑定
  • 编译并调用JIT生成的函数

示例代码

预编译C函数(utils.c)

int add(int a, int b) {
    return a + b;
}

主程序(jit_demo.c)

#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <stdio.h>

int main() {
    // 初始化LLVM本地目标环境
    LLVMInitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    LLVMInitializeNativeAsmParser();

    // 创建LLVM上下文与模块
    LLVMContextRef ctx = LLVMContextCreate();
    LLVMModuleRef mod = LLVMModuleCreateWithNameInContext("jit_demo", ctx);

    // 定义函数类型:int(int, int)
    LLVMTypeRef param_types[] = {LLVMInt32Type(), LLVMInt32Type()};
    LLVMTypeRef func_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);

    // 在模块中声明预编译的add函数
    LLVMValueRef add_func = LLVMAddFunction(mod, "add", func_type);
    // 构建JIT函数:调用add并返回结果
    LLVMValueRef jit_func = LLVMAddFunction(mod, "call_add", func_type);
    LLVMBasicBlockRef entry = LLVMAppendBasicBlock(jit_func, "entry");
    LLVMBuilderRef builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, entry);

    // 获取JIT函数的参数,调用add
    LLVMValueRef args[] = {LLVMGetParam(jit_func, 0), LLVMGetParam(jit_func, 1)};
    LLVMValueRef ret_val = LLVMBuildCall(builder, add_func, args, 2, "call_res");
    LLVMBuildRet(builder, ret_val);

    // 创建ExecutionEngine
    char *err_msg = NULL;
    LLVMExecutionEngineRef engine;
    if (LLVMCreateExecutionEngineForModule(&engine, mod, &err_msg) != 0) {
        fprintf(stderr, "ExecutionEngine创建失败: %s\n", err_msg);
        LLVMDisposeMessage(err_msg);
        return 1;
    }

    // 绑定符号:将IR中的add映射到实际函数地址
    LLVMAddGlobalMapping(engine, add_func, (void*)&add);

    // 获取JIT函数指针并调用
    int (*call_jit)(int, int) = (int(*)(int, int))LLVMGetFunctionAddress(engine, "call_add");
    printf("3 + 5 = %d\n", call_jit(3, 5));

    // 清理资源
    LLVMDisposeBuilder(builder);
    LLVMDisposeExecutionEngine(engine);
    LLVMContextDispose(ctx);

    return 0;
}

编译命令(使用clang)

clang -o jit_demo jit_demo.c utils.c `llvm-config --cflags --ldflags --system-libs --libs core executionengine native`

关键注意事项

  • 预编译函数不能用static修饰,否则符号会被隐藏,无法完成映射
  • 必须正确初始化LLVM的目标组件,否则ExecutionEngine会创建失败
  • 确保LLVM库版本与编译环境匹配,避免因ABI不兼容导致段错误

内容的提问来源于stack exchange,提问作者SocraticMathTutor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 19:52:27