从源文件到目标文件的整个流程

1
gcc hello.c
  1. 预处理(Prepressing)
  2. 编译(Compilation)
  3. 汇编(Assembly)
  4. 链接(Linking)

预处理(预编译)

1
2
gcc –E hello.c –o hello.i 或者
cpp hello.c > hello.i

主要用于删除/替换宏定义,处理 #include 指令,删除注释,添加行号,文件名标识便于调试,保留 #pragma 编译命令

编译

1
2
3
gcc –S hello.i –o hello.s  或者
cc1 hello.c(cc1可以完成预编译和编译)或者
gcc –S hello.c –o hello.s

完成词法分析,语法分析,语义分析,优化后生成汇编代码文件。

汇编

1
2
as hello.s –o hello.o 或者
gcc –c hello.c –o hello.o

一条汇编语言对应一条机器指令,汇编器要完成的任务很简单,将汇编指令翻译为机器指令就行了。(计算标号地址算么)

链接

1
2
例子:
$ld -static /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.1.3/crtbeginT.o -L/usr/lib/gcc/i486-linux-gnu/4.1.3 -L/usr/lib -L/lib hello.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/i486-linux-gnu/4.1.3/crtend.o /usr/lib/crtn.o

链接的主要内容就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确地衔接。

链接过程主要包括了地址和空间分配(Address and StorageAllocation)、符号决议(Symbol Resolution)和重定位(Relocation)等这些步骤

链接器在链接的时候,会根据你所引用的符号 foo,自动去相应的func.c模块查找foo的地址,然后将main.c模块中所有引用到foo的指令重新修正,让它们的目标地址为真正的foo函数的地址。这就是静态链接的最基本的过程和作用。(重定位)