基于PowerPC Linux的ELF格式分析设计.doc
《基于PowerPC Linux的ELF格式分析设计.doc》由会员分享,可在线阅读,更多相关《基于PowerPC Linux的ELF格式分析设计.doc(27页珍藏版)》请在沃文网上搜索。
1、 基于PowerPC Linux的ELF格式分析第一部分 ELF格式概述ELF(Executable and Linkable Format)是一种对可执行文件、目标文件以及库文件使用的文件格式,它在Linux下成为标准文件已经有很长的一段时间,代替了早期的a.out格式。ELF格式的一个优点是同一个文件格式可以用在Linux Kernel支持的所有体系结构之上。这不仅简化了用户空间工具程序的创建,也简化了内核自身的程序设计,比如必须为可执行程序生成装载例程时。但是文件格式相同并不意味着不同系统上的程序之间存在二进制兼容性,例如FreeBSD和Linux都使用ELF作为二进制格式,但是Free
2、BSD上的程序不能运行于Linux上,因为两者在系统调用机制和系统调用语义方面仍然有所不同,反之亦然;如果想让二者之间的程序能够运行,必须要有一个中间仿真层。同样PowerPC平台编译的ELF程序,也不能在X86平台的机器上运行,反之依然,因为两者的体系结构是完全不同的。但是由于ELF格式的存在,相同体系结构上的ELF程序本身的相关信息,以及程序的各个部分在二进制文件中的编码方式都是相同的。Linux不仅将ELF用于用户空间应用程序和库,还用于工具模块,另外Linux内核本身也是ELF格式。备注:ELF文件是一种开放的格式,其规范可以自由获得。ELF文件有三种类型:可重定位文件:也就是通常称的
3、目标文件,后缀为.o;共享文件:也就是通常称的库文件,后缀为.so;可执行文件:本文主要讨论的文件格式;总的来说,可执行文件的格式与上述两种文件的格式之间的区别主要在于观察的角度不同:一种称为连接视图(Linking View),一种称为执行视图(Execution View)。示意图如下:第二部分 布局和结构ELF Header:除了用于标识ELF文件的几个字节之外,ELF文件头还包含了有关文件类型和大小的信息,以及文件加载后程序执行的入口信息等等,总之ELF头部是一个关于本ELF文件的路线图(road map),从总体上描述文件的结构。程序表头(Program Head Table):向系
4、统提供了可执行文件的数据在进程虚拟地址空间中组织方式的相关信息,它还表示了文件可能包含的段的数目,段的位置以及用途。各个段SegmentX(X=1,2,)和节SectionX(X=1,2,):保存了与文件相关的各种形式的数据,例如符号表、实际的二进制代码、固定值或者程序使用的数值常数。节头表(Section Header Table):包含了与各段相关的附加信息。下面我们一个例子,用readelf工具来分析ELF文件:例如如下:/test.c#include #include int add(int a, int b) printf(Numbers are added togethern);
5、return a + b;int main() int a, b; a = 3; b = 4; int ret = add(a,b); printf(Result : %un,ret); exit(0);我们用file命令来显示编译器生成的两个文件的信息:一个是可执行文件,另一个是可重定位文件,示意图如下:2.1 ELF header文件结构我们用readelf工具来分析上例中生成ELF文件的ELF header,视图如下:在test文件的开始处是四个标志字节,0x 7f、0x45、0x4c、0x46。其中的0x45、0x4c、0x46分别代码“E”“L”“F”的ASCII码,这使得所有处理E
6、LF文件的工具都可以识别ELF类型的文件。还有一些与机器体系结构相关的信息。比如上图中Machine类型为PowerPC表明该ELF文件运行于PowerPC平台;ELF32表明这是一个运行在32位平台的机器;文件类型为EXEC表明这是一个可执行程序;Version用于区分当前ELF文件的各个修订版本,当前ELF文件是基于版本1;另外还包含ELF文件各个部分的长度和索引的位置,后面会相信讨论。如果ELF文件是可重定位文件,不同的字段如下图所示:如图所示:test.o的文件类型为REL,即它是一个可重定位的文件,其代码可以移动到任意位置,该文件没有程序头Program Headers,对于需要链接
7、的对象而言该表是不需要的,所以其所以长度均为0。2.2 程序头表(Program Head Table)分析下面我们来分析一下ELF可执行文件test中Program Head Table,示意图如下:在Program Headers中列出了8个段,这些段组成了最终在内存中执行的程序,并且还提供了各个段在虚拟地址空间和物理地址空间中的位置、大小、访问授权和其它方面的信息。从上图中我们可以看出,示例程序中包含的各个段的语义如下:PHDR:保存Program Headers TableINTERP:制定程序已经从可执行文件映射到内存之后,必须调用的解释器。在这里,解释器并不意味着二进制文件的内容必
8、须由另一个程序解释(比如Java字节代码必须由Java虚拟机来解释),它指的是这样的程序:通过链接其它库来满足未解决的引用。LOAD:表示一个需要从二进制文件映射到虚拟地址空间的段,其中保存常量数据(如字符串),程序的目标代码等等。DYNAMIC:保存了由动态链接区(即INTERP中指定的解释器)使用的信息。NOTE:保存了专用信息,与当前主题无关。GNU_EH_FRAM和GNU_STACK:用来分析栈帧,与体系结构相关,在PowerPC体系结构中需要分析栈帧实现回溯。备注:我们需要特别指出段是可以重叠的,比如在上图中LOAD段从物理地址0x1000 0000到物理地址0x1000 0000+
9、0x007f8的范围,该范围包含了PHDR、INTERP、NOTE、GNU_EH_FRAM和GNU_STACK段,在ELF标准中是允许这种行为的。2.3 节头标(Section Header Table)分析在ELF文件中描述各段的内容时,是指定了哪些节的数据映射到段中。在ELF中是有一张节头表来管理文件中的各个节,readelf同样可以用于显示可重定位文件test.o中的各个节,示意图如下:这里指定的偏移量0x168是相对于二进制文件的。节信息不需要复制到在虚拟地址空间中做为可执行文件创建的最终进程映象,尽管如此在ELF二进制文件中节信息总是存在的。每个节都指定了一个类型,定义了节数据的语义
10、。包含PROGBITS、SYSTAB、RELA和STRTAB。PROGBITS:程序必须解释的信息,比如二进制代码,程序的二进制代码被称之为text,指的是用作机器代码的二进制信息SYSTAB:符号表RELA:重定位信息STRTAB:用于存储与ELF相关的字符串,但与程序没有直接的关系。各个节Section都指定了其大小和在二进制文件内部的偏移量。地址Addr:指定加载到虚拟地址空间的位置,因为我们的例子中处理的是一个可链接的对象,目标地址是没有定义的,因而表示为0。标志Flg:指出各个节Section如何被访问或者处理。我们对标志A比较感兴趣,因为它控制着装载文件时是否将节的数据复制到虚拟地
11、址空间中。尽管节的名称是可以自由选择的,但是Linux(和其它所有使用ELF的类UNIX系统)都提供了一些标准节,其中一些是强制性的,例如总是有一个名为.text的节来保存二进制代码(即与该ELF文件相关联的程序信息),.rel.text保存了节的重定位信息。备注:节名以点开始是由系统自身使用的,如果应用程序要想定义自身的节,就不应该以点开头,以避免与系统节名相冲突。可执行程序包含了一些重定位的信息,示意图如下:与可重定位文件的11个节相比,可执行文件有36个节,并非所有的节都与我们的讨论有关。上图中标出的节是有具体意义的:.interp:保存了解释器的文件名,例如在我们的例子中用的是是ld.
12、so.1;.data:保存了初始化的数据,这是普通程序数据的一部分,可以在程序运行时修改;.rodata:保存了只读数据,可以读但不可以修改,例如编译器将所有出现在printf中的静态字符串封装到该节;.init和.fini:保存了进程初始化和结束时所用的代码,这两个节通常是编译器自动添加的,无需应用程序员关注;.hash:是一个散列表,允许在不对全表元素进行线性搜索的情况下,快速访问所有的符号表项。备注:可执行文件ELF各个Section中的Addr字段保存了有效地址的值,因为相应的代码必须映射到虚拟地址空间中某些已经定义好的位置,在基于PowerPC的Linux中应用程序通常使用0x100
13、0 0000以上的内存区间。2.4 符号表(Symbol Table)符号表是每个ELF文件的一个重要的组成部分,因为它保存了程序实现或者使用过程中所有的(全局)变量和函数,如果程序使用了一个自身代码没有定义的符号,则称之为未定义符号(例如例子中的printf函数是定义在C标准库中,自身没有定义),此类应用必须在静态链接期间用其它的目标模块或者库来解决,或者在加载期间使用lib/ ld.so.1来解决。我们可以使用nm工具生成程序定义或者使用的所有符号列表,如果下图所示:左侧一列给出了符号的值,即符号定义在目标文件中的位置,例子中包含了两个不同的符号类型:如果函数定义在text段,缩写为T;而
14、未定义的引用用U标明。逻辑上没有定义的函数没有符号值。可在可执行ELF文件test中,还会有更多的符号。当时大多数都是由编译器自动生成的,供运行时系统内部使用,以下例子中我们仅标出了同时出现在test.o中的符号: U exitGLIBC_2.01000058c T add100005dc T main U putsGLIBC_2.0解释:exit和puts虽然是没有定义的,但是同时增加了一些版本信息,标明能够提供函数的GNU标准库的最低版本,在我们的例子中要求库的最低版本不能低于2.0,这意味着该程序无法使用Libc5和Lib4工作,因为Libc4和Libc5是Linux专用的C标准库,Gl
15、ibc_2.0是该库的第一个跨平台版本,它替换了就版本,它替换了旧版本。由函数本身定义的add和main已经移到虚拟地址空间中的固定位置(在文件加载时,对应的代码将会映射到这些位置)ELF使用以下的三个节(Section);来实现字符串的管理:.systalb:确定字符串的名称与其值的索引,但符号的名称不是以字符串的形式出现的,而是表示为某个字符串数组的索引;.strtab:保存了字符串数组;.hash:保存了一个hash表用于快速查找符号。简而言之,符号名在字符串表(string table )中的位置和符号的值,为了说明字符串表示如何管理ELF中的字符串,我们看下面的例子:表的第一个字节是
16、NULL(即ASCII码值为0),后续的各个字符串通过NULL字节分割,为了引用字符串必须指定一个位置,即字符串的索引。这将选择下一个NULL字节之前的所有字符(如果用NULL字节的位置作为索引,那么将会对应空串)。如果允许索引不仅仅选择字符串的起始地址,也可以选择字符串中间的任何位置,就能够支持字串的用法(但是非常受限)上述的.strtab节并不是默认情况下的唯一的字符串表,.shstrtab用于存放文件中各个节的文本名称(比如.text)第三部分 Linux 内核中的数据结构内核在两处使用了ELF文件格式:ELF用于处理可执行文件和库,用于实现模块。这些地方使用了不同的代码来读取和操作数据
17、,但这两种情况下都利用了我们本文所介绍的数据结构,其基础是include/elf.h文件,它实现了ELF标准,基本没有做改动!3.1 数据类型ELF是一个与CPU和体系结构无关的格式,它不能依赖与特定的字长和字节序(大端还是小端),至少对文件中的那些需要在所有系统上读取和理解的数据元素来说是这样。出现在.text段中的机器代码存储为宿主系统的表示格式,以避免转换工作。为此Linux内核定义了一些数据类型,在所有体系结构上具有相同的位宽,如下所示:/32-bit ELF 基本类型typedef _u32 Elf32_Addr;typedef _u16 Elf32_Half;typedef _u3
18、2 Elf32_Off;typedef _s32 Elf32_Sword;typedef _u32 Elf32_Word;/ 64-bit ELF 基本类型typedef _u64 Elf64_Addr;typedef _u16 Elf64_Half;typedef _s16 Elf64_SHalf;typedef _u64 Elf64_Off;typedef _s32 Elf64_Sword;typedef _u32 Elf64_Word;typedef _u64 Elf64_Xword;typedef _s64 Elf64_Sxword;因为体系结构相关的代码必须总是明确定义整数类型的符号
19、和位宽,ELF标准的数据类型可以毫不费力的通过typedef实现3.2 ELF头部格式实现对ELF格式的各种头部文件,32位和64位需要分别定义其数据结构:32位的ELF头在include/elf.h定义如下:#define EI_NIDENT 16typedef struct elf32_hdr unsigned char e_identEI_NIDENT; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shof
20、f; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; Elf32_Ehdr;解释:e_ident:可以容纳16个字节,这些字节在所有的体系结构上都是由char数据类型表示的,前4个字节分别为0x7f(即ASCII码中的DEL)和字母E、L、F,我们在2.1节曾介绍过。其它的字节位置有其特定的含义:e_ident4:EI_CLASS标识文件的类
21、型,将文件分为32位和64位两类,即ELFCLASS32和ELFCLASS64e_ident5:EI_DATA指定了格式所使用的字节序,即ELFDATA2LSB(小端)和ELFDATA2MSB()大端ei_ident6:EI_VERSION指定ELF头文件的版本(该版本可能独立于数据段的版本),当前,值允许使用EV_CURRENT,这是第一个版本ei_ident7: EI_OSABI指定采用的OS的ABI版本,当前是UNIX System V ABI从ei_ident8EI_PAD起的剩余字节:用NULL来填充,因为这些位置上ELF不需要。e_type用去区分各种ELF文件的类型,如下所示:e
22、_machine指定了文件所需的体系结构,下表列出了Linux支持的各种选项:注意:每种体系结构都需要定义elf_check_arch,并由内核的通用代码使用,来确保加载的ELF文件可以在相应的体系结构上运行。e_version:保存了版本信息,用于区分不同的ELF变体,目前该规范仅支持版本1,由EV_CURRENT指出来e_entry:给出了文件在虚拟内存中的入口点,在程序已经加载并映射到内存之后,执行开始的位置e_phoff:保存了程序头表(Program Header Table)在二进制ELF文件中的偏移e_shoff:保存了节表头(Section Header Table) 在二进制
23、ELF文件中的偏移e_flags:保存了特定于处理器的标志,当前Linux内核不适用该标志e_ehsize:指定了ELF Header的长度,单位是字节e_phentsize:指定了Program Header中一个表项的长度,单位是字节(所有表项的长度均相同)e_phnum:指定了Program Header Table中表项的数目e_shentsize:指定了Section Header Table中一个表项的长度,单位是字节(所有表项的长度均相同)e_shnum:指定了节头表中项的数目e_shstrndx:保存了包含各节(Section)名称的字符串表在Section Header中的索
- 1.请仔细阅读文档,确保文档完整性,对于不预览、不比对内容而直接下载带来的问题本站不予受理。
- 2.下载的文档,不会出现我们的网址水印。
- 3、该文档所得收入(下载+内容+预览)归上传者、原创作者;如果您是本文档原作者,请点此认领!既往收益都归您。
下载文档到电脑,查找使用更方便
20 积分
下载 | 加入VIP,下载更划算! |
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于PowerPC Linux的ELF格式分析设计 基于 PowerPC Linux ELF 格式 分析 设计