文章目录
- 编译器编译源代码后生成的文件叫做目标文件,
- 里面到底存放的是什么?
- 源代码在经过编译以后是怎么存储的?
- 这一节剥开目标文件的外壳,去探索它最本质的内容。
- 目标文件从结构上讲,它是已经编详后的可执行文件格式,
- 只是还没有经过链接
- 有些符号或有些地址还没有被调整。
- 它本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。
- 可执行文件格式涵盖了程序的编译、链接、装载和执行的各个方面。
- 了解它的结构并深入剖析它对于认识系统、了解背后的机理大有好处
3.1目标文件的格式
- 可执行文件格式
- Windows的PE( Portable Executable)
- Linux的ELF( Executable Linkable Format),
- 都是COFF( Common file format)格式的变种
- 目标文件就是源代码编译后但未进行链接的那些中间文件( Windows
.obj和Linux .o),跟可执行文件的内容与结构很相似,所以一般跟可执行文件格式起采用一-种格式存储。
- 目标文件与可执行文件的格式几乎一样,
- 可广义地将目标文件与可执行文件看成是一种类型文件
- Windows下,统称PE-COFF文件格式
- Linux下,统称为ELF文件。
- 可执行文件格式还有 Intel/Microsoft的OMF( Object Module Format)、 Unix a.out和MS-DOS.COM等
- 不光可执行文件( Windows的.exe和Linux下ELF可执行文件)按照exe格式存储
- 动态链接库( Windows的.ddl和 llinux的.so)及静态链接库( Windows的.lib和 Linux的.a)文件都按照可执行文件格式存储
- Windows下都按照PE-COFF格式存储, Linux下按照ELF格式存储
- 静态链接库稍有不同,它是把很多目标文件捆绑在一起形成一个文件,再加上一些索引,可简单把它理解为一个包含有很多目标文件的文件包
- ELF文件标准里面把系统中用ELF格式的文件归为如表3-1
- 目标文件与可执行文件格式跟OS和编译器密切相关
- 不同系统平台下会有不同的格式,格式又大同小异,
- 目标文件格式与可执行文件格式的历史几乎是OS发展史
- COFF由 Unix System V Release3提出且使用的格式规范
- 微软基于COFF格式,制定PE格式标准,并将其用于当时Windows NT
- System V Release4在COFF基础上引入ELF格式
- Linux也以ELF作为基本可执行文件格式。
- 这也就是为什么目前PE和ELF如此相似的主要原因,因为
它们都是源于同一种可执行文件格式COFF。
-
Uniⅸ最早的可执行文件格式为a.out,设计非常筒单,
- 后来共享库这个概念出现时,a.out格式就捉襟见肘
-
设计COFF格式来解决这些问题,
- 这个设计通用,COFF的继承者到目前还被广泛使用
-
COFF在目标文件里面引入了“段”机制,
- 不同的目标文件可拥有不同数量及不同类型的“段"。
- 还定义了调试数据格式。
- 下文的剖析以ELF结构为主
- 专门分析PE-COFF文件结构,
- 对比其与ELF异同。
3.2目标文件是什么样的
- 目标文件中至少有编译后的机器指令代码、数据
- 日标文件中还包括了链接时所须要的一些信思,如符号表、调试信息、字符串等
- 目标文件将这些信息按不问属性,
- 以“节”形式存储
- 有时也叫“段”
- 一般它们都表示一个一定长度的区域,基本上不加区別,
- 唯一的区别是在
- ELF的链接视图和装载视图时,后面专门提到
- 本书默认统一将它们称为“段”
- 编译后的机器指令经常被放在代码段里,
- 代码段常见的名字“.code”或“text"”;
- 全局变量和局部静态变量数据经常放在数据段
- 般名字都叫“data”。
- 一个简单的程序被编详成目标文件后的结构
- 如图3-1
- 图3-1的可执行文件(目标文件)的格式是ELF
- 开头是一个“文件头”,
- 描述整个文件的文件属性,
- 文件是否可执行、
- 是静态链接还是动态链接及入口地址(可执行文件)、
- 目标硬件、
- 目标操作系统等信息
- 一个段表,段表是描述文件中各个段的数组
- 段表描述文件中各个段在文件中的偏移位置及段的属性,
- 段表里面可得到每个段所有信息
- 文件头后面就是各个段的内容,
- 代码段保存的就是程序的指令,
- 数据段保存的就是程序的静态变量
- C编译后执行语句都编译成机器代码,保存在.text
- 已初始化的全局变量和局部静态变量都保存在.data
- 未初始化的全局变量和局部静态变量放在.“bss”
- 未初始化的全局变量和局部静态变量默认值都0,
- 本来它们也可以被放在.data,但它们都是0,
- 为它们在.data段分配空间并且存放数据0是没必要
- 程序运行时它们的确是要占内存空间的,可执行文件必须记录所有未初始化的全局变量和局部静态变量大小总和,记为.bss段
- .bss段只是为未初始化的全局变量和局部静态变量预留位置而已,它并没有内容,所以它在文件中也不占空间