From cd3c09a5c2566d674680193042baf6474b6d0976 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sun, 18 Oct 2026 08:11:39 +0000 Subject: feat(driver): load the embedded C++ runtime into the JIT Co-Authored-By: Claude Opus 5.5 --- tools/driver/EmbeddedRunner.cc | 54 ++++++++++++++++++++++++++++++++++++++++++ tools/driver/NativeCompiler.cc | 20 ++++++++++++++++ tools/driver/NativeCompiler.h | 5 ++++ 3 files changed, 79 insertions(+) (limited to 'tools') 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> Archives; + if (!unpackCxxRuntime(Archives)) + return llvm::make_error("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 { + 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 &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 &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> &Archives) { + llvm::json::Object *Metadata = nullptr; + std::optional Manifest; + llvm::SmallVector 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(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 &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 #include #include @@ -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> &Archives); -- cgit v1.3.1-4-g156e