feat(C2): unit-first JIT symbol resolution — program-owned dylibs beat process images
runJITFromObject now takes priority dylibs (the #import c unit's linked objects first, then #library deps in declaration order) and attaches a per-path search generator for each AHEAD of the process-wide fallback, so a vendored symbol can never lose to a same-named export of an image the host process happens to carry (libz via LLVM, libsqlite3 via CoreServices). loadLibrary reports the name dlopen succeeded on; the c-import handle records its dylib path; temp link inputs are per-pid so concurrent runs can't clobber each other. Flips the C0.3 shadowing pin to from_unit: true.
This commit is contained in:
@@ -198,7 +198,12 @@ pub const TargetConfig = struct {
|
||||
|
||||
/// Execute a precompiled object file in-process using LLVM's ORC JIT.
|
||||
/// Takes ownership of obj_buf. Returns the exit code from main().
|
||||
pub fn runJITFromObject(obj_buf: c.LLVMMemoryBufferRef) !u8 {
|
||||
/// `priority_dylibs` are consulted for symbols BEFORE the process-wide
|
||||
/// search, in order: dylibs that belong to the program (the `#import c`
|
||||
/// unit's linked objects, then `#library` deps in declaration order)
|
||||
/// must win over a same-named export of an image the host process
|
||||
/// happens to carry (libz via LLVM, libsqlite3 via CoreServices, ...).
|
||||
pub fn runJITFromObject(obj_buf: c.LLVMMemoryBufferRef, priority_dylibs: []const [:0]const u8) !u8 {
|
||||
// Create LLJIT with default builder (no custom TM needed — .o is precompiled)
|
||||
var jit: c.LLVMOrcLLJITRef = null;
|
||||
var err = c.LLVMOrcCreateLLJIT(&jit, null);
|
||||
@@ -210,9 +215,25 @@ pub fn runJITFromObject(obj_buf: c.LLVMMemoryBufferRef) !u8 {
|
||||
}
|
||||
defer _ = c.LLVMOrcDisposeLLJIT(jit);
|
||||
|
||||
// Add process symbols so JIT can find libc (printf, etc.)
|
||||
const jd = c.LLVMOrcLLJITGetMainJITDylib(jit);
|
||||
const prefix = c.LLVMOrcLLJITGetGlobalPrefix(jit);
|
||||
|
||||
// Program-owned dylibs first (generators run in attachment order).
|
||||
// A failed generator is skipped: resolution then degrades to the
|
||||
// process-wide search below, exactly the pre-priority behavior.
|
||||
for (priority_dylibs) |path| {
|
||||
var pgen: c.LLVMOrcDefinitionGeneratorRef = null;
|
||||
err = c.LLVMOrcCreateDynamicLibrarySearchGeneratorForPath(&pgen, path.ptr, prefix, null, null);
|
||||
if (err != null) {
|
||||
const msg = c.LLVMGetErrorMessage(err);
|
||||
defer c.LLVMDisposeErrorMessage(msg);
|
||||
std.debug.print("warning: JIT could not search '{s}': {s}\n", .{ path, std.mem.span(msg) });
|
||||
continue;
|
||||
}
|
||||
c.LLVMOrcJITDylibAddGenerator(jd, pgen);
|
||||
}
|
||||
|
||||
// Process-wide fallback so the JIT finds libc (printf, etc.)
|
||||
var gen: c.LLVMOrcDefinitionGeneratorRef = null;
|
||||
err = c.LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(&gen, prefix, null, null);
|
||||
if (err != null) {
|
||||
|
||||
Reference in New Issue
Block a user