编译器编译源代码后生成的文件叫做目标文件。
目标文件从结构上讲,它是已经编译后的可执行文件格式,只是还没有链接的过程,其中可能有些符号或有些地址还没有调整。其实它本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。
可执行文件格式涵盖了程序的编译、链接、装载和执行的各个方面。
目标文件的格式:
PC平台流行的可执行文件格式主要是Windows下的PE和Linux的ELF,它们都是COFF格式的变种。目标文件就是源代码编译后但未进行链接的那些中间文件(Windows的.obj和Linux下的.o)
目标文件的内容:
编译后的机器指令代码、数据
符号表
调试信息
字符串
.......
一般目标文件将这些信息的不同属性,以"节"(也称"段")的形式存储。
SimpleSection.o
常见段
程序源代码编译后的机器指令经常放在代码段(.code 或.text)里
全局变量和局部静态变量数据经常放在数据段 (.data)
.data(数据段)保存的是初始化了的全局静态变量和局部静态变量
.rodata(只读数据段)存放的是只读数据,一半是程序里面的只读变量(如const修饰的变量)和字符串常量,操作系统在加载的时候可以将“ .radata ”段的属性映射成只读,对于这个段的任何修改操作都会作为非法操作处理。
.bss段存放的是未初始化的全局变量和局部静态变量(只是预留了位置)
(注:未初始化的全局变量和局部静态变量,默认值为0,本可以放在.data段,但是在.data段分配空间存放值为0的它们没有意义。由于在程序运行的时候他们确实是要占内存空间的,所以可执行文件必须记录所有未初始化的全局变量和局部静态变量的大小总和,记为.bss段。即.bss段只是为未初始化的全局变量和局部静态变量预留了位置,没有内容,也不占空间)
ELF文件结构描述(ELF文件头、段表、重定位表、字符串表)
我们可以用readlf命令来详细查看ELF文件
ELF文件头
定义了ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口和长度、段表的位置及段的数量等等
段表
(可使用objdmp -h 来查看ELF文件中包含的段)
段表是ELF文件中除了文件头以外的最重要的结构,它描述了ELF的各个段的信息(如:每个段的段名、长度、在文件中的偏移、读写权限及一些其他的属性)。
ELF文件的段结构就是由段表决定的,编译器、链接器和装载器都是依靠段表来定位和访问各个段的属性的。
重定位表
一个重定位表也是ELF的一个段。
链接器在处理目标文件时,须要对目标文件中某些部位进行重定位,即代码段和数据段中那些对绝对地址的引用的位置。这些重定位的信息都记录在ELF文件的重定位表里面,对于每个需要重定位的代码段或数据段,都会有一个相应的重定位表
字符串表
一般字符串表在ELF文件中也以段的形式保存
ELF文件中用到很多字符串(比如段名、变量名等),因为长度不确定,所以用固定的结构表示比较困难。
常见的做法就是把字符串集中起来存放到一个表,然后使用字符串在表中的偏移来使用字符串。