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

如何在构建LLVM 13 OrcV2 JIT编译器时解析当前会话中的符号

基于LLVM 13 ORC JIT暴露本地函数的可缓存实现方案

你之前使用absoluteSymbols无法支持缓存的核心原因是:该方式直接绑定了当前进程会话的函数绝对地址,缓存的编译产物会记录这个固定地址,程序重启或地址空间随机化(ASLR)生效后地址就会失效。以下是三种适用不同场景的常规处理方案:

方案1:自定义白名单符号生成器(最推荐,无额外依赖)

ORC的DefinitionGenerator接口是官方推荐的可缓存符号解析方案,你可以自定义生成器仅返回需要暴露的函数符号,完全不需要依赖外部动态库:

// 定义要暴露的符号白名单,key是JIT里要调用的符号名,value是对应函数指针
const std::unordered_map<std::string, void*> exposed_symbols = {
    {"add2", (void*)&mylibsubnamespace::add2},
    // 其他要暴露的函数直接在这里添加即可
};

// 自定义符号生成器
class CustomSymbolGenerator : public DefinitionGenerator {
public:
    Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
                        JITDylibLookupFlags JDLookupFlags,
                        const SymbolLookupSet &LookupSet) override {
        SymbolMap new_symbols;
        auto &SP = JD.getExecutionSession().getSymbolStringPool();
        
        for (auto &sym : LookupSet) {
            std::string sym_name = (*sym.first).str();
            if (exposed_symbols.count(sym_name)) {
                JITEvaluatedSymbol eval_sym(
                    pointerToJITTargetAddress(exposed_symbols.at(sym_name)),
                    JITSymbolFlags::Exported | JITSymbolFlags::Callable
                );
                new_symbols[sym.first] = eval_sym;
            }
        }
        
        if (!new_symbols.empty()) {
            return JD.define(absoluteSymbols(std::move(new_symbols)));
        }
        return Error::success();
    }
};

在JIT初始化逻辑中添加该生成器即可:

(*J)->getMainJITDylib().addGenerator(std::make_unique<CustomSymbolGenerator>());

该方案的优势:

  • 完全符合ORC标准符号查询流程,原生支持编译缓存,缓存中仅存储符号名而不是固定地址
  • 可以精确控制暴露给JIT的函数范围,不会泄露进程其他无关符号
  • 不需要额外编译独立动态库,接入成本低

方案2:过滤当前进程符号(实现最简单)

你现在使用的DynamicLibrarySearchGenerator::GetForCurrentProcess支持传入符号过滤回调,你可以仅放行白名单内的符号,不需要自定义完整的生成器:

auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
    (*J)->getDataLayout().getGlobalPrefix(),
    [](const llvm::orc::SymbolStringPtr &Name) {
        // 只允许白名单内的符号被JIT解析
        static const std::unordered_set<std::string> allowed_symbols = {"add2", "cos"};
        return allowed_symbols.count(Name->str());
    }
);

注意要暴露的函数需要加extern "C"避免C++名字修饰,和你当前的add2实现逻辑一致即可。

方案3:内置独立动态库(适合跨进程复用缓存场景)

如果你的JIT编译产物需要跨进程共享缓存,可以把所有要暴露的函数单独编译成一个独立动态库,嵌入到你的程序安装包中,直接用官方推荐的DynamicLibrarySearchGenerator::Load加载即可,路径指向程序自带的动态库路径即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:06:06