ORC JIT中符号隔离依赖JITDylib,默认不全局可见;每个JITDylib独立维护符号表,跨dylib调用需显式添加依赖,lookup必须指定目标dylib,内存由SectionMemoryManager自动管理。

ORC JIT 中符号隔离靠 JITDylib,不是自动全局可见
默认情况下,orc::ExecutionSession 创建的每个 JITDylib 都是符号隔离的——你在 main dylib 里 addIRModule 注入的函数,其他 dylib 根本看不到。这不是 bug,是设计:避免符号污染和重复定义冲突。
常见错误现象:调用 ES.lookup("add") 返回 nullptr 或地址为 0,但 IR 没报错、dump() 显示函数存在。原因往往是 lookup 目标 dylib 错了,或没显式声明依赖。
- 查符号必须指定目标 dylib:
mainJD.lookup(Mangle("add")),不能只写ES.lookup("add") - 跨 dylib 调用需手动添加依赖:
otherJD.addDependentJITDylib(mainJD) - 若模块含外部 C 函数(如
printf),必须先用absoluteSymbols注册地址,再通过DynamicLibrarySearchGenerator暴露给 dylib
内存释放不靠手动 free,而靠 JITDylib 生命周期或 removeModule
ORC 不让你直接 mmap/mprotect 管理页,而是通过 SectionMemoryManager 统一分配可执行内存。释放时机由 JITDylib 控制:销毁 dylib 或调用 removeModule 时,它会自动回收对应内存页并取消 mprotect(PROT_EXEC)。
容易踩的坑:在 dylib 还活着时,把函数指针保存到全局变量并长期持有,然后误删 dylib —— 下次调用就 SIGSEGV。因为地址虽还在,但底层内存已被 unmap。
立即学习“C++免费学习笔记(深入)”;
- 安全做法:函数指针只在 dylib 存活期内使用;需长期持有时,改用
std::shared_ptr包裹 JITDylib 引用 -
removeModule是异步的,返回orc::MaterializationUnit::Handle,可 await 完成后再释放相关资源 - 不要对 JIT 生成的函数地址调用
free()或munmap()—— ORC 会自己处理,强行干预会导致 double-free 或段错误
符号名冲突与重复注入必须主动防御
同一 JITDylib 内两次 addIRModule 含同名全局函数(如都叫 add),默认触发“重复定义”错误,addIRModule 抛异常或返回失败状态。这不是链接器报错,是 ORC 在符号注册阶段就拦截了。
原因在于 ORC 默认关闭自动接管符号所有权(setAutoClaimResponsibilityForObjectSymbols(false)),所以遇到重名就拒绝。
- 允许覆盖:创建 dylib 时调用
mainJD.setAutoClaimResponsibilityForObjectSymbols(true) - 更推荐做法:每次生成新模块时用唯一前缀命名函数,比如
"add_v2_1742",避免隐式覆盖逻辑 - 调试时加
module->dump()和ES.dump(),确认符号是否已注册、是否被正确 mangled
RTTI/EH 必须开启,否则 SymbolResolver 构造失败静默崩溃
LLVM 14+ 的 ORCv2(尤其是 orc::KaleidoscopeJIT 及其派生类)严重依赖 RTTI 做类型擦除和动态 dispatch。若 CMake 中未设 LLVM_ENABLE_RTTI=ON,orc::SymbolResolver 构造可能成功,但后续 lookup 时在虚函数调用点 SIGSEGV,且无明确错误信息。
同样,未启用异常处理(LLVM_ENABLE_EH=ON)会导致 ExecutionSession 内部异常传播中断,错误被吞掉,表现为 JIT 无响应或随机挂起。
- 检查方法:编译时加
-DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON,链接时确保llvm-orc和llvm-executionengine在依赖链中 - 运行时验证:在
addIRModule后立即ES.lookup一个已知函数,捕获std::exception并打印.what() - 不要依赖
llvm-config --cxxflags的默认输出 —— 它不包含 RTTI/EH 开关,必须显式传给 CMake
最易忽略的一点:符号解析失败和内存释放不匹配往往同时发生,但错误表现却像纯内存问题。实际 debug 时,应先确认 JITDylib 的生命周期管理是否与函数指针使用范围对齐,再查符号注册路径,最后碰内存权限——顺序反了,90% 的时间会浪费在 mprotect 调试上。


















