Как заставить clang компилироваться в llvm IR

150

Я хочу, чтобы clang компилировал мой C/C++код в LLVMбайт-код, а не в двоичный исполняемый файл. Как я могу этого достичь? И если я получу LLVMбайт-код, как я могу взять его для дальнейшей компиляции в двоичный исполняемый файл.

По сути, я хочу добавить свой собственный код в LLVMбайт-код перед компиляцией в двоичный исполняемый файл.

вещий
источник
Я предполагаю, что это называется битовым
кодом

Ответы:

204

Учитывая некоторый файл C / C ++ foo.c:

> clang -S -emit-llvm foo.c

Создает foo.llфайл IR LLVM.

-emit-llvmВариант также может быть передан в компилятор переднего конца непосредственно, а не водитель с помощью -cc1:

> clang -cc1 foo.c -emit-llvm

Производит foo.llс ИК. -cc1добавляет несколько интересных вариантов, как -ast-print. Проверьте -cc1 --helpдля более подробной информации.


Чтобы скомпилировать LLVM IR далее для сборки, используйте llcинструмент:

> llc foo.ll

Производит foo.sсо сборкой (в зависимости от архитектуры машины, на которой вы его запускаете). llcявляется одним из инструментов LLVM - вот его документация .

Эли Бендерский
источник
7
Что здесь делать?
meawoppl
13
@meawoppl: -S как в gcc говорит, что испускает текстовую сборку, а не собранный двоичный файл
Эли Бендерский
Ahha. Мне было трудно найти что-нибудь в документации по этому поводу. Можно с уверенностью предположить, что много флагов в структуре clang mirror gcc flag?
Meawoppl
@EliBendersky Знаете ли вы, как скомпилировать несколько файлов .c и .h в один читаемый человеком IR, чтобы я мог запустить IR, используя 'lli theIrFile'? Спасибо
кеш
1
@cache: скомпилируйте каждый в свой собственный файл IR, а затем используйте компоновщик LLVM для объединения
Эли Бендерский,
20

использование

clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc
Christoph
источник
9
Я бы рекомендовал сохранить значения расширений без изменений. IOW, .oдолжен ссылаться на двоичные объектные файлы, .sна файлы сборки и что-то еще (по соглашению .ll) на IR-файлы LLVM. В противном случае легко запутаться. Clang / LLVM теперь не имеет своего собственного компоновщика для бинарных объектов (хотя один находится в разработке). Линкер LLVM llvm-ldпросто объединяет несколько файлов IR в один
Эли Бендерски,
1
@EliBendersky: вы правы в том, что касается расширений файлов - и интерфейс Clang действительно делает правильные вещи, если .bcиспользуется; Кроме того, имейте в виду, что он llvm-ldможет выступать в качестве внешнего интерфейса для системного инструментария, т.е. мой предыдущий ответ с использованием llvm-ld -nativeдолжен работать, как и ожидалось ....
Кристоф
1
@rickfoosusa: работает для меня - foo.bcэто файл битового кода LLVM
Кристоф
1
Работы для меня clang -emit-llvm -o test.bc -c test.c && file test.bc: test.bc: LLVM IR bitcode.
ntc2
18

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

Вместо этого вы хотите скомпилировать с оптимизацией времени соединения

clang -flto -c program1.c -o program1.o
clang -flto -c program2.c -o program2.o

и для последнего шага связывания добавьте аргумент -Wl, -plugin-opt = Кроме того-emit-llvm

clang -flto -Wl,-plugin-opt=also-emit-llvm program1.o program2.o -o program

Это дает вам как скомпилированную программу, так и соответствующий ей битовый код (program.bc). Затем вы можете изменить program.bc любым удобным вам способом и перекомпилировать измененную программу в любое время, выполнив

clang program.bc -o program

хотя имейте в виду, что на этом шаге необходимо снова включить все необходимые флаги компоновщика (для внешних библиотек и т. д.).

Обратите внимание, что вам нужно использовать золотой компоновщик, чтобы это работало. Если вы хотите заставить clang использовать определенный компоновщик, создайте символическую ссылку на этот компоновщик с именем «ld» в специальной директории с именем «fakebin» где-нибудь на вашем компьютере и добавьте параметр

-B/home/jeremy/fakebin

к любым шагам связывания выше.

Джереми Салвен
источник
13

Если у вас есть несколько файлов и вы не хотите вводить каждый файл, я бы порекомендовал вам выполнить следующие простые шаги (я использую, clang-3.8но вы можете использовать любую другую версию):

  1. создать все .llфайлы

    clang-3.8 -S -emit-llvm *.c
  2. связать их в один

    llvm-link-3.8 -S -v -o single.ll *.ll
  3. (Необязательно) Оптимизируйте свой код (возможно, анализ псевдонимов)

    opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
  4. Создать сборку (создает optimised.sфайл)

    llc-3.8 optimised.ll
  5. Создать исполняемый файл (по имени a.out)

    clang-3.8 optimised.s
Кико Фернандес
источник
Ваше решение совершенно уникально: вы использовали «-S» вместо того, чтобы просто оставить его как двоичный вывод. Есть ли разница между "-S" и "-S"?
Питер Тео
@PeterTeoh Я использую -Sопцию (в шаге 2), я указываю, что я хотел бы произвести вывод в LLVM IR. По сути, поместите все файлы * .ll в один. Я делаю это, чтобы убедиться, что оптимизация действительно меняет код, то есть single.llи optimised.llтеперь должна выглядеть по-другому (с точки зрения кода), и вы также можете показать отчет, чтобы увидеть, есть ли какая-либо разница.
Кико Фернандес
-basicaaaнеправильный флаг, -basicaaдолжен использоваться вместо
anton_rh