Skip to content

Drop the unwind tables the COFF JIT cannot relocate - #324

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

tamnd merged 1 commit into
mainfrom
coff-jit-unwind

Conversation

@tamnd

@tamnd tamnd commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Fixes #323.

With #322 merged, mojo run on Windows resolves every symbol it needs and then fails in the linker instead:

JIT session error: In graph , section .pdata: relocation target 0x22cc7961000 (.text) is out of range of Pointer32 fixup at address 0x22cc7961000 (<anonymous block> @ 0x22cc79602b4 + 0x0)
error: Failed to materialize symbols: { (exec, { main }) }

Every x86_64 Windows function carries a .pdata entry describing how to unwind out of it, and each entry is three offsets from the image base. A linker writes one by subtracting the address of __ImageBase from the address of the thing being described, which is what IMAGE_REL_AMD64_ADDR32NB asks for and what JITLink models as a Pointer32NB edge. JIT'd code is not in an image, so COFFLinkGraphBuilder adds __ImageBase as an undefined external, no COFF platform is ever created to define it, and its address stays zero. The lowering pass still runs the subtraction, gets the untouched 64 bit address back, and hands it to a 32 bit fixup. The first function with unwind info trips it, which is all of them.

So this adds an object linking layer plugin that removes .pdata and .xdata from COFF link graphs. It goes in at the front of the pre prune passes, ahead of JITLink's own SEHFrameKeepAlivePass, because that pass gives every .pdata block a keep alive edge to the code it describes and those edges would otherwise be pointing at blocks that are no longer there. .xdata goes too: it is only ever reached through .pdata and it carries the same kind of image relative pointer.

The tables were not being used. Handing unwind info to Windows is the ORC COFF platform's job, we do not create a platform, and the execution engine destructor's platform shutdown branch is unreachable for the same reason, so the entries were being relocated for nobody. What this gives up is walking out of a JIT'd frame in a Windows debugger, which does not work today either. If the COFF platform is ever set up properly the plugin should come back out.

Everything is behind a COFF check, so the ELF and Mach-O paths are untouched.

Part of #31.

@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
@tamnd tamnd mentioned this pull request Sep 9, 2026
41 of 43 tasks
@tamnd

tamnd commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

Cross built and checked on a Windows host.

=== version
Mojo 1.1.0.dev0 (deadbeef)
VER_RC=0
=== run
hello from windows
RUN_RC=0

That is mojo run on Windows working end to end for the first time. The .pdata relocation failure is gone and the program runs.

A larger program that exercises List, Dict, string building, range and try gets further and then stops on a different thing, JIT session error: Symbols not found: [ snprintf ]. That is not this change, it is the next one along: snprintf and the rest of the stdio family are inline functions in the UCRT headers and ucrtbase.dll does not export them, so there is nothing on the machine for the JIT to find. Filed separately.

Every x86_64 Windows function carries a .pdata entry saying how to unwind out of it, and each entry is three offsets from the image base. A linker writes one by subtracting the address of __ImageBase from the address of what the entry describes. JIT'd code is not in an image, so JITLink adds __ImageBase as an undefined external, no COFF platform ever defines it, and its address stays zero. The subtraction is then a no op, the 64 bit address is left where a 32 bit offset should be, and the link fails on the first function that has unwind info, which is all of them.

So mojo run on Windows died with "relocation target 0x... (.text) is out of range of Pointer32 fixup" right after it finished resolving symbols.

This adds an object linking layer plugin that removes .pdata and .xdata from COFF link graphs. It goes in at the front of the pre prune passes so that it runs before JITLink's SEHFrameKeepAlivePass, which ties each .pdata block to the code it describes with a keep alive edge and would otherwise leave those edges pointing at blocks that are gone.

The tables were not doing anything. Handing unwind info to Windows is the ORC COFF platform's job and no platform is created here, so they were being relocated for nobody. What is given up is walking out of a JIT'd frame in a Windows debugger, which does not work today either, for the same reason.
@tamnd
tamnd merged commit 3ef3045 into main Sep 9, 2026
7 checks passed
@tamnd
tamnd deleted the coff-jit-unwind branch September 9, 2026 07:05
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.

COFF JIT cannot fix up .pdata because __ImageBase is never defined

1 participant