目标文件

来源:互联网 发布:存储过程的sql脚本代码 编辑:程序博客网 时间:2024/05/16 08:37

1.目标文件

excutable可执行文件,比如在windows的Portable Excutable,linux的Excutable Linkable Format文件。excutable本质上是COFF(common file format)的变种。COFF包括:
动态链接库dll:windows系统下的.dll, linux下的.so
静态链接库sll:windows系统下的.lib, linux下的.a
可执行文件:

ELF文件类型包括三种

  1. 可重定位文件(relocatable file):包含代码和数据,用于链接成可执行文件或者共享目标文件,静态链接库也属于此类。比如linux下的.o文件,window下的.obj文件。
  2. 可执行文件(excutable file):包含直接可执行的程序,代表ELF可执行文件。比如linux下的bin\bash,windows下的.exe文件。
  3. 共享目标文件(shared object file):包含代码和数据,在两种情况下使用,一种是链接器可以使用这种文件跟其他的可重定位文件以及共享目标文件链接,产生新的目标文件,第二种是动态链接器可以将几个共享目标文件与可执行文件结合,作为进程映像的一部分运行。比如linux下的.so文件(/lib/glibc-2.5.so),windows下的.DLL文件。
  4. 核心转储文件(core dump file):当进程意外终止时,系统可以将该进程地址空间的内容及终止时的一些其他信息转储到核心转储文件。linux下的core dump

2.目标文件格式:segment/section


代码段(code section):程序源代码,名字为.code,.text
数据段(data section):全局变量,局部静态变量 .data
File header: 是否可执行,静态链接/动态链接及入口地址,目标硬件,目标操作系统,段表(section table)描述文件中各个段的数组。
.BSS段(Block Started by Symbol):只是为未初始化的全局变量和局部静态变量预留位置(包括初始化为0的全局变量和局部静态变量),她没有内容,故在文件中也不占据空间。

数据段和程序段的分离的好处
(1)方便设置各自的读写权限
(2)提高程序的局部性,增加缓存命中率
(3)多个程序副本可以共享一份指令

readelf是专门读取ELF文件的解析器。
.code/.text
.data :初始化的全局/局部静态变量
.BSS : 有些编译器会将全局的未初始化变量存放在目标文件的.BSS段中,而另外一些编译器只是预留一个全局变量符号,等待到最终链接成可执行文件时,再在.BSS段分配空间
.rodata : const变量,字符串常量等,有时会合并到.data段中
.comment : 存放编译器版本信息
.not.GNUsteek :
.debug : 调试信息
.dynamic : 动态链接信息
.hash : 符号哈希表
.line :调试时的行号表,即源代码行号与编译后指令的对应表
.note :额外编译信息
.symtab : symbol table 符号表
.shstrtab :section string table 段表名
.plt 和 .got : 动态链接的跳转表和全局入口表
.Init和.fini : 程序初始化和终结代码段

可以自定义段,但自定义段不能以“.”开头,比如用户自定义放一段music音乐段。
自定义段:可以把代码段或者变量放到指定段中。比如gcc中可以这样:
_attibute_((section("FOO"))) int global = 42;

3.ELF文件结构


ELF Header:整个文件的基本属性,ELF文件版本,目标机器型号,程序入口地址
.text
.data
.bss
...
other sections
section header table: 所有段的信息:段名,段长,偏移,读写权限及其他属性
string Tables
symbol Tables

ELF文件头结构及相关常数定义在/usr/include/elf.h

文件类型
e_type{
 ET_REL,//可重定位
 ET_EXEC,//可执行
 ET_DYN//共享目标
}
机器类型:ELF文件格式被设计成可以在多个平台下使用,这并不表示同一个ELF文件可以在不同的平台下使用(就像java的字节码那样),而是表示不同平台下的ELF文件都遵循同一套ELF标准。
e_machine: 平台属性
段表:编译器,链接器和装载器都依靠此表来定位和访问各个段的属性。
重定位表:Relocatable table
.rel.text
sh_type: SHT_REL
链接器处理目标文件时,须要对目标文件中某些部位重定位,即代码段和数据段中那些对绝对地址的引用位置。这些重定位的信息都写在ELF文件的重定位表里,对于每个须要重定位的代码段,都会有一个相应的重定位表。

