[MIT6.828]ELF文件格式

1、整体
ELF文件结构看起来如下:

  Linking View                      Execution View
  ============                      ==============
  ELF header                        ELF header
  Program header table (optional)   Program header table
  Section 1                         Segment 1
  ...                               Segment 2
  Section n                         ...
  Section header table              Section header table (optional)




链接视图(Linking View)是链接器关注的结构,执行视图(Execution View)是程序加载器关注的结构,它们是一个文件的不同表现,之间的关系类似于C语言中的联合。在规定中只有ELF头部(ELF header)是确定位置的,其他可以是不固定(依据ELF头、程序头、区域头的信息而定),但是实际使用中经常用上述布局。

ELF文件中使用部分的数据类型如下:

  Name           Size Alignment   Purpose
  ====           ==== =========   =======
  Elf32_Addr      4       4       Unsigned program address
  Elf32_Half      2       2       Unsigned medium integer
  Elf32_Off       4       4       Unsigned file offset
  Elf32_Sword     4       4       Signed large integer
  Elf32_Word      4       4       Unsigned large integer
  unsigned char   1       1       Unsigned small integer




2、ELF头
在ELF文件中,ELF头在文件的最前端,保存了整个文件的信息摘要,是识别文件的入口处,32位ELF文件头其结构如下:

#define EI_NIDENT       16
typedef struct
{
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
  Elf32_Half    e_type;                 /* Object file type */
  Elf32_Half    e_machine;              /* Architecture */
  Elf32_Word    e_version;              /* Object file version */
  Elf32_Addr    e_entry;                /* Entry point virtual address */
  Elf32_Off     e_phoff;                /* Program header table file offset */
  Elf32_Off     e_shoff;                /* Section header table file offset */
  Elf32_Word    e_flags;                /* Processor-specific flags */
  Elf32_Half    e_ehsize;               /* ELF header size in bytes */
  Elf32_Half    e_phentsize;            /* Program header table entry size */
  Elf32_Half    e_phnum;                /* Program header table entry count */
  Elf32_Half    e_shentsize;            /* Section header table entry size */
  Elf32_Half    e_shnum;                /* Section header table entry count */
  Elf32_Half    e_shstrndx;             /* Section header string table index */
} Elf32_Ehdr; 



3、区域和区域头
区域头(Section header)保存在区域头表中,由ELF头中的e_shoff来指定区域头表的位置,e_shentsize指定一条区域头信息的大小,e_shnum指定区域头的数目 ,区域头保存了程序中区域的信息,32位区域头结构如下:

typedef struct
{
  Elf32_Word    sh_name;                /* Section name (string tbl index) */
  Elf32_Word    sh_type;                /* Section type */
  Elf32_Word    sh_flags;               /* Section flags */
  Elf32_Addr    sh_addr;                /* Section virtual addr at execution */
  Elf32_Off     sh_offset;              /* Section file offset */
  Elf32_Word    sh_size;                /* Section size in bytes */
  Elf32_Word    sh_link;                /* Link to another section */
  Elf32_Word    sh_info;                /* Additional section information */
  Elf32_Word    sh_addralign;           /* Section alignment */
  Elf32_Word    sh_entsize;             /* Entry size if section holds table */
} Elf32_Shdr;





区域的一些特点和规格:
(1)、每个区域都有一个区域头来标识,但是一个区域头可以不标识任何区域。
(2)、区域在文件中连续存放,但要求按照sh_addralign要求的对齐格式对齐。
(3)、区域不能相互重叠,但长度为零的区域是例外。
(4)、文件由ELF头,程序头表,区域头表,区域列表组成。如果还有其他空间,其内容是未指定的,不能依赖于这些空间来存放数据。

4、段和程序头
程序头(Program header),保存了运行视图的信息,在加载程序时需要这些数据结构。以下是程序头的结构:

typedef struct
{
  Elf32_Word    p_type;                 /* Segment type */
  Elf32_Off     p_offset;               /* Segment file offset */
  Elf32_Addr    p_vaddr;                /* Segment virtual address */
  Elf32_Addr    p_paddr;                /* Segment physical address */
  Elf32_Word    p_filesz;               /* Segment size in file */
  Elf32_Word    p_memsz;                /* Segment size in memory */
  Elf32_Word    p_flags;                /* Segment flags */
  Elf32_Word    p_align;                /* Segment alignment */
} Elf32_Phdr;





段的一些特点和规格:
(1)、为了在分页系统中提高性能,其文件偏移和虚拟地址对页面大小取模后余数相同,最好的情况是偏移和起始位置都在页开始处。
(2)、程序段中的p_filesz和p_memsz不一定相同,因为某些区域如.bbs没有在文件中保存任何数据,只是保存了一个长度信息。而.bss区域在运行的时候是需要占用内存,一般OS将其初始化为0。
(3)、一个可执行程序或者共享库至少有一个程序头,一个程序头会包括零个以上链接视图下的区段。

5、工具的使用
(1)、readelf,用来查看elf文件的各种段,头,区域,内容详尽。
(2)、objdump,不但可以查看elf文件还可以查看别的格式的二进制文件,还可以进行反汇编,但是对于elf格式的描述没有readelf详细。
(3)、hexdump,十六进制查看器,可以查看任何东西,但是本身不识别文件格式,可以很方便的对文件进行不同偏移,不同大小,不同进制的查看。
(4)、objcopy,用来复制和拼接目标文件,可以指定需要复制的区域,字节。
具体使用方法,man之。

参考资料:
"ELF file structure" http://labmaster.mi.infn.it/Laboratorio2/CompilerCD/clang/l1/ELF.html

《程序员的自我修养:链接、装载与库》http://book.51cto.com/art/200904/120986.htm

Linux Manual (binutils),binutils.info,/usr/include/elf.h

This entry was posted in 操作系统 and tagged . Bookmark the permalink.

2 Responses to [MIT6.828]ELF文件格式

  1. snail says:

    原来dave写过这篇文章啊
    刚把程序猿自我修养的相关内容看完

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注