Программа, скомпилированная LLVM JIT, не может найти внешние функции

Моя программа, которая JIT-компилирует модуль LLVM IR и вызывает определенную в нем функцию foo, дает сбой во время выполнения, если foo использует функцию, определенную извне:

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

Моя программа:

// 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;
}

Вот как я строю свою программу:

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

Выход:

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

Он завершается с аналогичной ошибкой каждый раз, когда я пытаюсь использовать внешне определенную функцию, которой нет в стандартной библиотеке C++ (например, printf, malloc и free не проблема). Что я делаю не так?


person Jared Hoberock    schedule 16.01.2014    source источник


Ответы (2)


Убедитесь, что glutInit был связан с a.out. Если ваш хост-код (вещь, выполняющая JIT) не вызывал его, он мог быть заблокирован компоновщиком. Если это так, вы должны добавить к нему фиктивную ссылку или использовать скрипты / флаги компоновщика.

person Eli Bendersky    schedule 16.01.2014
comment
Спасибо, распечатки адреса glutInit достаточно, чтобы выполнить JIT успешно, поэтому похоже, что компоновщик отбрасывает символ. Я думал, что флага -rdynamic достаточно, чтобы сохранить символы без ссылок? - person Jared Hoberock; 17.01.2014

Добавление параметра командной строки -Wl,-no-as-needed непосредственно перед -lglut предотвратит удаление компоновщиком библиотеки glut, которая, по его мнению, в противном случае не нужна:

$ g++ -rdynamic foo2.cpp `llvm-config --cxxflags` `llvm-config --libs` `llvm-config --ldflags` -Wl,-no-as-needed -lglut
person Jared Hoberock    schedule 16.01.2014