2015-11-21 79 views
1

我想在運行時在現有的C/C++程序中JIT編譯一些函數,但我遇到了全局變量初始化的一些麻煩。具體來說,我採用的方法是使用Clang將程序預編譯爲除可執行文件之外的IR位模塊模塊。在運行時,程序加載模塊,轉換它們(程序特化),編譯並執行它們。事實證明,我有一些全局變量在執行「主機」程序期間被初始化和修改。目前,這些全局變量也在JIT編譯代碼中初始化,而我希望它們映射到主機全局變量。有人可以幫我弄這個嗎?在MCJIT中使用全局變量

下面摘錄了一個小的轉載。完整的源代碼是here。文件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()); 
} 

回答

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();