Loading

快乐Linux —— 5. ElF 文件浅析

参考:

《程序员自我修养》《深入理解计算机系统》

https://blog.csdn.net/Vince_/article/details/89076338

http://www.skyfree.org/linux/references/ELF_Format.pdf 这篇英文pdf描述的很详细

https://www.jianshu.com/p/7c609b70acbd

0. 简述

ElF (Executable Linkable Format 可执行可连接格式),属于 COFF (Common file format) 通用文件格式 的变种。 因为目标文件( .o) 与可执行文件内容结构相似,所以一般与可执行文件格式采取同一种存储格式,我们将其统称为ELF文件。

我们重点关注 可重定位文件可执行文件

有两种不同理解ELF文件的视角。

  • 链接视角:在汇编器和链接器看来,ELF文件是由 Section Header Table 描述的一系列 Section

    Program Header Table在汇编和链接过程中没有用到,所以是可有可无的,Section Header Table中保存了所有Section的描述信息。

  • 执行视角:在加载器(Loader)看来它是由 Program Header Table 描述的一系列 Segment的集合。

    Program Header Table中保存了所有Segment的描述信息,Section Header Table在加载过程中没有用到,所以是可有可无的。

其他需要补充的:

  • 可重定位文件需要链接器做进一步处理,所以一定有Section Header Table; 可执行文件需要加载运行,所以一定有Program Header Table; 而共享库既要加载运行,又要在加载时做动态链接, 所以既有Section Header Table又有Program Header Table。
  • section:可重定位目标文件中的 .text.data.bss 等。
  • Segment:是指在程序运行时加载到内存的具有相同属性的区域,由一个或多个Section组成。在静态链接中由一个或多个可重定位目标文件的 section 在链接过程中合并而成。
  • 比如有两个Section都要求加载到内存后可读可写,就属于同一个Segment。有些Section只对汇编器和链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何Segment 。

Section Header Table 和 Program Header Table 并不是一定要位于文件开头和结尾的,其位置由ELF Header指出,上图这么画只是为了清晰。

如果仍然对section 和 segment 有疑惑的话,在后面编译链接原理里面有更详细的讲解。

1. ELF可重定位目标文件解析

readelf -S xxx.o 查看文件中的各个段

objdump -s -d xxx.o 查看各个段的内容

  1. ELF Header ELF文件头

    readelf -h xxx.o

  2. .text 代码段

    存放已编译的程序的机器指令。

  3. .rodata 和 .data

    .rodata 存放只读数据和字符串常量。(像printf中的格式串)

    .data 存放 已初始化非0 的(全局变量局部静态变量)。

  4. .bss Block Storage Start

    存放 初始化为0 的 (全局变量局部静态变量)和 (未初始化局部静态变量)。只在 Section Header 中占一个记录,而不占ELF空间。设置这个区是为了提高空间效率。

    而未初始化的全局变量分配给 COMMON 块 在深入理解计算机系统中有这样一段话

    在编译链接原理的链接过程中的符号解析详细说明了这个原因。

  5. .symtab 符号表

    记录ELF文件中用到的所有符号,每个符号有符号值对变量和函数来说,符号值就是它们的地址。

    (这块的符号表不包含函数里面的局部自动变量的符号。不要和编译过程中的符号表搞混,前者是由后者在汇编阶段生成)

    关于符号的更多信息: https://blog.csdn.net/baidu_41667019/article/details/84789564

  6. .rel.text 和 .rel.data 重定位表

  7. .debug 调试符号表 .line 源程序中行号和指令映射

    当编译器以调试形式生成目标文件时才有这些 section。

  8. .strtab 和 .shstrtab

    .strtab 保存普通的字符串,比如符号名称,包括.symtab 和 .debug 中符号信息。存放的是ELF文件中的字符串,而不是代码中的字符串。

    .shstrtab 常用于保存section名。

  9. Section Header Table 段表 / 节头部表

    保存各个段的信息包括 段名,段长,文件中的偏移,读写权限等等。

2. ELF可执行目标文件

image-20191209121509152

ELF可执行文件有以下几个特点:

  • 与可重定位文件大致类似。
  • .init 中定义了一个小函数 叫做 init,程序的初始化代码会调用它。
  • 没有 .rel 的区域,因为可执行文件已经被重定位。

可执行文件被设计得很容易加载到内存。在后面的编译链接原理中的装载会详细解释这个。

附加一个网上搜到的图! (右键打开看原图)

posted @ 2019-11-22 13:40  沉云  阅读(321)  评论(0编辑  收藏  举报