ELF文件结构
File Header |
.text section |
.data section |
.bss section |
. . . |
- 目标文件中的内容:编译后的机器指令代码、数据、链接时所须耍的一些信息(比如符号表、调试信息、字符串等)。
- 一般将这些信息按不同的属性,以“节”(Section ) 的形式存储,有时候也叫“段”(Segment ),它们都表示一个一定长度的区域,各个section只在ELF的链接和装载的时候有区别。
- 文件头(File Header) : 描述了整个文件的文件属性,包括文件是否可执行、是静态链接还是动态链接及入口地址(如果是吋执行文件)、目标硬件、目标操作系统等信息,文件头还包括一个段表(Section Header Table), 段表其实是一个描述文件中各个段的数组。段表描述了文件中各个段在文件中的偏移位置及段的属性等.从段表里面可以得到每个段的所有信息。
- 代码段(Code Section):存放源代码编译后的机器指令。代码段常见的名字有“.code ” 或“.text ”;
- 数据段(Data Section):存放全局变帚和局部静态变量数据。数据段的一般名字都叫“.data”
- 一般C语言的编译后执行语句都编译成机器代码.保存在.text 段;已初始化的全局变最和局部静态变量都保存在.data段;未初始化的全局变景和局部静态变量一般放在一个叫“.bss” 的段里.
- .bss段(Block Started by Symbol) : 未初始化的全局变量和局部静态变量默认值都为0, 本来它们也可以被放在.data 段的,但是因为它们都是0, 所以为它们在.data 段分配空间并且存放数据0是没有必要的。程序运行的时候它们的确是要占内存空间的,并且可执行文件必须记录所有未初始化的全局变量和局部静态变量的大小总和,记为.bss。所以.bss 段只是为未初始化的全局变量和局部静态变量预留位置而已,它并没有内容,所以它在文件中也不占据空间。
为什么要把程序和指令分开?
- 可以防止指令被改写。当程序被装载后,数据和指令分别被映射到两个虚存区域。由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写和只读。
- 可以提高cache命中率。对于现代的CPU 来说,它们有着极为强人的缓存(Cache ) 体系。由于缓存在现代的计算机中地位非常重要,所以程序必须尽量提高缓存的命中率。指令区和数据区的分离有利于提高程序的局部性。现代CPU 的缓存一般都被设计成数据缓存和指令缓存分离,所以程序的指令和数据被分开存放对CPU的缓存命中率提高有好处。
- 可以实现指令共享(最重要的原因)。当系统中运行着多个该程序的副本时,它们的指令都是一样的,所以内存中只须要保存一份改程序的指令部分。对于指令这种只读的区域来说是这样,对于其他的只读数据也一样,比如很多程序里面带有的图标、图片、文本等资源也是属于可以共享的。当然每个副本进程的数据区域是不一样的,它们是进程私有的。
链接的接口----符号
链接过程的本质就是要把多个不同的目标文件之间相互“粘” 到一起,为了使不同目标文件之间能够相互粘合,这些目标文件之间必须有固定的规则才行. 在链接中,目标文件之间相互拼合实际上是目标文件之间对地址的引用,即对函数和变景的地址的引用。比如目标文件B要用到了目标文件A 中的函数“foo”,那么我们就称目标文件A定义( Define )了函数“foo”,称目标文件B引用(Reference) 了目标文件A 中的函数“foo”。这两个概念也同样适用于变最。每个函数或变最都有自己独特的名字,才能避免链接过程中不同变量和函数之间的混淆。在链接中,我们将函数和变量统称为符号(Symbol ), 函数名或变最名就是符号名(Symbol Name )。
我们可以将符号看作是链接中的粘合剂,整个链接过程正是基于符号才能够正确完成。链接过程屮很关键的一部分就是符号的管理. 每一个目标文件都会有一个相应的符号表(Symbol Table), 这个表里面记录了目标文件中所用到的所有符号。每个定义的符号有一个对应的值,叫做符号值(Symbol Value), 对于变量和函数来说,符号值就是它们的地址。除了函数和变量之外,还存在其他几种常用到的符号。我们将符号表中所有的符号进行分类. 它们冇可能足下面这些类型中的一种:
- 定义在本目标文件的全局符号,可以被其他目标文件引用。
- 在本目标文件中引用的全局符号,却没冇定义在本目标文件, 这一般叫做外部符号(External Symbol), 也就是我们前面所讲的符号引用。比如
- 段名,这种符号往往由编译器产生,它的值就是该段的起始地址。
- 局部符这类符号只在编译单元内部可见。调试器可以使用这些符号来分析程序或崩溃时的核心转储文件。这些局部符号对于链接过程没有作用,链接器往往也忽略它们。
- 行号信息,即目标文件指令与源代码中代码行的对应关系,它也是可选的。