Невозможно выполнить функцию JITed от 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? Если да, как я могу сделать JIT-функции из 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;
}

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), Это должно "завершить" генерацию кода, изменив разрешения для памяти.

Другие вопросы по тегам