llvm 编译c/c++ 文件步骤以及中间文件说明
在LLVM框架中编译C/C++程序时,整个过程分为多个阶段,每个阶段会生成不同的中间文件。以下是详细的步骤和中间文件说明:
1. 预处理(Preprocessing)
-
输入:.c/.cpp 源文件(如 hello.c)
-
输出:预处理后的文本文件(.i 或 .ii)
-
工具:
clang -E
-
作用:
- 展开宏、处理 #include、#define 等预处理指令。
- 删除注释,添加行号标记(#line)。
-
生成文件:
clang -E hello.c -o hello.i # C语言 clang -E hello.cpp -o hello.ii # C++
2. 编译到LLVM IR(前端)
-
输入:预处理后的 .i/.ii 文件
-
输出:LLVM中间表示(IR),文本格式(.ll)或二进制格式(.bc)
-
工具:
clang -S -emit-llvm
-
作用:
- 将C/C++代码转换为与硬件无关的LLVM IR。
- 进行初步优化(如内联、死代码删除)。
-
生成文件:
clang -S -emit-llvm hello.c -o hello.ll # 文本IR clang -c -emit-llvm hello.c -o hello.bc # 二进制IR
关键文件:
.ll:人类可读的IR文本(可通过 cat hello.ll 查看)。
.bc:二进制IR(更紧凑,适合进一步处理)。
3. IR优化(中端)
-
输入:.ll 或 .bc 文件
-
输出:优化后的IR文件
-
工具:opt
-
作用:
- 执行多种优化(如循环展开、常量传播、函数内联)。
- 优化级别通过 -O1/-O2/-O3 控制。
-
示例命令:
opt -O2 hello.ll -o hello_opt.ll # 文本IR优化 opt -O2 hello.bc -o hello_opt.bc # 二进制IR优化
4. 代码生成(后端)
-
输入:优化后的 .ll 或 .bc 文件
-
输出:目标架构的汇编代码(.s)
-
工具:llc
-
作用:
- 将LLVM IR转换为特定架构(如x86、ARM)的汇编代码。
-
生成文件:
llc hello_opt.ll -o hello.s # 生成x86汇编 llc -march=arm hello_opt.ll -o hello.s # 生成ARM汇编
5. 汇编(Assembly)
-
输入:汇编文件 .s
-
输出:目标文件 .o(二进制机器码)
-
工具:汇编器(as 或LLVM集成工具)
-
作用:
- 将汇编代码转换为机器指令,生成可重定位的目标文件。
-
生成文件:
clang -c hello.s -o hello.o # 使用clang调用汇编器 as hello.s -o hello.o # 直接使用GNU汇编器
6. 链接(Linking)
-
输入:一个或多个 .o 文件 + 库文件(.a/.so)
-
输出:可执行文件(如 a.out)或动态库(.so/.dll)
-
工具:链接器(ld 或 clang 驱动)
-
作用:
- 合并目标文件,解析符号引用,处理重定位。
-
示例命令:
clang hello.o -o hello # 生成可执行文件 clang -shared hello.o -o libhello.so # 生成动态库
完整流程图示
graph TB
A[hello.c] -->|Preprocess| B[hello.i]
B -->|Compile to IR| C[hello.ll/.bc]
C -->|Optimize| D[hello_opt.ll/.bc]
D -->|Codegen| E[hello.s]
E -->|Assemble| F[hello.o]
F -->|Link| G[a.out or libhello.so]
键中间文件总结
文件扩展名 | 阶段 | 格式 | 作用 |
---|---|---|---|
.i/.ii | 预处理 | 文本 | 展开宏和头文件后的源代码 |
.ll IR生成 | 文本 | 人类可读的LLVM中间代码 | |
.bc | IR生成 | 二进制 | 紧凑的LLVM IR(Bitcode) |
.s | 代码生成(后端) | 文本 | 目标架构的汇编代码 |
.o 汇编 | 二进制 | 可重定位的机器码 | 目标文件 |
直接生成命令示例
LLVM工具链允许跳过中间步骤,直接生成最终文件:
从C源码直接生成可执行文件(隐式完成所有步骤)
clang hello.c -o hello
从C源码生成目标文件(跳过IR和汇编的显式步骤)
clang -c hello.c -o hello.o
调试与分析工具
查看IR:llvm-dis hello.bc -o hello.ll(反汇编二进制IR)
查看汇编:objdump -d hello.o
查看预处理结果:clang -E -dM hello.c(输出所有宏定义)
通过理解这些步骤和文件,可以更灵活地控制编译过程,例如手动优化IR或分析汇编代码。