You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Supporting Windows SEH without the ORC runtime #163503
I do not know whether the SEH runtime looks at any metadata at the base address, or whether it's used purely for address calculations, but I suspect the latter (or the various out-of-tree SEH experiments that people have gotten working would have blown up differently).
Assuming that BaseAddress is only used for address calculation then we can probably just find the lowest address in the graph and use that for each graph.
If BaseAddress needs to contain useful metadata (e.g. a COFF header) then we can do something similar to what we do for compact-unwind (see
I do not know whether the SEH runtime looks at any metadata at the base address, or whether it's used purely for address calculations, but I suspect the latter (or the various out-of-tree SEH experiments that people have gotten working would have blown up differently).
Assuming that BaseAddress is only used for address calculation then we can probably just find the lowest address in the graph and use that for each grab.
If BaseAddress needs to contain useful metadata (e.g. a COFF header) then we can do something similar to what we do for compact-unwind (see
I've posted a sketch of what simple in-process SEH registration might look like in lhames@fe70221.
You can ignore the code in the #else branch with the // for testing purposes only comment: that was just so that I could build this at all on Darwin. On Windows I'd expect those types to come from winnt.h.
The plugin logic is simple: registerFrameInfo is registered as a post-fixup pass in modifyPassConfig, which means that registerFrameInfo will run at the end of the linker pipeline after all addresses have been assigned and content written to the linker's working memory. The registerFrameInfo pass looks for a .pdata section and, if one exists, then it (a) finds the effective base address of the image (from __ImageBase if defined, otherwise taking the lowest address in the object file), then (b) adds allocation actions to call RtlAddFunctionTable (when the JIT'd memory is finalised) and RtlDeleteFunctionTable (when the JIT'd memory is deallocated).
The allocation actions are implemented as static methods (registerPData and deregisterPData) in the plugin class itself, so this will only work in-process.
Hi @lhames, thanks for the sketch and guidance, I’m taking a look . The code compiles fine (the correct header is <windows.h>) and I’m making good initial progress.
Hi @lhames, there were several issues that needed to be addressed to fully support SEH: COMDAT section symbols, GOT/PLT handling, ADDR32NB stubs, filtering DLLImportDefinitionGenerators, and keep alives for COMDAT sections.
I’ve opened a PR at lhames#5 for you to get a preliminary look. I’m happy to answer any questions or explain the fixes in more detail. I’ll flesh out the PR description in the next day or so, just wanted to give you a quick heads up first.
I’ve also bundled a set of tests, with one covering each issue addressed. The good news is that all exception tests are now passing in jank, which is a pretty significant milestone.
I did have to backport the changes to LLVM 22, though, because LLVM 23 currently can't compile jank. It gets stuck compiling a plain C++ file, unrelated to the JIT itself.
Hi @lhames, I've updated the PR with explanations for each of the fixes. When you have a chance, could you please take a look and suggest how we might best move it forward? thanks
Activity
llvmbot commentedon Oct 15, 2025
@llvm/issue-subscribers-orcjit
Author: Lang Hames (lhames)
Details
It'd be nice to get Windows SEH working without requiring the ORC runtime.This would bring Windows into line with Darwin and Linux, both of which support exceptions in-process without the runtime.
RtlAddFunctionTable(https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtladdfunctiontable) andRtlDeleteFunctionTableseem to be the registration APIs.RtlAddFunctionTabletakes a base address and a pointer to a table where function addresses are expressed as 32-bit offsets from the base:I do not know whether the SEH runtime looks at any metadata at the base address, or whether it's used purely for address calculations, but I suspect the latter (or the various out-of-tree SEH experiments that people have gotten working would have blown up differently).
Assuming that
BaseAddressis only used for address calculation then we can probably just find the lowest address in the graph and use that for each grab.If
BaseAddressneeds to contain useful metadata (e.g. a COFF header) then we can do something similar to what we do for compact-unwind (seellvm-project/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h
Line 634 in d83fe12
jeaye commentedon Oct 15, 2025
Thanks, Lang! @ikappaki for vis.
ikappaki commentedon Oct 16, 2025
Thanks both! Linking initial issue with steps to reproduce: #126365
lhames commentedon Oct 17, 2025
#158270 also probably involves constructing a valid
__ImageBase.lhames commentedon Apr 30, 2026
I've posted a sketch of what simple in-process SEH registration might look like in lhames@fe70221.
You can ignore the code in the
#elsebranch with the// for testing purposes onlycomment: that was just so that I could build this at all on Darwin. On Windows I'd expect those types to come fromwinnt.h.The plugin logic is simple:
registerFrameInfois registered as a post-fixup pass inmodifyPassConfig, which means thatregisterFrameInfowill run at the end of the linker pipeline after all addresses have been assigned and content written to the linker's working memory. TheregisterFrameInfopass looks for a.pdatasection and, if one exists, then it (a) finds the effective base address of the image (from__ImageBaseif defined, otherwise taking the lowest address in the object file), then (b) adds allocation actions to callRtlAddFunctionTable(when the JIT'd memory is finalised) andRtlDeleteFunctionTable(when the JIT'd memory is deallocated).The allocation actions are implemented as static methods (
registerPDataandderegisterPData) in the plugin class itself, so this will only work in-process.ikappaki commentedon May 3, 2026
Hi @lhames, thanks for the sketch and guidance, I’m taking a look . The code compiles fine (the correct header is
<windows.h>) and I’m making good initial progress.ikappaki commentedon May 21, 2026
Hi @lhames, there were several issues that needed to be addressed to fully support SEH: COMDAT section symbols, GOT/PLT handling, ADDR32NB stubs, filtering DLLImportDefinitionGenerators, and keep alives for COMDAT sections.
I’ve opened a PR at lhames#5 for you to get a preliminary look. I’m happy to answer any questions or explain the fixes in more detail. I’ll flesh out the PR description in the next day or so, just wanted to give you a quick heads up first.
I’ve also bundled a set of tests, with one covering each issue addressed. The good news is that all exception tests are now passing in jank, which is a pretty significant milestone.
I did have to backport the changes to LLVM 22, though, because LLVM 23 currently can't compile jank. It gets stuck compiling a plain C++ file, unrelated to the JIT itself.
Thanks
ikappaki commentedon May 22, 2026
Hi @lhames, I've updated the PR with explanations for each of the fixes. When you have a chance, could you please take a look and suggest how we might best move it forward? thanks