Skip to content

Give the COFF JIT somewhere to find libc - #322

Merged
tamnd merged 1 commit into
mainfrom
coff-jit-crt
Sep 9, 2026
Merged

tamnd merged 1 commit into
mainfrom
coff-jit-crt

Conversation

@tamnd

@tamnd tamnd commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Part of #31.

mojo run on Windows compiles a program and then cannot resolve a short list of symbols, all of which exist on the machine:

JIT session error: Symbols not found: [ __chkstk, SetConsoleOutputCP, GetConsoleMode, _write, _setmode, GetStdHandle, SetConsoleCP, memcpy, SetConsoleMode ]

Two separate things were missing.

The link order

$platform-stdlib is the dylib that holds the process wide search generator. It was in the search order that a lookup starts from, but it was in nobody's link order, and the link order is what a symbol gets resolved through once materialization is under way. So the generator was there and nothing could reach it.

That gap never showed on ELF or Mach-O. dlsym on the compiler runtime's handle keeps walking into that library's own dependencies, and libc is one of them, so memcpy resolves through $compilerrt-lib without anybody thinking about it. GetProcAddress reads one module's export table and stops. On Windows the platform stdlib is the only thing that can answer for a CRT symbol, so it has to be in the link order.

Added last, so anything the Mojo runtime defines still wins over a system copy of the same name.

The libraries

The process wide generator searches modules the process has already loaded, and that is not enough here either. A Windows build of mojo links the C runtime statically, so ucrtbase.dll is not loaded at all and nothing in the process exports _setmode or _write.

Naming ucrtbase.dll, kernel32.dll and ntdll.dll outright covers all nine symbols: the CRT entry points from ucrtbase, the console and handle calls from kernel32, and __chkstk from either of the other two. It also takes memcpy away from whatever order EnumProcessModules happens to return, since ntdll and ucrtbase both have one. The two that are already loaded cost a reference count and nothing else.

Where it gets to

Every one of the nine now resolves. The next failure is a different problem in a different place:

JIT session error: In graph , section .pdata: relocation target 0x22cc7961000 (.text) is out of range of Pointer32 fixup

That is the .pdata unwind tables wanting image relative addresses with no image to be relative to, and it is filed separately. mojo build --emit=llvm and mojo.exe --version are unaffected and still work.

Both changes are COFF only. The other two platforms already work and there is no reason to move their resolution around.

@tamnd tamnd added this to the M6 Tier 2 and native hosting milestone Sep 9, 2026
@tamnd tamnd added area/runtime AsyncRT, allocator, crash handling type/bug Something is broken priority/p1 Important. Needed for the milestone labels Sep 9, 2026
mojo run on Windows compiles a program, links it, and then cannot resolve __chkstk, memcpy, _setmode, _write and five kernel32 calls. All nine exist on the machine. Nothing was telling the JIT where to look.

Two things were missing. The platform stdlib, which is the dylib holding the process wide search generator, was in the search order a lookup starts from but in nobody's link order, and the link order is what resolution walks once materialization is under way. That gap never showed on ELF or Mach-O because dlsym on the compiler runtime handle keeps walking into that library's own dependencies, and libc is one of them. GetProcAddress reads one module's export table and stops, so on Windows the platform stdlib is the only thing that can answer and it has to be reachable.

The second is that the process wide generator is not enough on its own here. A Windows build of mojo links the C runtime statically, so ucrtbase.dll is not loaded and nothing in the process exports _setmode or _write. Naming ucrtbase, kernel32 and ntdll outright covers all nine, and it also takes memcpy away from whatever order EnumProcessModules happens to return, since ntdll and ucrtbase both have one.

Both changes are COFF only. The other two platforms already work and there is no reason to move their resolution around.
@tamnd
tamnd merged commit 0d20dff into main Sep 9, 2026
7 checks passed
@tamnd
tamnd deleted the coff-jit-crt branch September 9, 2026 06:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/runtime AsyncRT, allocator, crash handling priority/p1 Important. Needed for the milestone type/bug Something is broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant