2015-11-21 3 views
1

Я пытаюсь скомпилировать некоторые функции в существующей программе на C/C++ во время выполнения, но у меня возникают проблемы с инициализацией глобальной переменной. В частности, подход, который я использовал, - использовать Clang для предварительной компиляции программы в модули IR-бит в дополнение к исполняемому файлу. Во время выполнения программа загружает модули, преобразует их (специализацию по программам), компилирует и выполняет их. Как оказалось, у меня есть некоторые глобальные переменные, которые инициализируются и изменяются во время выполнения программы «хозяин». В настоящее время эти глобальные переменные также инициализируются в компилированном коде JIT, тогда как я бы хотел, чтобы они были сопоставлены с глобальными переменными хоста. Может кто-то помочь мне с этим?Использование глобальных переменных в MCJIT

Небольшой репродукция выдается ниже. Полный исходный код: here. Файл somefunc.cpp получает precompiled во время сборки и загружается в функцию main() в testCompile.cpp. Глобальная переменная xyz инициализируется, чтобы указать 25 в somefunc.cpp, но я бы хотел, чтобы она указывала на 10, как и на main(). Другими словами, утверждение в main() должно быть успешным.

Я пробовал несколько различных способов решить эту проблему. Функция ChangeGlobal() пытается (безуспешно) выполнить это обновлениеGlobalMapping(). Второй, более хакерский подход использует новую глобальную переменную, инициализированную соответствующим образом. Я могу использовать этот последний подход для работы над некоторыми типами глобальных переменных, но есть ли более элегантный подход, чем этот?

//————— 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(); 
Смежные вопросы