链接视图下的ELF头部详解

一 头部定义

typedef struct{
  unsigned char e_ident[EI_NIDENT];    //最开头是16个字节的e_ident, 其中包含用以表示ELF文件的字符,以及其他一些与机器无关的信息。开头的4个字节值固定不变,为0x7f和ELF三个字符。
  Elf32_Half e_type;       //该文件的类型 2
  Elf32_Half e_machine;    //该程序需要的体系结构 2
  Elf32_Word e_version;    //文件的版本 4
  Elf32_Addr e_entry;      //程序的入口地址 4
  Elf32_Off e_phoff;       //Program header table 在文件中的偏移量 4
  Elf32_Off e_shoff;       //Section header table 在文件中的偏移量 4
  Elf32_Word e_flags;      //对IA32而言,此项为0。 4
  Elf32_Half e_ehsize;     //表示ELF header大小 2
  Elf32_Half e_phentsize;  //表示Program header table中每一个条目的大小 2
  Elf32_Half e_phnum;      //表示Program header table中有多少个条目 2
  Elf32_Half e_shentsize;  //表示Section header table中的每一个条目的大小 2
  Elf32_Half e_shnum;      //表示Section header table中有多少个条目 2
  Elf32_Half e_shstrndx;   //包含节名称的字符串是第几个节 2
}Elf32_Ehdr;

二 数据类型说明

名称

大小

对齐

用途

Elf32_Addr

4

4

无符号程序地址

Elf32_Half

2

2

无符号中等大小整数

Elf32_Off

4

4

无符号文件偏移

Elf32_Sword

4

4

有符号大整数

Elf32_Word

4

4

无符号大整数

unsigned char

1

1

无符号小整数

三 读取整个ELF文件头的内容

[root@localhost 0401]# readelf -h add.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00            //Magic 魔数,用来指名该文件是一个 ELF 目标文件。第一个字节 7F 是个固定的数;后面的 3 个字节正是 E, L, F 三个字母的 ASCII 形式。
  Class:                             ELF64                            //CLASS 表示文件类型,这里是 64位的 ELF 格式。
  Data:                              2's complement, little endian    //Data 表示文件中的数据是按照什么格式组织(大端或小端)的,不同处理器平台数据组织格式可能就不同,如x86平台为小端存储格式。
  Version:                           1 (current)                      //当前 ELF 文件头版本号,这里版本号为 1 。
  OS/ABI:                            UNIX - System V                  //OS/ABI ,指出操作系统类型,ABI 是 Application Binary Interface 的缩写。
  ABI Version:                       0                                //ABI 版本号,当前为 0 。
  Type:                              REL (Relocatable file)           //Type 表示文件类型。ELF 文件有 3 种类型,一种是如上所示的 Relocatable file 可重定位目标文件,一种是可执行文件(Executable),另外一种是共享库(Shared Library) 。
  Machine:                           Advanced Micro Devices X86-64    //机器平台类型。
  Version:                           0x1                              //当前目标文件的版本号。
  Entry point address:               0x0                              //程序进入点指当程序真正执行起来的时候,其第1条要运行的指令地址。因为可重入文件只是供再链接而已,所以它不存在进入点,而可执行文件和动态库文件都存在所谓进入点。
  Start of program headers:          0 (bytes into file)              //因为这还不是可运行的程序,故而这里为零。
  Start of section headers:          544 (bytes into file)            //sections 头开始处,这里 544 是十进制,表示从地址偏移 544 处开始。
  Flags:                             0x0                              //是一个与处理器相关联的标志,x86 平台上该处为 0 。
  Size of this header:               64 (bytes)                       //ELF 文件头的字节数
  Size of program headers:           0 (bytes)                        //因为这个不是可执行程序,故此处大小为 0。
  Number of program headers:         0                                //因为这个不是可执行程序,故此处大小为 0。
  Size of section headers:           64 (bytes)                       //sections header 的大小,这里每个 section 头大小为 64个字节。
  Number of section headers:         11                               //一共有多少个 section 头,这里是 11 个。
  Section header string table index: 8

在ELF文件里面,每一个section内都装载了性质和属性都一样的内容。有以下几种情况:

  • .text:已编译程序的机器代码。
  • .rodata:只读数据,比如printf语句中的格式串和开关(switch)语句的跳转表。
  • .data:已初始化的全局C变量。局部C变量在运行时被保存在栈中,既不出现在.data中,也不出现在.bss节中。
  • .bss:未初始化的全局C变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分初始化和未初始化变量是为了空间效率在:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。
  • .symtab:一个符号表(symbol table),它存放在程序中被定义和引用的函数和全局变量的信息。一些程序员错误地认为必须通过-g选项来编译一个程序,得到符号表信息。实际上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的表目。
  • .rel.text:当链接噐把这个目标文件和其他文件结合时,.text节中的许多位置都需要修改。一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。另一方面调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非使用者显式地指示链接器包含这些信息。
  • .rel.data:被模块定义或引用的任何全局变量的信息。一般而言,任何已初始化全局变量的初始值是全局变量或者外部定义函数的地址都需要被修改。
  • .debug:一个调试符号表,其有些表目是程序中定义的局部变量和类型定义,有些表目是程序中定义和引用的全局变量,有些是原始的C源文件。只有以-g选项调用编译驱动程序时,才会得到这张表。
  • .line:原始C源程序中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译驱动程序时,才会得到这张表。
  • .strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null结尾的字符串序列。

你可能感兴趣的:(C++)