aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-18 08:59:49 +0000
committer_ov4 <ov4@ov4.org>2026-10-18 08:59:49 +0000
commiteaabdf5796594be87084758fa524622db1c1dbaa (patch)
tree38d0d602accafe5e7145066eb146c993dd162fdb /tools
parentc5f103663bbee226d20bf6405457a62e7ec41611 (diff)
fix(driver): bind MinGW JIT runtime dependencies to host symbols
Resolve the known weak __cxa_pure_virtual reference through the host ABI instead of JITLink's unsupported absolute-zero fallback. Share the host's initialized stack guard and failure handler, and map write to _write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/driver/EmbeddedRunner.cc19
-rw-r--r--tools/driver/MinGWCOFF.h31
2 files changed, 47 insertions, 3 deletions
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc
index 7bfbcf0..28fe2db 100644
--- a/tools/driver/EmbeddedRunner.cc
+++ b/tools/driver/EmbeddedRunner.cc
@@ -31,6 +31,9 @@
// Parse all LLVM COFF declarations and helpers before introducing those macros.
#include <windows.h>
#endif
+#ifdef __MINGW32__
+#include <io.h>
+#endif
namespace {
@@ -284,7 +287,7 @@ public:
void emit(std::unique_ptr<llvm::orc::MaterializationResponsibility> R,
std::unique_ptr<llvm::MemoryBuffer> O) override {
- auto Normalized = normalizeMinGWUnwindSections(std::move(O));
+ auto Normalized = normalizeMinGWObject(std::move(O));
if (!Normalized) {
getExecutionSession().reportError(Normalized.takeError());
R->failMaterialization();
@@ -345,6 +348,12 @@ extern "C" void __cps_jit_noop__main() {}
#if defined(__MINGW32__) && defined(__x86_64__)
extern "C" void ___chkstk_ms(void);
#endif
+#ifdef __MINGW32__
+// Use the initialized guard and failure handler from the statically linked
+// host runtime rather than loading a second guard and its CRT initializer.
+extern "C" uintptr_t __stack_chk_guard;
+extern "C" void __stack_chk_fail(void);
+#endif
static llvm::Error defineRuntimeSymbols(llvm::orc::LLJIT &J) {
llvm::orc::SymbolMap Symbols;
@@ -370,6 +379,8 @@ static llvm::Error defineRuntimeSymbols(llvm::orc::LLJIT &J) {
ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_guard_abort);
Symbols[Intern("__cxa_throw")] =
ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_throw);
+ Symbols[Intern("__cxa_pure_virtual")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_pure_virtual);
Symbols[Intern("__cxa_begin_catch")] =
ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_begin_catch);
Symbols[Intern("__cxa_end_catch")] =
@@ -396,6 +407,12 @@ static llvm::Error defineRuntimeSymbols(llvm::orc::LLJIT &J) {
ExecutorSymbolDef::fromPtr(&__ms_snprintf);
Symbols[Intern("strtoll")] =
ExecutorSymbolDef::fromPtr(&std::strtoll);
+ // msvcrt.dll exports _write; MinGW archive members call its POSIX alias.
+ Symbols[Intern("write")] = ExecutorSymbolDef::fromPtr(&_write);
+ Symbols[Intern("__stack_chk_guard")] =
+ ExecutorSymbolDef::fromPtr(&__stack_chk_guard);
+ Symbols[Intern("__stack_chk_fail")] =
+ ExecutorSymbolDef::fromPtr(&__stack_chk_fail);
#endif
#ifdef _WIN32
// Generated diagnostics write to stderr through __acrt_iob_func(2). The
diff --git a/tools/driver/MinGWCOFF.h b/tools/driver/MinGWCOFF.h
index 22b8fb2..186d981 100644
--- a/tools/driver/MinGWCOFF.h
+++ b/tools/driver/MinGWCOFF.h
@@ -6,6 +6,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/MemoryBuffer.h"
+#include <cstddef>
#include <cstring>
namespace {
@@ -20,7 +21,7 @@ inline bool isCOFFUnwindSection(llvm::StringRef Name, llvm::StringRef Base) {
// symbol used by relocations. Express their implicit association with .text$foo
// as ordinary associative COMDATs in a private copy of the object instead.
inline llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
-normalizeMinGWUnwindSections(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+normalizeMinGWObject(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
using namespace llvm;
auto Object = object::ObjectFile::createObjectFile(Buffer->getMemBufferRef());
if (!Object)
@@ -48,8 +49,28 @@ normalizeMinGWUnwindSections(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
struct Association { size_t Offset; int32_t Parent; };
SmallVector<Association, 16> Associations;
+ SmallVector<size_t, 2> PureVirtualReferences;
for (const auto &Symbol : COFF->symbols()) {
auto Sym = COFF->getCOFFSymbol(Symbol);
+ if (auto *Weak = Sym.getWeakExternal()) {
+ auto Name = Symbol.getName();
+ if (!Name)
+ return Name.takeError();
+ if (*Name == "__cxa_pure_virtual" &&
+ Weak->Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY) {
+ auto Fallback = COFF->getSymbol(Weak->TagIndex);
+ if (!Fallback)
+ return Fallback.takeError();
+ if (Fallback->isAbsolute() && Fallback->getValue() == 0) {
+ size_t Offset = reinterpret_cast<const char *>(Sym.getRawPtr()) -
+ Buffer->getBufferStart();
+ Offset += Sym.isBigObj()
+ ? offsetof(object::coff_symbol32, StorageClass)
+ : offsetof(object::coff_symbol16, StorageClass);
+ PureVirtualReferences.push_back(Offset);
+ }
+ }
+ }
auto *Def = Sym.getSectionDefinition();
if (!Def || Def->Selection != COFF::IMAGE_COMDAT_SELECT_ANY ||
Sym.getSectionNumber() <= 0 ||
@@ -77,7 +98,7 @@ normalizeMinGWUnwindSections(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
Buffer->getBufferStart()),
Parent->second});
}
- if (Associations.empty())
+ if (Associations.empty() && PureVirtualReferences.empty())
return std::move(Buffer);
auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(
@@ -91,6 +112,12 @@ normalizeMinGWUnwindSections(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
Def->NumberLowPart = A.Parent & 0xffff;
Def->NumberHighPart = static_cast<uint32_t>(A.Parent) >> 16;
}
+ // JITLink cannot alias a weak external to an absolute-zero fallback.
+ // The runner always supplies the host's __cxa_pure_virtual, so this known
+ // optional ABI reference can be an ordinary external. Keep its auxiliary
+ // entry count intact so the remaining symbol indices do not move.
+ for (size_t Offset : PureVirtualReferences)
+ Copy->getBufferStart()[Offset] = COFF::IMAGE_SYM_CLASS_EXTERNAL;
return std::unique_ptr<MemoryBuffer>(std::move(Copy));
}