程序编译与链接原理
- 预编译:处理#命令,但保留#pragma,删除注释。
- 编译:词法分析、语法分析、语义分析和优化,生成汇编代码。
- 汇编:将汇编代码翻译成机器码(AT&T,x86语法),打包为可重定位二进制目标文件,此文件不可执行。输出符号表。
- 链接:合并.o文件段,合并符号表,解析并符号重定向。
//以下为main文件
extern int gdata; //gdata *UND*代表需使用但未定义
int sum(int, int); //sum *UND*
int data = 20; //data .data
int main(){ //main .text
int a = gdata;
int b = data;
int ret = sum(a, b);
return 0;
}
//以下为sum文件
int gdata = 10; //gdata .data
int sum(int a, int b){ //sum_int_int .text
return a + b;
}
以上为.o文件中的部分符号注释
具体的.o文件的格式组成包括各种段
编译过程中不为符号分配地址,通过readelf可以观察到地址皆为0。虽然指令已经在编译阶段翻译好,但变量地址皆为0,需要在链接阶段补充,也因此.o文件无法执行。
链接
链接过程合并若干个.o文件的段合并:text段合并,data段合并...,以及符号表的合并。
-
符号表合并:检查符号表,所有对符号的引用(*UND*),都要找到该符号定义的地方,当然符号定义只能有一个,不可重定义,不可没有。最终符号解析成功。
-
符号解析成功后,在代码段中,为所有符号分配虚拟地址,并把这些地址写回指令中。这个过程叫做符号重定向。
可执行文件
链接产生可执行文件,可执行文件与二进制可重定向文件段格式几乎一致,但可执行文件中多了一个program headers段,这其中包含若干load项,比如.text,.data,这意味着这些load项要在代码执行时,加载如虚拟内存空间