【读书笔记】程序员的自我修养总结(四)
标签: 【编程开发】
声明:引用请注明出处http://blog.csdn.net/lg1259156776/
说明:这是程序员的自我修养一书的读书总结,随着阅读的推进,逐步增加内容。
链接过程中空间和地址分配
可执行文件中的代码段和数据段都是由输入目标中合并而来,链接器如何将各个段合并到输出文件并分配输出文件中的空间的呢?
分配方法
方法一:
直接按序叠加,obj 1 在obj 0的下面,就这样叠在一起。非常简单,但是问题是obj中都用自己的.text,.data段等,组合在输出的可执行文件中会造成一个问题:因为段的组织要求有一定的地址和空间对齐,比如x86的硬件,段的装载和空间的对齐单位是页,即4096字节,也就说即使某个段只有一个字节,它也要在内存中占用4096个字节,造成大量的内存空间碎片。
方法二:
相似段合并,即将所有输入文件的.text段等全都输出合并到输出文件的.text段,以此类推。
地址和空间
链接器为目标文件分配地址和空间,这里的地址和空间,有两个含义:第一个是在输出的可执行文件中的空间;第二个是在装载后的虚拟地址中的虚拟地址空间。对于有实际数据的段,比如.text,.data来说,它们在文件中和虚拟地址中都要分配空间,因为它们在两者中都存在;而对于.bss这样的段来说,分配空间的意义只局限于虚拟地址空间,因为它在文件中并没有内容。大多数时候,空间分配都只关注虚拟地址空间的分配,而可执行文件本身的空间分配与链接过程关系并不大。
两步链接
step 1 : 空间与地址的分配
扫描所有输入目标文件,并且获得各个段的长度,属性和位置,并且输入目标文件中的符号表中的所有符号定义和符号引用收集起来,统一放到一个全局符号表,获得所有输入目标文件的段长度,并且将它们合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系。
step 2: 符号解析与重定位
使用step 1中统计的信息,读取输入文件中段的数据,重定位信息,并进行符号解析与重定位,调整代码中的地址等。
在cmd中利用MinGW配置的gcc编译器等工具下,在windows上进行编译生成对应的目标文件,然后链接生成对应的可执行文件,通过objdump来查看链接前后地址的分配情况,可以发现链接前后的程序中所使用的地址已经是程序在进程中的虚拟地址,VMA,virtual memory address,而LMA,load memory address,加载地址,正常情况下两者一致,但有些嵌入式系统中试用了ROM的系统时,LMA和VMA可能是不相同的。经测试windows下是相同的。我们所关心的是VMA和size,而file off是文件偏移,一般可忽略不管。
需要说明的是:链接之前,所有的obj文件的VMA都是0,等到链接之后,可执行文件中的各个段都被分配到了相应的虚拟地址,因此VMA不再为0。
又有一个问题是:为什么链接器所分配的空间.text不是从0地址空间分配的?这涉及到操作系统的进程虚拟地址空间分配的规则,在linux下,ELF可执行文件默认地址是从0x0848000开始分配的。
符号地址的确定
在step 1中扫描和空间分配阶段,输入文件的各个段在连接后的虚拟地址就已经确定了,然后开始计算各个符号的虚拟地址,在段内相对位置是固定的,所以各个符号的地址也就是确定了。
2015-10-27 读书笔记 张朋艺