ELF格式大致描述

文章目录

  • ELF格式
    • ELF文件类型
    • ELF文件结构
    • ELF header
    • Program Header Table
    • Section与Segment

ELF格式

ELF文件类型

  ELF是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件的文件格式。是Linux上二进制文件的标准格式。
  ELF有四种类型:

  • 重定位文件( ET_REL ),也就是常称的目标文件
  • 可执行文件( ET_EXEC )
  • 共享目标文件( ET_DYN ),即共享对象文件、动态库文件
  • 核心转储文件( ET_CORE )

除此之外还会有类型不确定的ELF文件( ET_NONE ),即未知文件。

ELF文件结构

  ELF由四部分组成:ELF头( ELF header )、程序头表( Program header table )、节( section )、节头表( section header table ),大致结构如下图所示:
ELF格式大致描述_第1张图片
需要注意的是,ELF文件结构的排布并不一定如上图所示,而且也不一定包含上图的所有内容。但是,ELF头一定会有,且在整个文件的第一个部分。
  这篇笔记下面就是解释这张图中的信息。

ELF header

  ELF头就是一个结构体,被称为 struct ElfN_Ehdr (程序头、节头都是结构体,在图中已经标出了对应结构体的名称)。该结构主要描述了整个文件的组织,前面提到ELF头以外的内容没有固定的位置是因为它们的位置是由ELF头指出的。
  ELF头对应的结构体如下(32位)

#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;

  命令readelf -h可以查看ELF文件的ELF头信息:

#注释:hello是一个打印helloworld的可执行程序,该程序是64位的
$ readelf -h hello
ELF 头:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  版本:                              1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              EXEC (可执行文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点地址:               0x400430
  程序头起点:          64 (bytes into file)
  Start of section headers:          6616 (bytes into file)
  标志:             0x0
  本头的大小:       64 (字节)
  程序头大小:       56 (字节)
  Number of program headers:         9
  节头大小:         64 (字节)
  节头数量:         31
  字符串表索引节头: 28
$

从上面我们可以知晓该ELF文件的类型(ELF64指的就是64位的可执行程序)、程序头的位置、节头的位置等等。至于第一行的Magic就是结构体中的那一个字符数组,正好16个字节,其中45 4c 46代表的就是"ELF"这一字符串。

Program Header Table

  程序头( program header )对应的结构体称为 struct ElfN_Phdr 。程序头是对段( segment )的描述,主要描述了如何装载可执行文件(即可执行文件的内存布局以及如何映射到内存中)。
  一个程序的段不止一个,所以程序头当然也不止一个,多个程序头组合在一起就成为了程序头表( program header table )。
  一个程序头的结构体如下:

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;

  程序头还有有不同的类型,主要类型如下:

  • PT_LOAD
  • PT_DYNAMIC
  • PT_NOTE
  • PT_INTERP
  • PT_PHDR

  命令readelf -l可查看ELF文件的程序头表:

$ readelf -l hello

Elf 文件类型为 EXEC (可执行文件)
入口点 0x400430
共有 9 个程序头,开始于偏移量 64

程序头:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000006fc 0x00000000000006fc  R E    200000
  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x0000000000000228 0x0000000000000230  RW     200000
  DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e28
                 0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000005d0 0x00000000004005d0 0x00000000004005d0
                 0x0000000000000034 0x0000000000000034  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x00000000000001f0 0x00000000000001f0  R      1
  
  #...省略了部分内容...

Section与Segment

  section指的是节,而segment指的是段。一个程序会被划分为多个段,而每个段中有会被划分为节。
  段是由程序头所描述的,多个程序头又组成了程序头表;而节是由节头描述的。多个节头同样组成了一个节头表( Section Header Table )。
  节头对应的结构体称为 struct ElfN_Shdr
  结构体如下所示:

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;

  命令readelf -S可查看ELF文件的节头:

$ readelf -S hello
共有 31 个节头,从偏移量 0x19d8 开始:

节头:
  [] 名称              类型             地址              偏移量
       大小              全体大小          旗标   链接   信息   对齐
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       0000000000000060  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400318  00000318
       000000000000003d  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400356  00000356
       0000000000000008  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400360  00000360
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400380  00000380
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400398  00000398
       0000000000000030  0000000000000018  AI       5    24     8
  [11] .init             PROGBITS         00000000004003c8  000003c8
       000000000000001a  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000004003f0  000003f0
       0000000000000030  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000400420  00000420
       0000000000000008  0000000000000000  AX       0     0     8
  [14] .text             PROGBITS         0000000000400430  00000430
       0000000000000182  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         00000000004005b4  000005b4
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         00000000004005c0  000005c0
       000000000000000f  0000000000000000   A       0     0     4
  [17] .eh_frame_hdr     PROGBITS         00000000004005d0  000005d0
       0000000000000034  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         0000000000400608  00000608
       00000000000000f4  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .jcr              PROGBITS         0000000000600e20  00000e20
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .dynamic          DYNAMIC          0000000000600e28  00000e28
       00000000000001d0  0000000000000010  WA       6     0     8
  [23] .got              PROGBITS         0000000000600ff8  00000ff8
       0000000000000008  0000000000000008  WA       0     0     8
  [24] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000028  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         0000000000601028  00001028
       0000000000000010  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000601038  00001038
       0000000000000008  0000000000000000  WA       0     0     1
  [27] .comment          PROGBITS         0000000000000000  00001038
       0000000000000035  0000000000000001  MS       0     0     1
  [28] .shstrtab         STRTAB           0000000000000000  000018cc
       000000000000010c  0000000000000000           0     0     1
  [29] .symtab           SYMTAB           0000000000000000  00001070
       0000000000000648  0000000000000018          30    47     8
  [30] .strtab           STRTAB           0000000000000000  000016b8
       0000000000000214  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

你可能感兴趣的:(LINUX_C笔记)