如何正确销毁LLVMModule和LLVMExecutionEngine?

时间:2016-03-20 02:42:41

标签: c llvm

我有一个使用LLVM-C的简单程序:

#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS

#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/BitWriter.h>
#include <llvm-c/Linker.h>

#include <stdlib.h>
#include <stdio.h>

int main() {
    LLVMInitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    LLVMInitializeNativeAsmParser();

    LLVMContextRef ctx = LLVMGetGlobalContext();
    LLVMModuleRef mod = LLVMModuleCreateWithNameInContext("mymodule", ctx);
    LLVMTypeRef functype = LLVMFunctionType(LLVMInt32Type(), NULL, 0, 0);
    LLVMValueRef func = LLVMAddFunction(mod, "constfunc", functype);

    LLVMBasicBlockRef entry = LLVMAppendBasicBlock(func, "entry");
    LLVMBuilderRef builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, entry);
    LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 2, 0));
    LLVMDisposeBuilder(builder);

    char* error = NULL;
    LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
    LLVMDisposeMessage(error);
    error = NULL;
    LLVMExecutionEngineRef engine;
    if (LLVMCreateMCJITCompilerForModule (&engine, mod, NULL, 0, &error) != 0) {
        fprintf(stderr, "failed to create execution engine\n");
        exit(EXIT_FAILURE);
    }

    int (*func_p)(void) = (int(*)(void)) LLVMGetFunctionAddress(engine, "constfunc");
    printf("%d\n", func_p());

    LLVMDisposeExecutionEngine(engine);
    LLVMDisposeModule(mod);

    return 0;
}

原样,它在LLVMDisposeModule

内部分段错误
(gdb) run
Starting program: /home/col/llvmtest 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
2

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff668fbcc in llvm::SmallPtrSetImplBase::erase_imp(void const*) () from /usr/local/lib/libLLVM-3.7.1.so
(gdb) bt
#0  0x00007ffff668fbcc in llvm::SmallPtrSetImplBase::erase_imp(void const*) () from /usr/local/lib/libLLVM-3.7.1.so
#1  0x00007ffff5d60f00 in llvm::Module::~Module() () from /usr/local/lib/libLLVM-3.7.1.so
#2  0x00007ffff5c62b5e in LLVMDisposeModule () from /usr/local/lib/libLLVM-3.7.1.so
#3  0x00000000004010cd in main () at llvmtest.c:44

但是,如果我注释掉LLVMDisposeExecutionEngineLLVMDisposeModule的来电,则不再是段错误。

使用C API销毁LLVM模块和执行引擎的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

我看到列出的代码存在两个问题,

第一个问题和您的查询是, 当您调用LLVMCreateMCJITCompilerForModule时,它将提供的模块添加到执行引擎的模块列表中,下面是ExecutionEngineBindings.cpp中相同的剪切代码:196

std::string Error;
EngineBuilder builder(std::move(Mod));
builder.setEngineKind(EngineKind::JIT)
          .setErrorStr(&Error)
          .setOptLevel((CodeGenOpt::Level)options.OptLevel)
          .setCodeModel(unwrap(options.CodeModel))
          .setTargetOptions(targetOptions);
   if (options.MCJMM)
     builder.setMCJITMemoryManager(
       std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM)));
   if (ExecutionEngine *JIT = builder.create()) {
     *OutJIT = wrap(JIT);

因此,当您调用LLVMDisposeExecutionEngine时,它已删除了引擎列表中列出的所有模块,因此正确的方法是在部署执行引擎之前需要从列表中删除模块。 (代码在同一个文件ExecutionEngineBindings.cpp:258中)

 LLVMRemoveModule(engine, mod, &mod, &error);
 LLVMDisposeExecutionEngine(engine);

,第二个是JIT尚未链接,没有调用LLVMLinkInMCJIT(),它应该在LLVMInitializeNativeTarget()之前;

 LLVMLinkInMCJIT();
 LLVMInitializeNativeTarget();