I recently updated a project which had been using LLVM 6 to LLVM 8, and ran into an issue where symbols which exist in libraries loaded with LLVMLoadLibraryPermanently — which were correctly resolved by the MCJIT in LLVM 6 — are resolved as the constant $0x0 (null) in LLVM 8, causing a crash in what had been working code.
The image below shows what’s seen in the debugger. Note the call of %rax on the last line, which had $0x0 stored into it two lines previously.
Here is the LLVM IR which produced the assembly above:
The project uses the LLVM C API (via the Rust llvm-sys crate) and had no other changes between the working and the new non-working state.
Symbols within the module the execution engine was constructed with are resolved correctly; only symbols within loaded dynamic libraries fail to resolve.
Using LLVMSearchForAddressOfSymbol does correctly resolve the symbols from the dynamic library — it’s only when JITed that resolution fails.
My questions are:
- Is there a way to get LLVM JIT to crash when a symbol fails to resolve, rather than fill in a constant null? That it didn’t crash in the first place was surprising to me — it took a whole day to track down that this resolution failure was even the problem.
- Were there any changes to the way LLVM’s JIT resolves symbols between LLVM 6 and LLVM 8?
- I checked the documentation for the LLVMCreateJITCompiledForModule and LLVMLoadLibraryPermanently but found nothing to suggest the behavior would have changed (no deprecation warning, no new documentation).
I’d appreciate any help or suggestions. I’m unsure how to proceed debugging or fixing this.