posts - 297,  comments - 15,  trackbacks - 0

a.out 格式在不同的机器平台和不同的 UNIX 操作系统上有轻微的不同,例如在 MC680x0 平台上有 6 个 section。下面我们讨论的是最"标准"的格式。

a.out 文件包含 7 个 section,格式如下:exec header(执行头部,也可理解为文件头部)
text segment(文本段)
data segment(数据段)
text relocations(文本重定位段)
data relocations(数据重定位段)
symbol table(符号表)
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(程序进入点),代表了系统在加载程序并初试化各种环境后开始执行程序代码的入口。这个字段在后面讨论的 ELF 文件头部中也有出现。由 a.out 格式和头部数据结构我们可以看出,a.out 的格式非常紧凑,只包含了程序运行所必须的信息(文本、数据、BSS),而且每个 section 的顺序是固定的。这种结构缺乏扩展性,如不能包含"现代"可执行文件中常见的调试信息,最初的 UNIX 黑客对 a.out 文件调试使用的工具是 adb,而 adb 是一种机器语言调试器!

a.out 文件中包含符号表和两个重定位表,这三个表的内容在连接目标文件以生成可执行文件时起作用。在最终可执行的 a.out 文件中,这三个表的长度都为 0。a.out 文件在连接时就把所有外部定义包含在可执行程序中,如果从程序设计的角度来看,这是一种硬编码方式,或者可称为模块之间是强藕和的。在后面的讨论中,我们将会具体看到ELF格式和动态连接机制是如何对此进行改进的。

a.out 是早期UNIX系统使用的可执行文件格式,由 AT&T 设计,现在基本上已被 ELF 文件格式代替。a.out 的设计比较简单,但其设计思想明显的被后续的可执行文件格式所继承和发扬。可以参阅 参考资料 16 和阅读 参考资料 15 源代码加深对 a.out 格式的理解。 参考资料 12 讨论了如何在"现代"的红帽LINUX运行 a.out 格式文件。

 

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(符号表)
String 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 格式进行了扩展。Microsoft 设计了名为 PE(Portable Executable)的文件格式,主要扩展是在 COFF 文件头部之上增加了一些专用头部,具体细节请参阅 参考资料 18,某些 UNIX 系统也对 COFF 格式进行了扩展,如 XCOFF(extended common object file format)格式,支持动态连接,请参阅 参考资料 5。

紧接文件头部的是可选头部,COFF 文件格式规范中规定可选头部的长度可以为 0,但在 LINUX 系统下可选头部是必须存在的。下面是 LINUX 下可选头部的数据结构:typedef struct
            {
                  char     magic[2];    /* 魔数 */
                  char     vstamp[2];    /* 版本号 */
                  char     tsize[4];    /* 文本段长度 */
                  char     dsize[4];    /* 已初始化数据段长度 */
                  char     bsize[4];    /* 未初始化数据段长度 */
                  char     entry[4];    /* 程序进入点 */
                  char     text_start[4];         /* 文本段基地址 */
                  char     data_start[4];         /* 数据段基地址 */
            }
            COFF_AOUTHDR;

 

字段 magic 为 0413 时表示 COFF 文件是可执行的,注意到可选头部中显式定义了程序进入点,标准的 COFF 文件没有明确的定义程序进入点的值,通常是从 .text 节开始执行,但这种设计并不好。

前面我们提到,COFF 格式比 a.out 格式多了一个节段表,一个节头条目描述一个节数据的细节,因此 COFF 格式能包含更多的节,或者说可以根据实际需要,增加特定的节,具体表现在 COFF 格式本身的定义以及稍早提及的 COFF 格式扩展。我个人认为,节段表的出现可能是 COFF 格式相对 a.out 格式最大的进步。下面我们将简单描述 COFF 文件中节的数据结构,因为节的意义更多体现在程序的编译和连接上,所以本文不对其做更多的描述。此外,ELF 格式和 COFF格式对节的定义非常相似,在随后的 ELF 格式分析中,我们将省略相关讨论。struct COFF_scnhdr
            {
                  char s_name[8];       /* 节名称 */
                  char s_paddr[4];      /* 物理地址 */
                  char s_vaddr[4];      /* 虚拟地址 */
                  char s_size[4];         /* 节长度 */
                  char s_scnptr[4];     /* 节数据相对文件的偏移量 */
                  char s_relptr[4];      /* 节重定位信息偏移量 */
                  char s_lnnoptr[4];    /* 节行信息偏移量 */
                  char s_nreloc[2];     /* 节重定位条目数 */
                  char s_nlnno[2];      /* 节行信息条目数 */
                  char s_flags[4];       /* 段标记 */
            };

 

有一点需要注意:LINUX系统中头文件coff.h中对字段s_paddr的注释是"physical address",但似乎应该理解为"节被加载到内存中所占用的空间长度"。字段s_flags标记该节的类型,如文本段、数据段、BSS段等。在COFF的节中也出现了行信息,行信息描述了二进制代码与源代码的行号之间的对映关系,在调试时很有用。
转自:
http://www.360doc.com/content/080313/18/59039_1115300.html

posted on 2009-12-05 23:34 chatler 阅读(524) 评论(0)  编辑 收藏 引用 所属分类: FileFormat

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(10)

随笔分类(307)

随笔档案(297)

algorithm

Books_Free_Online

C++

database

Linux

Linux shell

linux socket

misce

  • cloudward
  • 感觉这个博客还是不错,虽然做的东西和我不大相关,觉得看看还是有好处的

network

OSS

  • Google Android
  • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
  • os161 file list

overall

搜索

  •  

最新评论

阅读排行榜

评论排行榜