sum.cpp
int sum(int a, int b){
return a + b;
}
main.cpp
extern int gdata;
int sum(int, int);
int main(){
int a;
int b;
int ret = sum(a, b);
return 0;
}
现在对以上文件进行举例,介绍编译过程
预编译 编译 汇编 是分开执行,链接是将最后的源文件合并
预编译
gcc -E main.cpp -o main.i
处理#开头的命令
#pragma除外,因为都发生在链接阶段,需要保持到链接时期
#pragma lib //添加静态库,是发生在链接阶段的
#pragma link //指定程序入口,在链接阶段指定第一条指令地址
编译
gcc -S main.cpp -o main.i
生成汇编指令
g++ -o
汇编
生成二进制的可重定向文件
gcc -c main.cpp -o main.o
gcc -c sum.cpp -o sum.o
生成符号表
通过objdump -t 查看符号表
-
定义在其他文件的,还未链接的符号都是引用的,因此位置都是UND
-
l表示local,g表示全局,链接的时候连接器只能看到全局的
-
此时文件包含
-
elf文件头:文件的入口地址
-
.text
-
.data
-
'.bss
-
符号表
-
…
此时指令已经产生,但是没有地址
链接
所有的.o文件+静态库文件
步骤一:
所以的.o文件段合并
符号表合并后,进行符号解析
- 所以对符号的引用,要找到符号定义的地方,即原来符号的地址是UND
步骤二:
给所有符号分配虚拟地址,在指令中符号的地址都是000000,此时填写正确的地址
符号重定向
生成可执行文件
此时再查看,能够看到所有符号都有地址
相比于二进制可重定位文件,可执行文件还有一个program headers
有两个load,告诉系统运行程序时,将那些内容加入到内存段中,代码段
可执行的文件加载过程
虚拟地址做地址映射,触发页中断,分配物理内存。