Я пытаюсь скомпилировать некоторые функции в существующей программе на 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());
}