a.out
a.out是"assembler output"的缩写格式,代表汇编程序输出。在较早版本的类unix系统中,a.out是一种输出格式,用于可执行文件,目标文件和共享库。早期的PDP-7系统上没有链接器,程序的创建过程是先把所有源文件连接成一个文件,然后进行汇编,产生的汇编程序保存在a.out中。这样a.out是名副其实的汇编输出,但到PDP-11之后,人们为其编写了链接器,程序的创建是先编译然后链接输出保存到a.out中,这时a.out其实已经是链接输出了,但输出的可执行文件仍然延续这个命名习惯。
标准的a.out 文件包含 7 个 section,格式如下:
exec header(执行头部|文件头部) | |
text segment(文本段) | |
data segment(数据段) | |
text relocations(文本重定位段) | |
data relocations(数据重定位段) | |
data relocations(数据重定位段) | |
string table(字符串表) | |
struct exec { unsigned long a_midmag; /* 魔数和其它信息 */ unsigned long a_text; /* 文本段的长度 */ unsigned long a_data; /* 数据段的长度 */ unsigned long a_bss; /* BSS段的长度 */ unsigned long a_syms; /* 符号表的长度 */ unsigned long a_entry; /* 程序进入点 */ unsigned long a_trsize; /* 文本重定位表的长度 */ unsigned long a_drsize; /* 数据重定位表的长度 */ }; |
文件头部主要描述了各个section 的长度,比较重要的字段是 a_entry(程序进入点),代表了系统在加载程序并初试化各种环境后开始执行程序代码的入口。a.out 的格式非常紧凑,只包含了程序运行所必须的信息:文本、数据、BSS(BSS是Unix链接器产生的未初始化数据段。其他的段分别是包含程序代码的“text”段和包含已初始化数据的“data”段。BSS段的变量只有名称和大小却没有值。此名后来被许多文件格式使用,包括PE。“以符号开始的块”指的是编译器处理未初始化数据的地方。BSS节不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零。BSS节在应用程序的二进制映象文件中并不存在),而且每个 section 的顺序是固定的。这种结构缺乏扩展性,如不能包含"现代"可执行文件中常见的调试信息。a.out 文件中包含符号表和两个重定位表,这三个表的内容在连接目标文件以生成可执行文件时起作用。在最终可执行的 a.out 文件中,这三个表的长度都为 0。a.out 文件在连接时就把所有外部定义包含在可执行程序中,如果从程序设计的角度来看,这是一种硬编码方式,或者可称为模块之间是强藕和的。a.out 是早期UNIX系统使用的可执行文件格式,由 AT&T 设计,现在基本上已被 ELF 文件格式代替。a.out 的设计比较简单,但其设计思想明显的被后续的可执行文件格式所继承和发扬。
魔数:Unix中的可执行文件用一种特殊的方式加上标签,这样便于系统确认它们的属性。普遍采用的方式是使用独特的数字,这些数字也被称为“神秘”数字。
PE
Microsoft设计了名为 PE(Portable Executable)的文件格式,主要扩展是在 COFF 文件头部之上增加了一些专用头部。
ELF
Executableand Linkable Format,可执行连接格式,是UNIX系统实验室作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的。工具接口标准委员会选择了正在发展中的ELF标准作为工作在32位INTEL体系上不同操作系统之间可移植的二进制文件格式。
COFF
COFF 格式比 a.out 格式要复杂一些,最重要的是包含一个节段表(section table),因此除了 .text,.data,和 .bss 区段以外,还可以包含其它的区段。另外也多了一个可选的头部,不同的操作系统可一对此头部做特定的定义。
COFF 文件格式如下:
File Header(文件头部) |
Optional Header(可选文件头部) |
Section 1 Header(节头部) |
……… |
Section n Header(节头部) |
Raw Data for Section 1(节数据) |
Raw Data for Section n(节数据) |
Relocation Info for Sect. 1(节重定位数据) |
Relocation Info for Sect. n(节重定位数据) |
Line Numbers for Sect. 1(节行号数据) |
Line Numbers for Sect. n(节行号数据) |
Symbol table(符号表) |
Symbol table(符号表) |
struct filehdr {
unsigned short f_magic; /* 魔数 */
unsigned short f_nscns; /* 节个数 */
long f_timdat; /* 文件建立时间 */
long f_symptr; /* 符号表相对文件的偏移量 */
long f_nsyms; /* 符号表条目个数 */
unsigned short f_opthdr; /* 可选头部长度 */
unsigned short f_flags; /* 标志 */
};
COFF 文件头部中魔数与其它两种格式的意义不太一样,它是表示针对的机器类型,例如 0x014c 相对于 i386 平台,而 0x268 相对于 Motorola 68000系列等。当 COFF 文件为可执行文件时,字段 f_flags 的值为 F_EXEC(0X00002),同时也表示此文件没有未解析的符号,换句话说,也就是重定位在连接时就已经完成。由此也可以看出,原始的 COFF 格式不支持动态连接。为了解决这个问题以及增加一些新的特性,一些操作系统对 COFF 格式进行了扩展。