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.