Repository navigation
Give the COFF JIT somewhere to find libc - #322
Merged
Merged
Conversation
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.
This was referenced Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #31.
mojo runon Windows compiles a program and then cannot resolve a short list of symbols, all of which exist on the machine:Two separate things were missing.
The link order
$platform-stdlibis 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.
dlsymon the compiler runtime's handle keeps walking into that library's own dependencies, and libc is one of them, somemcpyresolves through$compilerrt-libwithout anybody thinking about it.GetProcAddressreads 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.dllis not loaded at all and nothing in the process exports_setmodeor_write.Naming
ucrtbase.dll,kernel32.dllandntdll.dlloutright covers all nine symbols: the CRT entry points from ucrtbase, the console and handle calls from kernel32, and__chkstkfrom either of the other two. It also takesmemcpyaway from whatever orderEnumProcessModuleshappens 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:
That is the
.pdataunwind tables wanting image relative addresses with no image to be relative to, and it is filed separately.mojo build --emit=llvmandmojo.exe --versionare 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.