预处理,编译,汇编,链接
- 预处理
gcc -E hello.cpp -o hello.i
- 编译
gcc -S hello.i -o hello.s
- 汇编
gcc -c hello.s -o hello.o
- 链接
ld
目标文件格式
- 目标文件分类
- 可重定位文件 .o文件
- 可执行文件
- 共享目标文件 .so文件
- 核心转储文件 coredump文件
- 目标文件分段
- text段(程序指令)
- .data段(已经初始化值的全局变量和局部静态变量)
- .bss段(未初始化的全局变量和局部静态变量),没有内容,不占空间,因为这些值默认都是0
- 文件格式查看
gcc -c hello.cpp
生成hello.o
objdump -h hello.o
查看各个段的大小,起始位置
objdump -d -s hello.o
查看汇编代码
readelf -h hello.o
查看文件的基本信息
readelf -S hello.o
查看文件的具体段的分布
readelf -s hello.o
查看文件的变量函数
- 强符号和弱符号
- 初始化了的全局变量是强符号
- 弱符号的使,通过 __attribute__((weak))指定此引用为弱引用,如果外部没有定义,可以链接出错,但是引用为空,如果外部有定义,正常运行,引用不为空,自己代码可以声明一个外部库的弱引用,如果为空,说明运行时没有外部库,可以执行自己另外的逻辑,达到一定的动态化
静态链接过程
- 将每个.o文件的相同的段放在一起并合并,并根据每个文件的符号定义和引用,建立一个全局符号表
- 对每个.o文件,
- 根据自己在合并之后的位置,更新自己的地址为原地址加现在在合并文件中的起始地址
- 读取文件的重定位表中的每一项
objdump -r a.o
,在全局符号表中查找,并进行重定位
动态链接过程
- 对于可共享的so文件,按照不同的段区分,数据段是每个个进程各自拥有一份,程序指令段需要编译此so的时候就编译为地址无关代码,
- so编译的具体过程是:凡是调用了本so外部的变量函数,都通过一个GOT表指针间接访问,而GOT表是此时未初始化的,而且GOT是放在数据段的
- Program装载这个so的时候,每个进程拥有自己的数据段和GOT,然后根据此时so的内存位置,填写GOT,此时Program调用的so的指令部分是多个进程共享的.但是指令访问数据函数的时候,会拿各自进程自己的GOT表,所以对数据的操作是各个进程独立的。