Анализ и изменение кода LLVM IR
Я хочу прочитать (проанализировать) код LLVM IR (который сохраняется в текстовом файле) и добавить к нему некоторый мой собственный код. Мне нужен пример этого, то есть, как это делается, используя библиотеки, предоставленные LLVM для этой цели. Так что в основном я хочу читать в ИК-коде из текстового файла в память (возможно, библиотека LLVM представляет его в форме AST, я не знаю), вносите изменения, например добавляя еще несколько узлов в AST, а затем, наконец, пишите вернуть AST в текстовый файл IR.
Хотя мне нужно как читать, так и изменять IR-код, я был бы очень признателен, если бы кто-то мог предоставить или передать мне какой-то пример, который просто читал (анализирует) его.
Ответы
Ответ 1
Во-первых, чтобы устранить очевидное недоразумение: LLVM - это среда для управления кодом в формате IR. Нет АСТ в поле зрения (*) - вы читаете IR, трансформируете/манипулируете/анализируете его, и вы пишете IR назад.
Чтение IR очень просто:
int main(int argc, char** argv)
{
if (argc < 2) {
errs() << "Expected an argument - IR file name\n";
exit(1);
}
LLVMContext &Context = getGlobalContext();
SMDiagnostic Err;
Module *Mod = ParseIRFile(argv[1], Err, Context);
if (!Mod) {
Err.print(argv[0], errs());
return 1;
}
[...]
}
Этот код принимает имя файла. Это должен быть IR файл LLVM (текстовый). Затем он анализирует его на Module
, который представляет собой модуль IR в внутреннем формате LLVM в памяти. Затем это можно манипулировать с помощью различных пропусков, которые LLVM имеет или вы добавляете самостоятельно. Взгляните на некоторые примеры в базе кода LLVM (например, lib/Transforms/Hello/Hello.cpp
) и прочитайте это - http://llvm.org/docs/WritingAnLLVMPass.html.
Прыгать IR обратно в файл еще проще. Класс Module
просто записывается в поток:
some_stream << *Mod;
Что это.
Теперь, если у вас есть какие-то конкретные вопросы о конкретных изменениях, которые вы хотите сделать для IR-кода, вы должны действительно спросить что-то более целенаправленное. Надеюсь, этот ответ покажет вам, как анализировать ИК-сигналы и записывать их обратно.
(*) IR не имеет представления АСТ внутри LLVM, потому что это простой ассемблерный язык. Если вы переходите на один уровень вверх, на C или С++, вы можете использовать Clang для разбора в AST, а затем выполнять манипуляции на уровне AST. Затем Кланг знает, как производить LLVM IR из своего АСТ. Однако вам нужно начинать с C/С++ здесь, а не LLVM IR. Если LLVM IR вам все равно, забудьте об AST.
Ответ 2
Это обычно делается путем реализации LLVM pass/transform. Таким образом, вам не нужно анализировать IR вообще, потому что LLVM сделает это за вас, и вы будете работать с OO-ориентированным представлением IR в памяти.
Это является точкой входа для записи пропуска LLVM. Затем вы можете посмотреть любой из уже реализованных стандартных проходов, которые поставляются в комплекте с LLVM (посмотрите lib/Transforms).
Ответ 3
Самый простой способ сделать это - посмотреть на один из существующих инструментов и украсть у него код. В этом случае вы можете посмотреть источник для llc. В качестве входных данных он может принимать либо биткод, либо файл .ll. Вы можете изменить входной файл любым способом, а затем записать файл, используя что-то похожее на код в llvm-dis, если вы хотите получить текстовый файл.
Ответ 4
Инструмент Opt принимает llvm IR-код, прогоняет его, а затем выплескивает преобразованный IRI IR с другой стороны.
Самый простой способ начать взлом - lib\Transforms\Hello\Hello.cpp. Взломайте его, запустите опцию с исходным файлом в качестве ввода, проверьте вывод.
Кроме того, документы для написания пропусков действительно неплохие.
Ответ 5
Как упоминалось выше, лучший способ написать пропуск. Но если вы хотите просто перебирать инструкции и делать что-то с LLVM, предоставляемым классом InstVisitor. Это класс, который реализует шаблон посетителя для инструкций. Это очень просто для пользователя, поэтому, если вы хотите не узнать, как реализовать пропуск, вы можете прибегнуть к этому.