如何使clang编译为llvm IR


150

我希望clang将我的C/C++代码编译为LLVM字节码,而不是二进制可执行文件。我该如何实现?如果我得到了LLVM字节码,该如何将其进一步编译为二进制可执行文件。

基本上,我想LLVM在编译为二进制可执行文件之前将自己的代码添加到字节码中。


我猜它被称为LLVM位代码
PreeJackie

Answers:


204

给定一些C / C ++文件foo.c

> clang -S -emit-llvm foo.c

产生foo.ll哪个是LLVM IR文件。

-emit-llvm选项也可以直接传递给编译器前端,而不是通过以下方式传递给驱动程序-cc1

> clang -cc1 foo.c -emit-llvm

foo.ll用IR 产生。-cc1添加了一些很酷的选项,例如-ast-print。查看-cc1 --help更多详细信息。


要在组装时进一步编译LLVM IR,请使用以下llc工具:

> llc foo.ll

产生foo.s装配体(默认为您在其上运行的机器体系结构)。llc是LLVM工具之一- 这是其文档


7
-S在这里做什么?
meawoppl 2014年

13
@meawoppl:-S在gcc中表示发出文本汇编而不是汇编二进制
Eli Bendersky 2014年

啊哈 我很难在文档中找到关于它的任何内容。可以安全地假设clang镜像gcc标志结构中有许多标志?
meawoppl 2014年

@EliBendersky您知道如何将多个.c和.h文件编译为一个人类可读的IR,以便可以使用“ lli theIrFile”运行IR吗?谢谢
2014年

1
@cache:将每个文件编译成自己的IR文件,然后使用LLVM链接器进行合并
Eli Bendersky

20

clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc

9
我建议保持扩展名的含义不变。IOW .o应该引用二进制目标文件,.s程序集文件,以及其他(按约定.ll)到LLVM IR文件。否则很容易混淆。Clang / LLVM现在没有自己的二进制对象链接器(尽管有一个链接正在编写中)。LLVM的链接llvm-ld只是加入一些IR文件合并成一个
礼Bendersky

1
@EliBendersky:对于文件扩展名,您是正确的-如果.bc使用clang前端实际上会做正确的事;还有,请记住,llvm-ld可以作为前端的系统工具链行事,即我以前的答案使用llvm-ld -native应该按预期工作....
克里斯托夫

1
@rickfoosusa:对我有用- foo.bc是LLVM位代码文件
Christoph

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 = also-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使用特定的链接程序,请在计算机上某个特殊目录“ fakebin”中创建指向该链接程序“ ld”的符号链接,并添加选项

-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”有什么区别吗?
Peter Teoh

@PeterTeoh我使用-S选项(在第2步中),我指定要在LLVM IR中生成输出。基本上,将所有* .ll文件放入一个文件中。我这样做是为了检查最佳化真正改变的代码,即single.lloptimised.ll现在看起来应该不同(代码明智),你也可以显示报告,看看是否有在所有任何区别。
Kiko Fernandez

-basicaaa是错误的标志,-basicaa必须改用。
anton_rh

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.