这篇笔记对比一下可执行目标文件和可执行目标的3个区别。下图分别是可重定位目标文件和可执行目标文件各段结构。
1.1 可执行目标文件和可重定位目标文件的3个区别
区别1:可执行目标文件的rel.text和.rel.data消失了
链接器将.o中.text和.data节整合到一起时,会对整合后的.text和.data进行重定位,.text和.data节重定位时需要依赖.rel.text和.rel.data中的信息,一旦重定位结束后,这两个节的使命就完成了,所以可执行目标文件中不存在rel.text和rel.data节。
区别2:多出了init节
init节的作用:init节会初始程序的堆栈。在编译时候,如果加上-v查看详细的编译过程(前边笔记中使用过-v选项),就会看到如下信息。
collect2 //链接程序
-dynamic-linker /lib64/ld-linux-x86-64.so.2 //动态链接器
crt1.o crti.o crtbegin.o //启动代码
ccyIcm4A.o //自己程序的.o
-lc //libc,常用c函数库——c标准库的子库
crtend.o crtn.o //程序运行结束时的扫尾代码
区别3:可执行目标文件增加了段头部表
段头部表的作用:用来辅助加载程序。当程序加载到内存时,需要将硬盘上的可执行目标文件,搬到“运行地址(虚拟内存的地址0x08400XXXX)”所指定的内存位置,段头部表中的作用就是用来辅助加载程序的。
1.2 总结下可执行目标文件的ELF格式
通过以上的对比,将可执行目标文件的格式分为如下图所示的节,符号表和调试信息,可读可写存储段和只读存储段。
符号表和调试信息:程序正常运行时,这5个节中的信息不会被加载到内存中,只有调试时候,才会被加载。
可读可写存储段(静态数据段):bss和data段的内存可以被修改,.data存放初始化的全局变量和static静态变量;.bss存放未初始化的静态和全局变量。之所以成为静态存储段,是因为在编译时候,就对.data/.bss的空间进行了划分,并不是程序运行起来后才被安排,所以称为静态数据段。
只读存储段(代码段):这些空间只能读不能写,.radata存放只读常量数据;.text存放代码段。