Using Global Variables in MCJIT

Hi folks,
I’m trying to JIT compile some functions in an existing C/C++ program at runtime, but I’m running into some trouble with global variable initialization. Specifically, the approach I’ve taken is to use Clang to precompile the program into IR bitcode modules in addition to the executable. At runtime, the program loads the modules, transforms them (program specialization), compiles and executes them. As it turns out, I have some global variables that get initialized and modified during execution of the “host” program. Currently, these globals are also getting initialized in the JIT compiled code, whereas I’d like them to be mapped to the host global variables instead. Can someone help me with this?

A small repro is excerpted below. Full source code is in the attached zip file. The file somefunc.cpp gets precompiled during build, and is loaded in the main() function in testCompile.cpp. The global variable xyz is initialized to point to 25 in somefunc.cpp, but I’d like it to point to 10 as in main() instead. In other words, the assertion in main() should succeed.

I tried a few different ways to solve this problem. The ChangeGlobal() function attempts (unsuccessfully) to achieve this updateGlobalMapping(). The second, more hacky approach uses a new global variable initialized appropriately. I can get this latter approach to work for some types of globals, but is there a more elegant approach than this?

Cheers,
Navneet Potti

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

repro.zip (2.39 KB)

Hi Naveet,

Sorry about the delayed reply. Your repro case is currently passing for me on MacOSX - are you still seeing this issue?

Cheers,
Lang.