Не удается выполнить функцию JIT, созданную LLVM

Используя LLVM-5.0, я реализовал минимальный тестовый пример, который создает сборку для функции, возвращающей 32-битное целое число «42» во время выполнения, и выполняет ее.

Используя llvm::ExecutionEngine, я смог сгенерировать следующий код во время выполнения (отображается с помощью gdb):

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

Вызов функции дает

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

Моя рабочая теория заключается в том, что страница памяти, на которой LLVM записал код, не является исполняемой.

Это действительно проблема DEP? Если да, то как я могу сделать JITed-функции из LLVM действительно исполняемым?

Приложение: фактический тестовый пример

#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;
}

person Richard    schedule 23.10.2017    source источник


Ответы (1)


Согласно источникам, метод getPointerToFunction устарел для исполнительного механизма MCJIT.

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

Поэтому я бы использовал addModule(std::move(module)), а затем getFunctionAddress(functionName). Это должно «завершить» генерацию кода, изменив права доступа к памяти.

person PaulR    schedule 23.10.2017