《程序员的自我修养》第四章 静态编译


程序员的自我修养第三章,讲了elf文件的各个段的作用和属性,但是我感觉书面上的讲述可能并不能让我们理解这些段,所以我就不进行这章的总结了,我在这里推荐holk师傅的第三章的讲解,我觉得写的真的非常好,希望能对大家有所帮助

(19条消息) 《程序员的自我修养》学习心得——第三章 目标文件里有什么_hollk’s blog-CSDN博客

在第四章中,讲述的是代码经过编译器编译,在连接器和编译器之间发生的过程

1.链接

  当一个程序需要链接合并时,一个最简单的过程就是将输入的目标文件按照次序叠加起来,但是这样却会有很多问题,比如在输出的文件有很多的情况下,就可能会有数百个目标文件甚至上千个,而这些目标文件都有自己的各个段,直接合并会造成很多的空间浪费,这对于要求节约的我们明显是不允许的,所以就出现了如下的步骤

  相似段合并

  我们可以将相同性质的段合并到一起,例如.text合并到输出文件的.text段,然后是.data段等等,但是在第三章提到的.bss段在目标文件和可执行文件中,并不占用文件的空间,但是它在装载时占用地址空间,所以我们就需要分配这个虚拟空间(如.text和.data来说,它们在文件中和虚拟地址中都要分配空间,因为这俩者都存在,而对于.bss这样的段来说,分配空间的意义只局限于虚拟空间地址,事实上,我们这里谈到的空间分配只关注与虚拟的地址空间分配

  现在的链接器空间分配一般都采用一种叫俩步链接的方法:

    第一步 空间与地址分配,扫描所有的输入目标文件,获得各个段的长度,属性和位置,并且将符号定义和符号引用放到一个全局符号表,有链接器进行计算合并后的长度和位置

    第二步 符号解析与重定位, 根据上一步收集到的信息,读取输入文件的中段的数据,重定位信息,并且进行符号解析与重定位,调整代码中的地址等,这里我们要尤其关注重定位过程

这里我们可以看一下书上的例子

 这是将a.o和b.o链接成ab.o的前后地址分配情况,我们可以注意一下为什么链接器给ab的.text段分配到0x08048094这个段,因为在linux下,elf可执行的文件默认从地址0x08048000开始分配

(符号地址的确认:在第一步中,链接器已经将各个段在链接后的虚拟地址分配确定,在前面一步完成后,链接器就开始计算各个符号的虚拟地址,链接器会给每一个符号加上一个偏移量,是他们能调整到正确的虚拟地址,这里我们也可以自己计算看看,我就不计算了QAQ)

  符号解析与重定位

在完成了空间地址分配步骤后,链接器就进入了符号解析与重定位的步骤,

为什么要重定位?

比如当a.c使用了别的外部变量符号时,那编译器再将a.c编译成指令时,它将如何访问这些变量

 就比如这个程序,粗体就是外部变量,可以看到指令先预留了这俩变量的位置,这是一个假地址,编译器把真正的地址计算工作交给了链接器,链接器就根据之前获得的偏移去修正地址

  重定位表

  在elf文件中,有一个叫重定位表的结构专门用来保存这些与重定位相关的信息,重定位表往往是一个段或者多个段,它的结构也较为简单,是一个elf32_Rel结构的数组,定义如下:

这里我们可以提一下指令修正方法,在我们不考虑intel的段间远址寻址(太多了)唯一的区别就是绝对寻址和相对寻址。绝对寻址就是修正后的地址为该符号的实际地址,相对寻址就是修正后的地址为符号距离被修正位置的地址差(感兴趣的师傅可以翻阅一下书上的110页)

在链接过程中还有着许多的步骤,比如重复代码消除我就不一一列出来了

  全局构造与析构

  在linux系统下程序的入口是"_start",这个函数会和glibc链接成最终的可执行文件,但是有些场合,程序特定的操作必须在main函数前执行,有些需要在main后执行,这里就不得不提俩个elf文件的俩特殊的段

  .init :该段保存的是可执行指令,构成了进程的初始化代码,在mainl函数被调用前就会被安排执行

  .finni:该段保存的是进程终止代码,在main调用后安排执行

静态库链接

一个有意义的程序需要有输入输出,就需要使用操作系统提供的应用程序编程接口(API),我们知道,在一个c语言的运行库中,包含许多跟系统功能相关的代码,为了方便人们管理,这些不同功能的.o文件被使用"ar压缩程序压缩道一起,我们可以通过ar工具来进行查看

 但是这些文件并不是相互独立的,就比如printf代码,如果我们直接将文件和printf.o链接到一起,则会显示失败,是因为printf.o还依赖与其它的目标文件,而这些目标文件还依赖其它文件,我们可以想象一个树形图,许多文件链接起来构成了一个完整的printf代码,从而实现了代码的功能

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

以上这些是我觉得挺有意思的部分,如果感兴趣的师傅可以去看一下这本书,讲的真的挺不错,那么这一章就这么结束了

  

相关