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
).