Cannot execute function JITed by LLVM

2019-07-27 13:07发布

问题:

Using LLVM-5.0 I implemented a minimal testcase that creates assembly for a function returning the 32bit integer "42" at runtime and executes it.

Using llvm::ExecutionEngine I was able to generate the following code at runtime (displayed with gdb):

0x7ffff7ff5000  mov    $0x2a,%eax                                                                                                                                                                             
0x7ffff7ff5005  retq

Calling the function yields

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7ff5000 in ?? ()

My working theory is that the memory page LLVM wrote the code on is not executable.

Is this really a DEP problem? If yes how can I make JITed functions from LLVM actually executable?

Appendix: The actual testcase

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Verifier.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/TargetSelect.h>

#include <iostream>

int main() {
    // Initialize global state
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();

    // Initialize local state
    llvm::LLVMContext context;

    // Create the module that will be compiled
    std::unique_ptr<llvm::Module> module(new llvm::Module("jit", context));

    // Create function type
    std::vector<llvm::Type*> arg_types;
    llvm::FunctionType* func_type = llvm::FunctionType::get(llvm::Type::getInt32Ty(context), arg_types, false);

    // Create actual function
    llvm::Function* func = llvm::Function::Create(func_type, llvm::Function::LinkageTypes::ExternalLinkage, "anon", module.get());

    // Define function body
    llvm::IRBuilder<> builder(context);
    llvm::BasicBlock *block = llvm::BasicBlock::Create(context, "entry", func);
    builder.SetInsertPoint(block);
    builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 42));

    // Verify function
    llvm::verifyFunction(*func);

    // Build the execution engine
    std::string error;
    llvm::EngineBuilder engine_builder(std::move(module));
    engine_builder.setErrorStr(&error);
    engine_builder.setEngineKind(llvm::EngineKind::JIT);
    std::unique_ptr<llvm::ExecutionEngine> engine(engine_builder.create());
    if (!engine) {
        std::cerr << error << std::endl;
        return 1;
    }

    // Get a pointer to the JITed function
    void* jit_ptr = engine->getPointerToFunction(func);
    auto function = reinterpret_cast<int32_t(*)()>(jit_ptr);

    // Execute the JITed function
    std::cout << function() << std::endl;
    return 0;
}

回答1:

The method getPointerToFunction is deprecated for the MCJIT execution engine according to the sources.

  /// getPointerToFunction - (...)
  /// This function is deprecated for the MCJIT execution engine.  Use
  /// getFunctionAddress instead.
  virtual void *getPointerToFunction(Function *F) = 0;

Therefore I would use addModule(std::move(module)) followed by getFunctionAddress(functionName). This should "finalize" code generation by changing the permissions for the memory.