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

LLVM ORC JIT中ReexportsGenerator无法解析符号问题排查

LLVM ORC跨JIT实例符号解析问题排查

问题场景

存在两个LLJIT实例(JIT1、JIT2),尝试让JIT2引用JIT1中的函数时,出现JIT session error: Symbols not found错误。已尝试用ReexportsGenerator将JIT1的主JITDylib导出到JIT2,但未生效。

进一步排查发现:

  • 直接调用JIT1->lookup("my_symbol_name")能正确获取符号地址,确认JIT1中存在目标符号;
  • 调用lookupFlags尝试匹配符号时,返回的匹配结果数量为0。

相关代码片段:

定义JITDylib

llvm::orc::JITDylib &JD = JIT2->getMainJITDylib();
llvm::orc::JITDylib &SourceJD = JIT1->getMainJITDylib();

尝试ReexportsGenerator

auto gen = std::make_unique<ReexportsGenerator>(JIT1->getMainJITDylib(),
                                                llvm::orc::JITDylibLookupFlags::MatchAllSymbols);
JIT2->getMainJITDylib().addGenerator(std::move(gen));

验证lookup成功

llvm::StringRef symName("my_symbol_name");
// 直接lookup能拿到正确地址
auto addr = JIT1->lookup(symName);
if (auto E = addr.takeError()) {
    throw E;
}
uint64_t fun_addr = addr->getValue(); // 地址正确,确认JIT1持有符号

lookupFlags匹配失败

// 自行创建SymbolStringPool并intern符号名
llvm::orc::SymbolStringPool pool;
llvm::orc::SymbolStringPtr symNamePtr = pool.intern(symName);

llvm::orc::SymbolLookupSet LookupSet;
LookupSet.add(symNamePtr, llvm::orc::SymbolLookupFlags::WeaklyReferencedSymbol);

auto Flags = JD.getExecutionSession().lookupFlags(
            llvm::orc::LookupKind::DLSym,
            {{&SourceJD, llvm::orc::JITDylibLookupFlags::MatchAllSymbols}},
            LookupSet);
if (auto E = Flags.takeError()) {
    throw E;
}
std::cout << "Flags.size() " << (*Flags).size() << std::endl; // 输出0,匹配失败

核心问题分析

1. SymbolStringPool不共享导致匹配失败

LLVM ORC的SymbolStringPtr依赖同一个SymbolStringPool保证符号唯一性——不同pool中intern相同字符串得到的SymbolStringPtr是不同实例,lookupFlags会严格比对SymbolStringPtr指针而非字符串内容。

你在测试中自行创建了新的SymbolStringPool,但JIT1和JIT2各自持有独立pool,导致你intern出的symNamePtr和JIT1中存储的符号指针不匹配,因此lookupFlags无法找到目标符号。而JIT->lookup(StringRef)会自动将字符串intern到JIT自身的pool,所以能正确匹配。

2. ReexportsGenerator未生效的可能原因

  • 符号名不匹配:LLVM默认会对C++函数进行名称修饰(mangling),你使用的my_symbol_name可能是未修饰的原名,而JIT1中实际存储的是修饰后的符号(比如__Z12my_symbol_namev)。
  • JITDylib搜索顺序问题:JIT2的主JITDylib可能优先搜索自身的符号生成器,ReexportsGenerator优先级不足导致未被触发。
  • ExecutionSession隔离:两个LLJIT实例默认使用独立的ExecutionSession,跨会话的符号导出需要额外配置。

解决建议

1. 修复lookupFlags的测试代码

使用JIT1的SymbolStringPool来intern符号名,确保指针一致:

// 改用JIT1的SymbolStringPool
llvm::orc::SymbolStringPtr symNamePtr = JIT1->getExecutionSession().getSymbolStringPool().intern(symName);

llvm::orc::SymbolLookupSet LookupSet;
LookupSet.add(symNamePtr, llvm::orc::SymbolLookupFlags::WeaklyReferencedSymbol);

// 或者直接调用JIT1的lookupFlags方法,避免手动指定JITDylib
auto Flags = JIT1->lookupFlags(LookupSet);

2. 确保ReexportsGenerator正确工作

  • 验证符号的真实名称:使用llvm::demangle工具查看JIT1中符号的实际名称,确保你使用的符号名和JIT中存储的一致:
    #include "llvm/Demangle/Demangle.h"
    // ...
    std::string demangled = llvm::demangle("__Z12my_symbol_namev"); // 传入修饰后的符号名
    
  • 共享ExecutionSession:如果两个JIT实例需要跨会话导出符号,创建LLJIT时指定同一个ExecutionSession:
    auto ES = std::make_unique<llvm::orc::ExecutionSession>();
    auto JIT1 = llvm::orc::LLJITBuilder().setExecutionSession(std::move(ES)).create();
    auto JIT2 = llvm::orc::LLJITBuilder().setExecutionSession(JIT1->getExecutionSession()).create();
    
  • 调整符号生成器优先级:添加ReexportsGenerator时设置更高的优先级:
    JD.addGenerator(std::move(gen), llvm::orc::GeneratorPosition::Front);
    

3. 替代方案:手动添加符号映射

如果ReexportsGenerator仍不生效,可以直接将JIT1中的符号地址添加到JIT2的JITDylib中:

auto symAddr = JIT1->lookup("my_symbol_name").get();
JD.define(llvm::orc::absoluteSymbols({{JIT2->getExecutionSession().getSymbolStringPool().intern("my_symbol_name"), symAddr}}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:01:12