如何使clang编译为llvm IR

如何使clang编译为llvm IR,c,llvm,clang,C,Llvm,Clang,我希望clang将我的C/C++代码编译成LLVM字节码,而不是二进制可执行文件。我怎样才能做到这一点?如果我得到LLVMbytecode,我如何将它进一步编译成二进制可执行文件 基本上,在编译成二进制可执行文件之前,我想在LLVM字节码中添加一些我自己的代码。你读了吗?您可能正在寻找-emit llvm给定一些C/C++文件foo.C: > clang -S -emit-llvm foo.c 生成foo.ll,它是一个LLVM IR文件 -emit llvm选项也可以通过-cc1直接传

我希望clang将我的
C/C++
代码编译成
LLVM
字节码,而不是二进制可执行文件。我怎样才能做到这一点?如果我得到
LLVM
bytecode,我如何将它进一步编译成二进制可执行文件


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

你读了吗?您可能正在寻找
-emit llvm

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

> clang -S -emit-llvm foo.c
生成
foo.ll
,它是一个LLVM IR文件

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

> clang -cc1 foo.c -emit-llvm
使用IR生成
foo.ll
-cc1
添加了一些很酷的选项,如
-ast print
。查看
-cc1--help
了解更多详细信息


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

> llc foo.ll
使用程序集生成
foo.s
(默认为运行它的机器体系结构)
llc
是LLVM工具之一-。

使用

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

如果您有多个源文件,您可能实际上希望使用链接时间优化为整个程序输出一个位代码文件。给出的其他答案将导致每个源文件都有一个位代码文件

相反,您希望使用链接时优化进行编译

clang -flto -c program1.c -o program1.o
clang -flto -c program2.c -o program2.o
对于最后一个链接步骤,添加参数-Wl,-plugin opt=allomit 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

如果您有多个文件并且不想键入每个文件,我建议您遵循以下简单步骤(我使用的是
clang-3.8
,但您可以使用任何其他版本):

  • 生成所有
    .ll
    文件

    clang-3.8 -S -emit-llvm *.c
    
  • 将它们链接成一个

    llvm-link-3.8 -S -v -o single.ll *.ll
    
  • (可选)优化代码(可能进行一些别名分析)

  • 生成程序集(生成
    优化的.s
    文件)

  • 创建可执行文件(名为
    a.out


  • 我建议保持扩展的含义不变。依惯例,
    .o
    应该引用二进制对象文件,
    .s
    应该引用程序集文件,而其他东西(按照惯例,
    .ll
    )应该引用LLVM IR文件。否则很容易混淆。Clang/LLVM现在没有自己的二进制对象链接器(尽管一个正在开发中)。LLVM链接器
    LLVM ld
    只是将几个IR文件连接到one@EliBendersky:关于文件扩展名,您是正确的-如果使用
    .bc
    ,那么clang前端实际上做了正确的事情;另外,请记住,
    llvm ld
    可以充当系统工具链的前端,ie我以前使用
    llvm ld-native
    的答案应该能像预期的那样工作。@rickfoossa:works for me-
    foo.bc
    是一个llvm位代码文件works for me:
    clang-emit llvm-o test-o test.bc-c test.c&&file test.bc:test.bc:llvm IR bitcode
    。-S在这里做什么?@meawppl:-S像在gcc中说emit文本程序集而不是我叫比纳里亚哈。我很难在文件中找到任何关于它的东西。可以安全地假设clang mirror gcc flag结构中有许多标志?@EliBendersky您知道如何将多个.c和.h文件编译成一个人类可读的IR,以便我可以使用“lli theIrFile”运行IR吗?Thanks@cache:将每个文件编译成自己的IR文件,然后使用LLVM链接器组合您的解决方案非常独特:您使用“-S”而不是将其作为二进制输出。有“-S”和没有“-S”之间有什么区别吗?@PeterTeoh我使用
    -S
    选项(在步骤2中),我指定要在LLVM IR中生成输出。基本上,将所有*.ll文件放在一个文件中。我这样做是为了检查优化是否真的改变了代码,即
    single.ll
    optimized.ll
    现在看起来应该不同了(代码方面),您还可以显示报告以查看是否有任何差异。
    -basicaaa
    是一个错误的标志,
    -basicaa
    必须改用。我猜它被称为LLVM位码
    opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
    
    llc-3.8 optimised.ll
    
    clang-3.8 optimised.s