微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > MCU和DSP > UNIX/LINUX 平台可执行文件格式分析

UNIX/LINUX 平台可执行文件格式分析

时间:03-01 来源:IBM 点击:

具体细节请参阅 参考资料 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的节中也出现了行信息,行信息描述了二进制代码与源代码的行号之间的对映关系,在调试时很有用。

参考资料 19是一份对COFF格式详细描述的中文资料,更详细的内容请参阅 参考资料 20。

ELF文件格式分析

ELF文件有三种类型:可重定位文件:也就是通常称的目标文件,后缀为.o。共享文件:也就是通常称的库文件,后缀为.so。可执行文件:本文主要讨论的文件格式,总的来说,可执行文件的格式与上述两种文件的格式之间的区别主要在于观察的角度不同:一种称为连接视图(Linking View),一种称为执行视图(Execution View)。

首先看看ELF文件的总体布局:

ELF header(ELF头部)
Program header table(程序头表)
Segment1(段1)
Segment2(段2)
………
Sengmentn(段n)
Setion header table(节头表,可选)

段由若干个节(Section)构成,节头表对每一个节的信息有相关描述。对可执行程序而言,节头表是可选的。 参考资料 1中作者谈到把节头表的所有数据全部设置为0,程序也能正确运行!ELF头部是一个关于本文件的路线图(road map),从总体上描述文件的结构。下面是ELF头部的数据结构:

typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* 魔数和相关信息 */
Elf32_Half e_type; /* 目标文件类型 */
Elf32_Half e_machine; /* 硬件体系 */
Elf32_Word e_version; /* 目标文件版本 */
Elf32_Addr e_entry; /* 程序进入点 */
Elf32_Off e_phoff; /* 程序头部偏移量 */
Elf32_Off e_shoff; /* 节头部偏移量 */
Elf32_Word e_flags; /* 处理器特定标志 */
Elf32_Half e_ehsize; /* ELF头部长度 */
Elf32_Half e_phentsize; /* 程序头部中一个条目的长度 */
Elf32_Half e_phnum; /* 程序头部条目个数 */
Elf32_Half e_shentsize; /* 节头部中一个条目的长度 */
Elf32_Half e_shnum; /* 节头部条目个数 */
Elf32_Half e_shstrndx; /* 节头部字符表索引 */
} Elf32_Ehdr;

下面我们对ELF头表中一些重要的字段作出相关说明,完整的ELF定义请参阅 参考资料6和 参考资料 7。

e_ident[0]-e_ident[3]包含了ELF文件的魔数,依次是0x7f、'E'、'L'、'F'。注意,任何一个ELF文件必须包含此魔数。 参考资料 3中讨论了利用程序、工

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top