要理解为什么 FreeBSD 使用 elf(5) 格式, 您必须首先了解一些 UNIX® 系统中的 三种 “主要” 可执行文件格式的有关知识:
a.out(5)
是最古老和“经典的” UNIX 目标文件格式, 这种格式在其文件的开始处有一个短小而又紧凑的首部, 该首部带有一个魔幻数字,用来标识具体的格式(更多详情参见a.out(5))。 这种格式包含3个要装载入内存的段:.text, .data, 和 .bss,以及 一个符号表和一个字符串表。
COFF
SVR3目标文件格式。其文件头现在包括一个区段表(section table), 因此除了.text,.data,和.bss区段以外,您还可以包含其它的区段。
elf(5)
COFF 的后继, 其特点是可以有多个区段, 并可以使用32位或64位的值。 它有一个主要的缺点: ELF 在其设计时假设每个系统体系结构只有一种 ABI。 这种假设事实上相当错误, 甚至在商业化的SYSV世界中都是错误的 (它们至少有三种ABI: SVR4, Solaris, SCO)。
FreeBSD试图在某种程度上解决这个问题,它提供一个工具,可以 对一个已知的ELF可执行文件 标识它所遵从的ABI的信息。 更多这方面的知识可以参见手册页brandelf(1)
FreeBSD从“经典”阵营中来,因此使用了a.out(5)格式, 众多BSD版本的发行(直到3.X分支的开始)也证明了这种格式的有效性。 虽然在那以前的某段时间,在FreeBSD系统上创建和运行ELF格式 的二进制可执行文件(和内核)也是可能的,但FreeBSD一开始并不积极“进步” 到使用ELF作为其缺省的格式。为什么?噢,当Linux阵营完成了 转换到ELF格式的痛苦历程后,却发现并不足以由此而放弃 a.out可执行文件格式,因为正是由于它们不灵活的, 基于跳转表的共享库机制,使得销售商和开发者们构建共享库非常困难。 直到已有的ELF工具提供了一种解决共享库问题的办法, 并被普遍认为是“前进方向”以后,迁徙的代价在FreeBSD界才被接受, 并由此完成了迁徙。FreeBSD的共享库机制其基础更类似于Sun SunOS™的共享库机制, 并且正因为此,其易用性很好。
那么,为什么会有这么多不同的格式呢?
回溯到蒙昧和黑暗的过去,那时只有简单的硬件。这种简单的硬件支撑了一个简单 和小型的系统。在这样的简单系统上(PDP-11)a.out格式 足以胜任表达二进制文件的任务。当人们将UNIX从这种简单的系统中移植出来的时候, a.out格式被保留了下来,因为对于早期将UNIX移植到 Motorola 68k,VAXen等系统来说,它还是足够可用的。
然后,一些聪明的硬件工程师认为,如果可以让软件完成一些简单的聪明操作, 那么他们就可以在硬件设计中减少若干门电路,并可以让CPU核心运行得更快。 当a.out格式用于这种新型的硬件系统时(现在我们叫它 RISC),显得并不合适。因此,人们设计了许多新的格式 以便在这样的硬件系统上能获得比简单的a.out格式更优越 的性能。诸如COFF,ECOFF,还有其它 一些晦涩难懂的格式正是在这个阶段被发明出来的,人们也研究了这些格式的局限性, 慢慢地最终落实到ELF格式。
同时,程序的大小变得越来越大,磁盘空间(以及物理内存)相对来说却仍然较小, 因此共享库的概念便产生了。VM系统也变得越来越复杂了。当所有这些进步都建立在 a.out格式的基础上的时候,它的可用性随着每个新特性 的产生就受到了严重考验。并且,人们还希望可以在运行时动态装载某些东西,或者 在初始化代码运行以后可以丢弃部分程序代码,以便节约主存储器和交换区。编程语言 也变得越来越复杂,人们希望可以在main()函数执行之前自动执行某些代码。为了实现 所有这些功能,人们对a.out格式作了很多改动(hack), 他们在某个阶段里基本也是可行的。随着时间的推移,a.out格式 不得不增加大量的代码和复杂度来满足这些需求。虽然ELF格式 解决了许多这样的问题,但是从一个可用的系统迁移到另一个系统却是痛苦的。因此 直到继续保留a.out格式的代价比迁移到ELF格式 的代价还大的时候,人们才会最终转换到ELF格式。
然而,随着时间的推移,FreeBSD系统本身的编译工具(特别是汇编器和装载器) 赖以派生的编译工具,其发展却形成了两个平行的分支。FreeBSD这个分支增加了共享库, 并修改了一些错误。而原先编写了这些工具的GNU人则重写了这些工具,并对交叉编译提供了 更简化的支持,还随意插入了不同格式的支持,等等。虽然很多人希望创建针对FreeBSD的 交叉编译器,但他们却并未如愿以偿,因为FreeBSD的as 和ld的源代码更为老旧,所以无法完成这个任务。 新的GNU工具链(binutils)则确实支持交叉编译,ELF 格式,共享库,C++扩展,等等。并且,由于很多供应商都发布ELF格式的 二进制文件,因而让FreeBSD能够运行它们将是一个很好的事情。
ELF格式比a.out格式开销要大些,同时也 允许基础系统有更好的扩展性。ELF格式的有关工具有着更好的维护, 并且提供交叉编译支持,这对许多人来说是很重要的。ELF格式可能会稍微 慢一些,但很难测量出来。另外,在这两者之间,有许多细节也是不同的,比如它们映射页面的方式, 处理初始化代码的方式,等等。所有这些都不太重要,但这也确实是不同之处。在将来的适当时候, GENERIC内核将不再支持a.out格式,并且, 当不再需要运行遗留的a.out格式程序时,内核也将不再提供对其的支持。