ELF 文件格式 是一个开放标准,各种 UNIX 系统的可执行文件都采用 ELF 格式,它有三种不同的类型:
- 可重定位的目标文件(Relocatable,或者Object File)
- 可执行文件(Executable)
- 共享库(Shared Object,或者Shared Library)
在这里先详细解释一下程序的汇编、链接、运行过程:
1、写一个汇编程序保存成文本文件 max.s。
2、汇编器读取这个文本文件转换成目标文件 max.o,目标文件由若干个 Section 组成,我们在汇编程序中声明的 .section 会成为目标文件中的 Section,此外汇编器还会自动添加一些 Section(比如符号表)。
3、然后链接器把目标文件中的 Section 合并成几个 Segment,生成可执行文件 max。
4、最后加载器(Loader)根据可执行文件中的 Segment 信息加载运行这个程序。
ELF 格式提供了两种不同的视角,链接器把 ELF 文件看成是 Section 的集合,而加载器把 ELF 文件看成是 Segment 的集合。如下图所示。
左边是从链接器的视角来看 ELF 文件,开头的 ELF Header 描述了体系结构和操作系统等基本信息, 并指出 Section Header Table 和 Program Header Table 在文件中的什么位置,Program Header Table 在链接过程中用不到,所以是可有可无的,Section Header Table 中保存了所有 Section 的描述信息,通过 Section Header Table 可以找到每个 Section 在文件中的位置。右边是从加载器的视角来看 ELF 文件,开头是 ELF Header,Program Header Table 中保存了所有 Segment 的描述信息,Section Header Table 在加载过程中用不到,所以是可有可无的。
从上图可以看出,一个 Segment 由一个或多个 Section 组成,这些 Section 加载到内存时具有相同的访问权限。有些 Section 只对链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何 Segment。注意 Section Header Table 和 Program Header Table 并不是一定要位于文件的开头和结尾,其位置由 ELF Header 指出,上图这么画只是为了清晰。
目标文件需要链接器做进一步处理,所以一定有 Section Header Table;可执行文件需要加载运行,所以一定有 Program Header Table;而共享库既要加载运行,又要在加载时做动态链接,所以 既有 Section Header Table 又有 Program Header Table。