LLVM ORC V2 符号到全局变量

LLVM ORC V2 Symbol to Global Variable

我正在尝试使用全局变量从 LLVM IR 访问主机程序中的变量,但我在使其工作时遇到了问题。我在主 JitDylib 中声明了一个具有所需变量地址的符号。之后,我创建了具有相同名称的全局变量,并带有外部链接,以便链接器可以找到它。但它不起作用。执行 Jit 函数会使主机程序崩溃。

下面是我基于 LLVM 存储库中的 LLJIT 示例的测试程序。我尝试了很多方法,例如使用 CreateGEP 获取有效指针,或使用不同的 JitDylib 来声明符号。但是 none 对我有用。我怀疑这是链接相关的东西。有没有人使用新的 ORC V2 JIT API?

//===-- examples/HowToUseJIT/HowToUseJIT.cpp - An example use of the JIT --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//===-- examples/HowToUseJIT/HowToUseJIT.cpp - An example use of the JIT --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace llvm::orc;

ExitOnError ExitOnErr;

ThreadSafeModule createDemoModule() 
{
    auto Context = std::make_unique<LLVMContext>();
    auto M = std::make_unique<Module>("test", *Context);

    Function* Add1F =
        Function::Create(FunctionType::get(Type::getInt64Ty(*Context),
            { }, false),
            Function::ExternalLinkage, "add1", M.get());

    BasicBlock* BB = BasicBlock::Create(*Context, "EntryBlock", Add1F);

    IRBuilder<> builder(BB);

    Value* One = builder.getInt32(1);

    llvm::Type* arr_ty = builder.getInt32Ty()->getPointerTo();
    llvm::GlobalVariable* g = new llvm::GlobalVariable(*M, arr_ty, true, llvm::GlobalValue::LinkageTypes::ExternalLinkage, nullptr, "_mptr");
    g->setInitializer(ConstantPointerNull::get(cast<PointerType>(g->getType()->getPointerElementType())));
    g->setExternallyInitialized(true);

    auto g_loaded = builder.CreateLoad(g);
    auto Val = builder.CreateLoad(g_loaded);

    Value* Add = builder.CreateAdd(One, Val);
    builder.CreateRet(Add);

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

int main(int argc, char* argv[]) 
{
    InitLLVM X(argc, argv);

    InitializeNativeTarget();
    InitializeNativeTargetAsmPrinter();

    cl::ParseCommandLineOptions(argc, argv, "HowToUseLLJIT");
    ExitOnErr.setBanner(std::string(argv[0]) + ": ");

    auto J = ExitOnErr(LLJITBuilder().create());

    uint32_t test = 5;

    auto& ES = J->getExecutionSession();
    auto& DL = J->getDataLayout();
    MangleAndInterner Mangle(ES, DL);

    auto& JD = J->getMainJITDylib();
    JD.define(
        llvm::orc::absoluteSymbols({
            { Mangle("_mptr"), { llvm::pointerToJITTargetAddress(&test), llvm::JITSymbolFlags::Exported } }
        }));

    auto M = createDemoModule();

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

    auto Add1Sym = ExitOnErr(J->lookup("add1"));
    int (*Add1)() = (int (*)())Add1Sym.getAddress();

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

    return 0;
}

需要告知 JITDylib 在主机程序中搜索符号,如下所示:

JD.addGenerator(cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())))

您定义绝对符号的方法也应该有效。但是,我认为在这种情况下您不需要修改变量名。您可能还想添加 llvm::JITSymbolFlags::Absolute 符号标志。你可以试试这个:

   JD.define(
    llvm::orc::absoluteSymbols({
        { ES->intern("_mptr"), { llvm::pointerToJITTargetAddress(&test), llvm::JITSymbolFlags::Exported | llvm::JITSymbolFlags::Absolute} }
    }));

最后,您可以简单地将地址硬编码为常量,而不依赖任何链接,如下所示:

llvm::ConstantInt* addressConstant = llvm::ConstantInt::get(Context, llvm::APInt(sizeof(std::uintptr_t) * 8, reinterpret_cast<uint64_t>(&test), false));
llvm::Value* testPtr =  builder->CreateIntToPtr(addressConstant, llvm::Type::getInt8PtrTy(Context));