aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-16 16:38:48 +0000
committer_ov4 <ov4@ov4.org>2026-10-16 16:38:48 +0000
commit8489d0bd3e0121e1d804da5139606dc6532b864f (patch)
tree80195f6d93e9fc36ea4b0dc3048a3f73f5a8a211 /tools
parent838d636d42db87b91f8b37bd39ab71ed3dc90599 (diff)
fix(jit): keep COFF unwind tables addressable from JIT memory
COFF unwind tables use 32-bit image-relative addresses. Alias the external __ImageBase to the lowest defined block once addresses are final, and route the personality through a JIT-local stub so both stay within range of the JIT tables. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/driver/EmbeddedRunner.cc82
1 files changed, 63 insertions, 19 deletions
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc
index 0c1346f..2bb7e3b 100644
--- a/tools/driver/EmbeddedRunner.cc
+++ b/tools/driver/EmbeddedRunner.cc
@@ -4,10 +4,12 @@
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/TargetSelect.h"
#include <cstdio>
#include <cstdlib>
+#include <string>
#include <cxxabi.h>
#include <typeinfo>
#include <unwind.h>
@@ -132,35 +134,37 @@ public:
return Error::success();
});
- // Define a per-graph __ImageBase and build stubs for externals.
+ // Build GOT/stub entries for externals. Host runtime calls reach
+ // their far addresses through these under the large code model.
Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
using namespace llvm::jitlink::x86_64;
- // External calls and personality references use the generic
- // x86_64 pointer and stub builders.
GOTTableManager GOT(G);
PLTTableManager PLT(G, GOT);
visitExistingEdges(G, GOT, PLT);
+ return Error::success();
+ });
+ // COFF unwind tables use 32-bit image-relative addresses, so the
+ // image base must sit at or below the lowest JIT address. Alias the
+ // external __ImageBase to the lowest defined block once addresses
+ // are final; a trailing zero block would push RVAs negative.
+ Config.PostAllocationPasses.push_back([](LinkGraph &G) -> Error {
auto *ImageBaseExt =
G.findExternalSymbolByName(G.intern("__ImageBase"));
- auto *PDataSec = G.findSectionByName(".pdata");
- if (!ImageBaseExt && !PDataSec)
+ if (!ImageBaseExt)
return Error::success();
- // One base per graph so relocations and SEH registration agree.
- Section *BaseSec = G.findSectionByName("__image_base");
- if (!BaseSec)
- BaseSec = &G.createSection("__image_base", orc::MemProt::Read);
- static const char ZeroContent[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- auto &BaseBlock = G.createContentBlock(
- *BaseSec, ArrayRef<char>(ZeroContent, sizeof(ZeroContent)),
- orc::ExecutorAddr(), 8, 0);
- if (ImageBaseExt) {
- G.makeDefined(*ImageBaseExt, BaseBlock, 0, 8,
- Linkage::Strong, Scope::Default, true);
- } else {
- G.addDefinedSymbol(BaseBlock, 0, "__ImageBase", 8,
- Linkage::Strong, Scope::Default, false, true);
+ jitlink::Block *Low = nullptr;
+ for (auto &Sec : G.sections()) {
+ for (auto *B : Sec.blocks()) {
+ if (!Low || B->getAddress() < Low->getAddress())
+ Low = B;
+ }
}
+ if (!Low)
+ return make_error<JITLinkError>(
+ "missing embedded __ImageBase content");
+ G.makeDefined(*ImageBaseExt, *Low, 0, 8, Linkage::Strong,
+ Scope::Default, true);
return Error::success();
});
@@ -427,6 +431,46 @@ int runEmbedded(const cps::CodeGen &CG) {
if (auto Err = TSM.withModuleDo([&](llvm::Module &M) -> llvm::Error {
M.setTargetTriple(J->getTargetTriple());
M.setDataLayout(J->getDataLayout());
+ // COFF unwind tables address the personality by 32-bit RVA, so
+ // it must live near JIT code. Route through a JIT-local stub;
+ // the stub's own call to the host runtime uses 64-bit. Same
+ // code on all platforms; only COFF needs it.
+ if (J->getTargetTriple().isOSBinFormatCOFF()) {
+ for (const char *RealName :
+ {"__gxx_personality_seh0", "__gxx_personality_sj0",
+ "__gxx_personality_v0"}) {
+ llvm::Function *Real = M.getFunction(RealName);
+ if (!Real)
+ continue;
+ bool Used = false;
+ for (auto &F : M.functions()) {
+ if (F.getPersonalityFn() &&
+ F.getPersonalityFn()->stripPointerCasts() == Real) {
+ Used = true;
+ break;
+ }
+ }
+ if (!Used)
+ continue;
+ std::string FwdName = std::string("__cps_jit_") + RealName;
+ if (M.getFunction(FwdName))
+ continue;
+ llvm::Function *Fwd = llvm::Function::Create(
+ Real->getFunctionType(),
+ llvm::GlobalValue::InternalLinkage, FwdName, M);
+ llvm::BasicBlock *BB = llvm::BasicBlock::Create(
+ M.getContext(), "", Fwd);
+ llvm::IRBuilder<> B(BB);
+ llvm::CallInst *C = B.CreateCall(Real, {});
+ C->setTailCall();
+ B.CreateRet(C);
+ for (auto &F : M.functions()) {
+ if (F.getPersonalityFn() &&
+ F.getPersonalityFn()->stripPointerCasts() == Real)
+ F.setPersonalityFn(Fwd);
+ }
+ }
+ }
return llvm::Error::success();
})) {
llvm::errs() << "error: cannot configure the embedded JIT module: "