Step 06 · Runtime symbols (printf and friends)

When our JITed module says call i32 @printf(...), ORC needs an address for the external symbol. LLJIT adds a DynamicLibrarySearchGenerator::GetForCurrentProcess(...) to its main JITDylib by default, which dlsyms into the host process.

Since the test binary is linked against libc, printf resolves immediately and the JITed call writes to our captured stdout.

Injecting your own runtime functions

// inside jit.cpp, after LLJIT::create()
auto& dylib = jit->getMainJITDylib();
dylib.define(orc::absoluteSymbols({
    { jit->mangleAndIntern("ml_print"),
      { reinterpret_cast<uintptr_t>(&ml_print),
        JITSymbolFlags::Exported } }
}));

cp-14 will introduce a real ml_print(Value) helper and a tiny runtime library. Then the front end can stop hard-coding printf and emit call void @ml_print(%Value) instead — opening the door to boxed types, GC headers, etc.

Mangling

On macOS, symbols carry a leading underscore (_printf). LLJIT does the right mangling internally; mangleAndIntern exposes the same logic when you register a host pointer.