ELF文件中用到很多字符串,比如段名,变量名,且长度不固定,无法用固定的结构表示,一种做法是集中在一个表中,用偏移来应用。比如
字符串表:string table
段表字符串表:section header string table

4. 链接的接口-符号

 链接过程的本质就是把不同目标文件“粘”到一起。
目标文件之间须有固定的规则
目标文件的拼合,实际是目标文件之间对地址的引用,即对变量和地址的引用。

函数和变量统称为符号
函数名和变量名统称为符号名

每个目标文件都有一个符号表,每个符号表对应一个符号值:
1.定义在本文件中的全局符号
2.在目标文件中引用的全局符号,即external symbol,却没有在本文件中定义。
3.段名:编译器产生,其值为该段的起始地址
4.局部符号:只在编译单元内可见
调试器用其来分析程序或崩溃时的核心转储文件,这些符号对链接无作用。
行号信息:目标文件指令与源代码中代码行的对应关系。

符号表结构
typedef struct{
 Elf32_Word      st_name;  //符号名,包含符号表在字符串中的下标
 Elf32_Addr      st_value; //绝对地址或相对地址
 Elf32_Word      st_size;  //符号大小
 unsigned char   st_info;  //符号类型和绑定信息,绑定信息:局部符号,全局符号,弱引用,符号类型,
         //STT_NOTYPE, STT_OBJECT, STT_FUN, STT_SECTION, STT_FILE
 unsigned char   st_in;    //
 Elf32_half      st_shndx; //符号所在段,SHN_ABS, SHN_COMMON, SHN_UNDEF
}Elf32_Sym;
特殊符号:这些符号没有在程序中定义,但可以直接声明并引用,例如
_excutable.start
_etext 或 etext
_edata 或 edata
_end 或 end

符号修饰和符号签名
解决多个目标文件拼合时的名字冲突问题
namespace
C++符号修饰
Function Signature
Decorated Name
extern "C"

弱符号强符号
解决符号重复定义的问题,即相同名字的全局符号
strong symbol:全局且初始化,如main
weak symbol:全局但未初始化
规则1.不允许强符号多次被定义
规则2.如果一个符号在一个文件中为强,其他文件中全为弱,则选择强符号
规则3.若果所有空间中都为弱,则选择占用空间最大的

弱引用,强引用
强引用:链接生成可执行文件时,须正确决议,若没有找到该符号定义,则报错
弱引用:若没有找到符号定义,并不报错,对于未定义的弱引用,默认值为0


调试信息


静态链接
目标文件合并策略:按需叠加,相似段合并
两个地址和空间:输出的可执行文件中的空间,装载后的虚拟地址的虚拟空间
两步链接:空间与地址的分配,符号解析与重定位

符号地址的确定
计算各个段的地址:虚拟地址

重定位
编译器指一些指令的地址部分暂时用“OXOOOO...”或其他来代替

链接器在完成地址和空间分配之后已经可以确定所有符号的虚拟地址了,此时链接器可以根据符号的地址对每个需要重定位的指令进行地址修正。

重定位表: Relocation table
结构
Elf32_Rel
typedef struct{
 Elf32_Addr r_offset; //对重定位文件来说,该值是重定位入口所要修正的位置的第一个字节相对于段起始的偏移
                         //对可执行文件或共享对象文件,该值是该重定位入口所要修正的位置的第一个字节的虚拟地址
 Elf32_Word r_info;   //重定位入口的类型和符号:低8位-重定位入口的类型,高24位-重定位入口的符号在符号表中的下标
} Elf32_Rel;

符号解析
重定位过程中,每个重定位的入口都是对一个符号的引用,重定位时,先要确定符号的目标地址,此时,链接器会去查找所有输入目标文件的符号表组成的全局符号表,找到相应的符号表后,重定位。

指令修正方式:
近地寻址和远址寻址
绝对寻址和相对寻址

原创粉丝点击