1

我正在尝试在运行时在现有的 C/C++ 程序中 JIT 编译一些函数,但是我在全局变量初始化方面遇到了一些麻烦。具体来说,我采用的方法是使用 Clang 将程序预编译为 IR 位码模块以及可执行文件。在运行时,程序加载模块,转换它们(程序专业化),编译并执行它们。事实证明,我有一些全局变量在“主机”程序执行期间被初始化和修改。目前,这些全局变量也在 JIT 编译代码中被初始化,而我希望它们被映射到主机全局变量。有人可以帮我弄这个吗?

下面摘录了一个小复制品。完整的源代码在这里。文件 somefunc.cpp 在构建期间被预编译,并在 testCompile.cpp 的 main() 函数中加载。全局变量 xyz 在 somefunc.cpp 中被初始化为指向 25,但我希望它像在 main() 中那样指向 10。换句话说,main() 中的断言应该成功。

我尝试了几种不同的方法来解决这个问题。ChangeGlobal() 函数尝试(未成功)实现此 updateGlobalMapping()。第二种更老套的方法使用适当初始化的新全局变量。我可以让后一种方法适用于某些类型的全局变量,但是还有比这更优雅的方法吗?

//————— somefunc.h ————————
extern int *xyz;

//—————— somefunc.cpp ——————
int abc = 25;
int *xyz = &abc;

int somefunc() {
    return *xyz;
}

//—————— testCompile.cpp —————— 
class JitCompiler {
 public:
    JitCompiler(const std::string module_file);
    void LoadModule(const std::string& file);
    template <typename FnType>  
        FnType CompileFunc(FnType fn, const std::string& fn_name);
    void ChangeGlobal();

 private:
    std::unique_ptr<LLVMContext> context_;
    Module *module_;
    std::unique_ptr<ExecutionEngine> engine_;
};

void JitCompiler::ChangeGlobal() {
    // ----------------- #1: UpdateGlobalMapping -----------------
    //auto g = engine_->FindGlobalVariableNamed("xyz");
    //engine_->updateGlobalMapping(g, &xyz);
    //assert(engine_->getGlobalValueAddress("xyz") == (uint64_t) &xyz);

    // ----------------- #2: Replace with new global ————————
    // ------- Ugly hack that works for globals of type T** ----------
    auto g = engine_->FindGlobalVariableNamed("xyz");
    Constant *addr_i = ConstantInt::get(*context_, APInt(64, (uint64_t) xyz));
    auto addr = ConstantExpr::getIntToPtr(
                    addr_i, g->getType()->getPointerElementType());

    GlobalVariable *n = new GlobalVariable(
        *module_,
        g->getType()->getPointerElementType(),
        g->isConstant(),
        g->getLinkage(),
        addr,
        g->getName() + "_new");
    g->replaceAllUsesWith(n);
    n->takeName(g);
    g->eraseFromParent();
}

int main() {
    xyz = new int (10);
    JitCompiler jit("somefunc.bc");

    jit.ChangeGlobal();
    auto fn = jit.CompileFunc(&somefunc, "somefunc");
    assert(somefunc() == fn());
}
4

1 回答 1

0

更好的方法是将您介绍的两者结合起来,即创建一个具有映射到外部链接的新全局&xyz并将其替换为原始链接:

auto g = engine_->FindGlobalVariableNamed("xyz");

GlobalVariable *n = new GlobalVariable(
  g->getType()->getPointerElementType(),
  g->isConstant(),
  ExternalLinkage
  nullptr,
  g->getName() + "_new");

engine_->updateGlobalMapping(n, &xyz);

g->replaceAllUsesWith(n);
n->takeName(g);
g->eraseFromParent();
于 2016-06-22T21:41:24.677 回答