aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-18 08:11:39 +0000
committer_ov4 <ov4@ov4.org>2026-10-18 08:11:39 +0000
commitcd3c09a5c2566d674680193042baf6474b6d0976 (patch)
tree50276c3de1ee4262eccbddb4240bf4267c04a15f /tools
parent30fced09675acfd2b9ab6db6be8359a70d3f0402 (diff)
feat(driver): load the embedded C++ runtime into the JIT
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/driver/EmbeddedRunner.cc54
-rw-r--r--tools/driver/NativeCompiler.cc20
-rw-r--r--tools/driver/NativeCompiler.h5
3 files changed, 79 insertions, 0 deletions
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc
index f7077f2..3eedf8f 100644
--- a/tools/driver/EmbeddedRunner.cc
+++ b/tools/driver/EmbeddedRunner.cc
@@ -1,4 +1,6 @@
#include "EmbeddedRunner.h"
+#include "NativeCompiler.h"
+#include "llvm/Object/ObjectFile.h"
#include "cps/CodeGen.h"
#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
@@ -321,6 +323,22 @@ static llvm::Error defineRuntimeSymbols(llvm::orc::LLJIT &J) {
using llvm::orc::ExecutorSymbolDef;
Symbols[Intern("__cxa_allocate_exception")] =
ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_allocate_exception);
+ Symbols[Intern("__cxa_current_exception_type")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_current_exception_type);
+ Symbols[Intern("__cxa_demangle")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_demangle);
+ Symbols[Intern("__cxa_free_exception")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_free_exception);
+ Symbols[Intern("__cxa_rethrow")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_rethrow);
+ Symbols[Intern("__cxa_get_exception_ptr")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_get_exception_ptr);
+ Symbols[Intern("__cxa_guard_acquire")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_guard_acquire);
+ Symbols[Intern("__cxa_guard_release")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_guard_release);
+ Symbols[Intern("__cxa_guard_abort")] =
+ ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_guard_abort);
Symbols[Intern("__cxa_throw")] =
ExecutorSymbolDef::fromPtr(&__cxxabiv1::__cxa_throw);
Symbols[Intern("__cxa_begin_catch")] =
@@ -370,6 +388,37 @@ static llvm::Error defineRuntimeSymbols(llvm::orc::LLJIT &J) {
llvm::orc::absoluteSymbols(std::move(Symbols)));
}
+static llvm::Error loadCxxRuntime(llvm::orc::LLJIT &J) {
+ std::vector<std::unique_ptr<llvm::MemoryBuffer>> Archives;
+ if (!unpackCxxRuntime(Archives))
+ return llvm::make_error<llvm::StringError>("cannot unpack the C++ runtime", llvm::inconvertibleErrorCode());
+ for (auto &Archive : Archives) {
+ auto Generator = llvm::orc::StaticLibraryDefinitionGenerator::Create(
+ J.getObjLinkingLayer(), std::move(Archive),
+ [](llvm::object::Archive &, llvm::MemoryBufferRef Buffer, size_t) -> llvm::Expected<bool> {
+ auto Object = llvm::object::ObjectFile::createObjectFile(Buffer);
+ if (!Object) { llvm::consumeError(Object.takeError()); return false; }
+ // Keep one exception ABI and unwinder. ABI archive members must
+ // not replace the host addresses registered above.
+ for (const auto &Symbol : (*Object)->symbols()) {
+ auto Flags = Symbol.getFlags();
+ if (!Flags) return Flags.takeError();
+ if (*Flags & llvm::object::SymbolRef::SF_Undefined) continue;
+ auto Name = Symbol.getName();
+ if (!Name) return Name.takeError();
+ llvm::StringRef N = *Name;
+ if ((*Object)->isMachO() && N.starts_with("_")) N = N.drop_front();
+ if (N.starts_with("__cxa_") || N.starts_with("__gxx_personality_") ||
+ N.starts_with("_Unwind_") || N == "_ZTIi") return false;
+ }
+ return true;
+ });
+ if (!Generator) return Generator.takeError();
+ J.getMainJITDylib().addGenerator(std::move(*Generator));
+ }
+ return llvm::Error::success();
+}
+
int runEmbedded(const cps::CodeGen &CG, const std::vector<std::string> &Objects) {
if (llvm::InitializeNativeTarget() || llvm::InitializeNativeTargetAsmPrinter()) {
llvm::errs() << "error: cannot initialize the embedded LLVM target\n";
@@ -412,6 +461,11 @@ int runEmbedded(const cps::CodeGen &CG, const std::vector<std::string> &Objects)
<< llvm::toString(std::move(Err)) << "\n";
return 1;
}
+ if (auto Err = loadCxxRuntime(*J)) {
+ llvm::errs() << "error: cannot load embedded C++ runtime: "
+ << llvm::toString(std::move(Err)) << "\n";
+ return 1;
+ }
#ifdef _WIN32
// Process-wide lookup may find C functions in ucrtbase.dll, loaded by
// system DLLs, whose stdio buffers differ from the host's msvcrt. Prefer
diff --git a/tools/driver/NativeCompiler.cc b/tools/driver/NativeCompiler.cc
index 4547203..e09fe98 100644
--- a/tools/driver/NativeCompiler.cc
+++ b/tools/driver/NativeCompiler.cc
@@ -180,6 +180,26 @@ bool collectLibcSymbols(llvm::StringSet<> &Out) {
return true;
}
+bool unpackCxxRuntime(std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Archives) {
+ llvm::json::Object *Metadata = nullptr;
+ std::optional<llvm::json::Value> Manifest;
+ llvm::SmallVector<uint8_t, 0> Data;
+ if (!unpackRuntime(Metadata, Manifest, Data)) return false;
+ for (const auto &Entry : *Metadata->getArray("files")) {
+ const auto &File = *Entry.getAsObject();
+ llvm::StringRef Path = *File.getString("path");
+ llvm::StringRef Name = llvm::sys::path::filename(Path);
+ // The unwind and C libraries continue to come from the host process.
+ if (*File.getBoolean("script") ||
+ !(Name == "libstdc++.a" || Name == "libc++.a" || Name == "libc++abi.a" ||
+ Name == "libgcc.a" || Name == "libmingwex.a" || Name == "libm.a")) continue;
+ llvm::StringRef Contents(reinterpret_cast<const char *>(Data.data()) +
+ *File.getInteger("offset"), *File.getInteger("size"));
+ Archives.push_back(llvm::MemoryBuffer::getMemBufferCopy(Contents, Path));
+ }
+ return true;
+}
+
bool compileNative(const cps::CodeGen &CG, llvm::StringRef OutputPath, const char *Argv0,
const std::vector<std::string> &Objects) {
TemporaryDirectory Runtime;
diff --git a/tools/driver/NativeCompiler.h b/tools/driver/NativeCompiler.h
index ffc38f1..54b690f 100644
--- a/tools/driver/NativeCompiler.h
+++ b/tools/driver/NativeCompiler.h
@@ -2,6 +2,8 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
#include <string>
#include <vector>
@@ -19,3 +21,6 @@ bool collectObjectSymbols(llvm::StringRef Path, llvm::StringSet<> &Out, std::str
// Defined global symbols of the embedded C library (INCLUDE_OBJ "__libc").
bool collectLibcSymbols(llvm::StringSet<> &Out);
+
+// Owning copies of the embedded C++ and compiler-support static archives.
+bool unpackCxxRuntime(std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Archives);