LLVM - проблема связывания

Я пишу генератор кода LLVM для языка Timber, текущий компилятор испускает C-код. Моя проблема заключается в том, что мне нужно вызвать функции C из сгенерированных файлов LLVM, например, у компилятора есть сборщик мусора в реальном времени, и мне нужно вызвать функции для уведомления, когда новые объекты распределяются в куче. Я не знаю, как связать эти функции с моими сгенерированными файлами LLVM.

Генерация кода производится путем генерации .ll файлов, а затем вручную их компилирует.

Я пытаюсь вызвать внешнюю функцию из LLVM, но мне не повезло. В примерах, которые я нашел > , вызывается только стандартные функции C, такие как "puts" и "printf", но я хочу вызвать функцию "home". Я застрял.

Ответ 1

Скомпилируйте файлы сборки LLVM обычно с помощью llvm-as:

llvm-as *.ll

Скомпилируйте файлы биткода в файлы языка ассемблера .s:

llc *.bc

Включите их с помощью библиотеки времени выполнения:

gcc *.s runtime.c -o executable

Замените в реальных make файлах, общих библиотеках и т.д., если это необходимо. Вы получаете идею.

Ответ 2

Я предполагаю, что вы пишете преобразование LLVM, и хотите добавить вызовы к внешним функциям в преобразованный код. Если это не так, отредактируйте свой вопрос и укажите дополнительную информацию.

Прежде чем вы сможете вызывать внешнюю функцию из кода LLVM, вам нужно вставить для нее объявление. Например:

virtual bool runOnModule(Module &m) {
    Constant *log_func = m.getOrInsertFunction("log_func",
                                               Type::VoidTy,
                                               PointerType::getUnqual(Type::Int8Ty),
                                               Type::Int32Ty,
                                               Type::Int32Ty,
                                               NULL);
    ...
}

В приведенном выше коде объявлена ​​функция log_func, которая возвращает void и принимает три аргумента: указатель байтов (строка) и два 32-битных целых числа. getOrInsertFunction - это метод Module.

Чтобы на самом деле вызвать функцию, вам нужно вставить CallInst. Для этого существует несколько статических Create методов.

Ответ 3

Я интерпретирую ваш вопрос как "как мне реализовать библиотеку времени выполнения на C или С++ для моего языка, который скомпилирован в LLVM?"

Один из подходов, подробно описанный Джонатаном Тангом, преобразовать вывод вашего компилятора из LLVM IR в биткод в сборку и связать сборку с исходным кодом (или объектными файлами) с помощью vanilla gcc.

Альтернативным, возможно, более гибким подходом является использование llvm-gcc для компиляции самой среды выполнения в бит-код LLVM, а затем использовать llvm-ld для связывания битового кода с вашим компилятором с битовым кодом вашей среды выполнения. Затем этот биткод может быть повторно оптимизирован с помощью opt, преобразованный обратно в IR с помощью llvm-dis, интерпретируемый непосредственно с помощью lli (это будет, afaik, работает только если LLVM был создан против libffi) или скомпилирован для сборки с llc (а затем в нативный двоичный код с ванилью gcc).