1、首先了解一下编译器
Linux中c语言编译器gcc,它编译分为四个阶段:
阶段一:预处理
案例:hello.c文件
#include <stdio.h>
int main(){
printf("hello,world\n");
}
gcc hello.c -o hello --save-temps --verbose#--save-temps保存编译中间生成的文件,--verbose展示编译过程详细信息
此过程生成文件:hello.i,主要处理以#号开头的预处理指令。
gcc -E hello.c -o hello.i#可以直接执行此过程
阶段二:编译阶段
此阶段进行一系列词法分析、语法分析、语义分析等最后生成汇编代码
gcc -S hello.c -o hello.s
gcc -S hello.c -o hello.s -masm=intel -fno-asynchronous-unwind-tables#生成没有cfi宏的intel格式的汇编指令,cfi宏是调试时用的
生成的文件内容如下:
printf默认被替换成了puts是因为他们十分类似,gcc优化策略为了提高性能。
阶段三:汇编阶段
汇编指令向机器指令进行翻译,生成文件hello.o
gcc -c hello.c -o hello.o
gcc -c hello.s -o hello.o
此时的目标文件是一个可重定位文件,可以使用objdump命令来查看内容
objdump -sd hello.o -M intel
阶段四:链接阶段
默认使用动态链接,这一阶段将目标文件及其依赖库进行链接,生成可执行文件,主要包括地址和空间分配、符号绑定和重定位等操作。通过链接操作,对象文件的中无法确定的符号地址已经被修正为实际的符号地址,程序也就可以被加载到内存中正常执行了。
gcc hello.o -o hello -static #静态链接的可执行文件