在使用llvm-13构建(OrcV2)Jit编译器时,如何解析当前会话中的符号?

How to resolve symbols that reside in the current session when constructing a (OrcV2) Jit compiler with llvm-13?(在使用llvm-13构建(OrcV2)Jit编译器时,如何解析当前会话中的符号?)

本文介绍了在使用llvm-13构建(OrcV2)Jit编译器时,如何解析当前会话中的符号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑

我基本上是在尝试this,但使用llvm的orcJit API(llvm-13)


我有一个库,其中包含一些使用llvm(13)的代码。我想让JIT使用该库中的一些函数,而不必用LLVMIR编写它们。

以下是一些代码:


#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/Mangling.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/TargetSelect.h"


using namespace llvm;
using namespace llvm::orc;

// this is just a demo module that creates a function that adds 1 to an int
ThreadSafeModule makeSimpleModule() {
    auto Context = std::make_unique<LLVMContext>();
    auto M = std::make_unique<Module>("test", *Context);

    // Create the add1 function entry and insert this entry into module M.  The
    // function will have a return type of "int" and take an argument of "int".
    Function *Add1F =
            Function::Create(FunctionType::get(Type::getInt32Ty(*Context),
                                               {Type::getInt32Ty(*Context)}, false),
                             Function::ExternalLinkage, "add1", M.get());

    // Add a basic block to the function. As before, it automatically inserts
    // because of the last argument.
    BasicBlock *BB = BasicBlock::Create(*Context, "EntryBlock", Add1F);

    // Create a basic block builder with default parameters.  The builder will
    // automatically append instructions to the basic block `BB'.
    IRBuilder<> builder(BB);

    // Get pointers to the constant `1'.
    Value *One = builder.getInt32(1);

    // Get pointers to the integer argument of the add1 function...
    assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
    Argument *ArgX = &*Add1F->arg_begin();          // Get the arg
    ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.

    // Create the add instruction, inserting it into the end of BB.
    Value *Add = builder.CreateAdd(One, ArgX);

    // Create the return instruction and add it to the basic block
    builder.CreateRet(Add);

    return {std::move(M), std::move(Context)};
}

// this represents a function in my library that I want to make available to the JIT. 
namespace mylibsubnamespace {
extern "C" {

    int add2(int a) {
        return a + 2;
    }
}
}

int main(int argc, const char *argv[]) {

    // do some JIT initialization 
    llvm::InitLLVM X(argc, argv);
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();

    // Create an LLJIT instance.
    auto J = LLJITBuilder().create();

    // this code seems to enable symbol resolution for when the missing symbol is 
    // in the standard C library (and presumably included). 
    // This is what allows the "cos" function below to work (comment it out and we get a seg fault)
    auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
            (*J)->getDataLayout().getGlobalPrefix());
    if (!DLSG) {
        llvm::logAllUnhandledErrors(
                std::move(DLSG.takeError()),
                llvm::errs(),
                "DynamicLibrarySearchGenerator not built successfully"
        );
    }
    (*J)->getMainJITDylib().addGenerator(std::move(*DLSG));


    auto M = makeSimpleModule();

    (*J)->addIRModule(std::move(M));

    // Look up the JIT'd function, cast it to a function pointer, then call it.
    // This function is written in LLVM IR directly. 
    auto Add1Sym = (*J)->lookup("add1");
    int (*Add1)(int) = (int (*)(int)) Add1Sym->getAddress();

    int Result = Add1(42);
    outs() << "add1(42) = " << Result << "
";

    // Look up the JIT'd function, cast it to a function pointer, then call it.
    // This function is defined in the standard C library. Its symbol is resolved 
    // by DynamicLibrarySearchGenerator above
    auto CosSym = (*J)->lookup("cos");
    double (*Cos)(double) = (double (*)(double)) CosSym->getAddress();

    outs() << "Cos(50) = " << Cos(50) << "
";

到目前为止一切顺利。我还没有弄清楚的是如何以可缓存的方式使add2函数可用。我已经成功地按照here的说明在当前会话中启用了地址的硬编码,如下所示:

    auto symbolStringPool = (*J)->getExecutionSession().getExecutorProcessControl().getSymbolStringPool();
    orc::SymbolStringPtr symbPtr = symbolStringPool->intern("add2");

    // JITTargetAddress is uint64 typedefd
    llvm::JITSymbolFlags flg;
    llvm::JITEvaluatedSymbol symb((std::int64_t) &mylibsubnamespace::add2, flg);
    if (llvm::Error err = (*J)->getMainJITDylib().define(
            llvm::orc::absoluteSymbols({{symbPtr, symb}}))) {
        llvm::logAllUnhandledErrors(std::move(err), llvm::errs(), "Could not add symbol add2");
    }
但instructions明确建议不要使用此策略,因为以这种方式解析的符号不可缓存。但是,使用类似说明建议的方式来解析符号:

JD.addGenerator(DynamicLibrarySearchGenerator::Load("/path/to/lib"
                                                    DL.getGlobalPrefix()));

是不可能的,因为没有/path/to/lib。处理此类情况的正常方法是什么?

推荐答案

您需要的是向链接器添加-rdynamic-Wl, -export-dynamic标志。

-E--导出-动态

在创建动态链接的可执行文件时,将所有符号添加到动态符号表。动态符号表是在运行时从动态对象可见的符号集。如果不使用此选项,动态符号表通常只包含链接中提到的某些动态对象引用的符号。如果使用dlopen加载需要引用程序定义的符号的动态对象,而不是某个其他动态对象,则在链接程序本身时可能需要使用此选项。

这篇关于在使用llvm-13构建(OrcV2)Jit编译器时,如何解析当前会话中的符号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:在使用llvm-13构建(OrcV2)Jit编译器时,如何解析当前会话中的符号?