LLJIT链接C++标准库时触发Segmentation fault:11错误求助
I've run into this exact issue before working with LLVM 10's LLJIT on macOS 10.15. The segmentation fault happens because LLJIT can't resolve critical libc++ symbols (like those for std::vector operations) by default—even though your main executable links against libc++. Let's break down the problem and fix it step by step.
Environment Context
- OS: macOS 10.15.2
- LLVM: 10
- Clang: 11
Reproducible Code
main.cpp (LLJIT Loading Logic)
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/TargetSelect.h" #include <fstream> #include <iostream> using namespace std; using namespace llvm; using namespace llvm::orc; int main(int argc, char *argv[]) { InitLLVM X(argc, argv); InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); ThreadSafeContext context(std::make_unique<LLVMContext>()); ExitOnError ExitOnErr; auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost()); JTMB.setCodeModel(CodeModel::Small); auto jit = ExitOnErr(LLJITBuilder() .setJITTargetMachineBuilder(std::move(JTMB)) .create()); jit->getMainJITDylib().addGenerator( ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( jit->getDataLayout().getGlobalPrefix()))); char ffi_file[] = "build/ffi"; llvm::Error err = jit->addObjectFile(ExitOnErr(errorOrToExpected(MemoryBuffer::getFileAsStream(ffi_file)))); if (err) { cout << "error addObjectFile" << endl; return 1; }; char func_name[] = "add"; auto func_add = ExitOnErr(jit->lookup(func_name)); int (*func)(int, int) = (int (*)(int, int))func_add.getAddress(); int result = func(111, 222); cout << "result: " << result << endl; return 0; }
ffi.cpp (Compiled to build/ffi)
#include <vector> extern "C" int add(int a, int b) { std::vector<int> vc; vc.push_back(1); return a + b; }
CMake Configuration
cmake_minimum_required(VERSION 3.15.0) project(jitdemo) SET (CMAKE_C_COMPILER /usr/bin/clang) SET (CMAKE_CXX_COMPILER /usr/bin/clang++) SET ( CMAKE_BUILD_TYPE Debug ) find_package(LLVM REQUIRED CONFIG) message(STATUS ">>Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS ">>Using LLVMConfig.cmake in: ${LLVM_DIR}") add_compile_options(-std=c++17) add_compile_options(-stdlib=libc++) add_definitions(${LLVM_DEFINITIONS}) include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${PROJECT_SOURCE_DIR}) add_subdirectory(link) llvm_map_components_to_libnames(llvm_libs support core orcjit irreader nativecodegen) add_executable(main main.cpp) target_link_libraries(main link ${llvm_libs})
Root Cause
On macOS, LLJIT's default symbol search doesn't automatically include all symbols from libc++. When your JITted function calls std::vector::push_back, LLJIT can't find the implementation of this method (or underlying dependencies like memory allocation routines), leading to a segmentation fault when trying to execute unresolved code.
Additionally, if your ffi object file isn't compiled as position-independent code (PIC), it might cause memory addressing issues when loaded into the JIT's memory space.
Fix Steps
1. Compile ffi.cpp as Position-Independent Code (PIC)
Update the CMake configuration for your ffi target (in link/CMakeLists.txt) to add the -fPIC flag—this is required for code loaded by JIT:
# Example link/CMakeLists.txt add_library(ffi OBJECT ffi.cpp) # Or if building a shared library: add_library(ffi SHARED ffi.cpp) target_compile_options(ffi PRIVATE -fPIC -std=c++17 -stdlib=libc++)
2. Explicitly Add libc++ Symbols to LLJIT's Search Path
Modify the symbol generator setup in main.cpp to explicitly load libc++ and include its symbols in the JIT's search scope:
// Replace the existing generator setup with this: auto currentProcessGenerator = ExitOnErr( orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( jit->getDataLayout().getGlobalPrefix())); jit->getMainJITDylib().addGenerator(std::move(currentProcessGenerator)); // Explicitly load libc++ and add its symbols to the JIT's search path sys::DynamicLibrary libcxx; if (auto Err = sys::DynamicLibrary::LoadLibrary("/usr/lib/libc++.dylib", &libcxx)) { ExitOnErr(std::move(Err)); } auto libcxxGenerator = ExitOnErr( orc::DynamicLibrarySearchGenerator::Create( libcxx, jit->getDataLayout().getGlobalPrefix())); jit->getMainJITDylib().addGenerator(std::move(libcxxGenerator));
3. Verify Compilation Consistency
Ensure both your main executable and the ffi code are compiled with the same standard library (-stdlib=libc++) and C++ version (-std=c++17) to avoid ABI mismatches. Your existing CMake already sets these flags, so this should be covered, but double-check to be safe.
After making these changes, your LLJIT should correctly resolve all std::vector related symbols, and the segmentation fault should be resolved.
内容的提问来源于stack exchange,提问作者Lanistor

