You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LLJIT链接C++标准库时触发Segmentation fault:11错误求助

Segmentation Fault When Using LLJIT to Load C++ Function with std::vector on macOS 10.15

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:11:14