Question

My program which JIT compiles a LLVM IR module and calls a function foo defined therein fails at runtime if foo uses an externally-defined function:

LLVM ERROR: Program used external function 'glutInit' which could not be resolved!

My program:

// foo1.cpp
#include <GL/glut.h>

extern "C" void foo()
{
  glutInit(0,0);
}

// foo2.cpp
#include <iostream>
#include <fstream>
#include <string>

#include <llvm/Support/raw_ostream.h>
#include <llvm/LLVMContext.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/IRReader.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/ExecutionEngine/JIT.h>
#include <llvm/ExecutionEngine/RuntimeDyld.h>

int main(int argc, char **argv)
{
  using namespace llvm;
  InitializeNativeTarget();

  LLVMContext context;
  SMDiagnostic error;

  std::ifstream ir_file("foo1.s");
  std::string ir((std::istreambuf_iterator<char>(ir_file)),
                 (std::istreambuf_iterator<char>()));

  Module *m = ParseIR(MemoryBuffer::getMemBuffer(StringRef(ir)), error, context);
  if(!m)
  {
    error.print(argv[0], errs());
  }

  ExecutionEngine *ee = ExecutionEngine::create(m);

  Function *func = ee->FindFunctionNamed("foo");
  if(func == 0)
  {
    std::cerr << "Couldn't find Function foo" << std::endl;
    std::exit(-1);
  }

  typedef void (*fcn_ptr)();
  fcn_ptr foo = reinterpret_cast<fcn_ptr>(ee->getPointerToFunction(func));
  foo();
  delete ee;

  return 0;
}

Here's how I build my program:

$ clang -S -emit-llvm foo1.cpp
$ g++ -rdynamic foo2.cpp `llvm-config --cxxflags` `llvm-config --libs` `llvm-config --ldflags` -lglut

The output:

$ ./a.out 
LLVM ERROR: Program used external function 'glutInit' which could not be resolved!

It fails with a similar error any time I try to use an externally-defined function which is not in the C++ standard library (e.g., printf, malloc, & free are no problem). What am I doing wrong?

Was it helpful?

Solution

Make sure that glutInit was linked into a.out. If your host code (the thing executing the JIT) didn't call it, it could have been nixed by the linker. If that's the case, you have to add a dummy reference to it or use linker scripts / flags.

OTHER TIPS

Adding the command line option -Wl,-no-as-needed immediately before -lglut will prevent the linker from dropping the glut library, which it otherwise thinks is not needed:

$ g++ -rdynamic foo2.cpp `llvm-config --cxxflags` `llvm-config --libs` `llvm-config --ldflags` -Wl,-no-as-needed -lglut
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top