跳转至

ELF


更新于2023-11-24

可执行可链接格式(executable and linkable format, ELF)

使用ELF格式的文件

  • 可执行文件
  • 可重定位文件(Relocatable File),.o
  • 共享对象文件(Shared Object File), .so .a
  • coredump

组成

  • ELF头
  • 程序头表,描述若干个内存段
  • 节头表,描述若干个节
  • data entries
  • 符号
  • 重定位
  • 动态链接
  • 编码ELF解释器
  • 重定向入口
  • 数据动态链接信息

ELF头

ELF头(ELF Header)是每个ELF文件的第一个部分,包含了文件的基本信息和控制信息。它的结构定义了文件的类型、目标架构、入口点地址、程序头表和节头表的位置和大小等。

ELF头结构

ELF头的结构如下: - e_ident:一个16字节的数组,包含魔数、文件类型、目标架构等信息。 - e_type:文件类型,如可执行文件、重定位文件、共享对象文件等。 - e_machine:目标架构,如x86、x86-64、ARM等。 - e_version:ELF版本。 - e_entry:程序入口点的虚拟地址。 - e_phoff:程序头表在文件中的偏移。 - e_shoff:节头表在文件中的偏移。 - e_flags:与处理器相关的标志。 - e_ehsize:ELF头的大小。 - e_phentsize:程序头表中每个条目的大小。 - e_phnum:程序头表中的条目数。 - e_shentsize:节头表中每个条目的大小。 - e_shnum:节头表中的条目数。 - e_shstrndx:节头字符串表的索引。

示例

以下是一个简单的ELF头表示例:

Bash
1
readelf -h a.out
输出示例:
Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
ELF Header:
    Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
    Class:                             ELF64
    Data:                              2's complement, little endian
    Version:                           1 (current)
    OS/ABI:                            UNIX - System V
    ABI Version:                       0
    Type:                              EXEC (Executable file)
    Machine:                           Advanced Micro Devices X86-64
    Version:                           0x1
    Entry point address:               0x400080
    Start of program headers:          64 (bytes into file)
    Start of section headers:          0x200 (bytes into file)
    Flags:                             0x0
    Size of this header:               64 (bytes)
    Size of program headers:           56 (bytes)
    Number of program headers:         9
    Size of section headers:           64 (bytes)
    Number of section headers:         29
    Section header string table index: 28

程序头

程序头表(Program Header Table)描述了一个可执行文件或共享对象文件的内存布局。每个程序头条目(Program Header Entry)定义了一个段(Segment),包括段的类型、文件中的位置、内存中的位置、大小、权限等信息。程序头表在程序加载时被操作系统用来将文件中的各个段映射到内存中。

程序头条目类型

常见的程序头条目类型包括: - PT_NULL:无效的条目 - PT_LOAD:可加载段 - PT_DYNAMIC:动态链接信息 - PT_INTERP:解释器路径 - PT_NOTE:附加信息 - PT_SHLIB:保留类型 - PT_PHDR:程序头表自身 - PT_TLS:线程局部存储段

示例

以下是一个简单的程序头表示例:

Bash
1
readelf -l a.out
输出示例:
Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Elf file type is EXEC (Executable file)
Entry point 0x400080
There are 9 program headers, starting at offset 64

Program Headers:
    Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
    PHDR           0x000040 0x00400040 0x00400040 0x0001c 0x0001c R   0x8
    INTERP         0x00005c 0x0040005c 0x0040005c 0x00013 0x00013 R   0x1
            [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
    LOAD           0x000000 0x00400000 0x00400000 0x001000 0x001000 R E 0x200000
    LOAD           0x001000 0x00601000 0x00601000 0x000004 0x000004 RW  0x200000
    DYNAMIC        0x000f98 0x00600f98 0x00600f98 0x0000d0 0x0000d0 RW  0x8
    NOTE           0x000070 0x00400070 0x00400070 0x000024 0x000024 R   0x4
    GNU_EH_FRAME   0x000f5c 0x00600f5c 0x00600f5c 0x000004 0x000004 R   0x4
    GNU_STACK      0x000000 0x00000000 0x00000000 0x000000 0x000000 RW  0x10
    GNU_RELRO      0x000f98 0x00600f98 0x00600f98 0x000068 0x000068 R   0x1

 Section to Segment mapping:
    Segment Sections...
     00     
     01     .interp 
     02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
     03     .init_array .fini_array .dynamic .got .data .bss 
     04     .dynamic 
     05     .note.ABI-tag .note.gnu.build-id 
     06     .eh_frame_hdr 
     07     
     08     .init_array .fini_array .dynamic .got 

节头

符号

重定位

动态链接

编码ELF解释器

名字 类型 说明
NULL
.interp PROGBITS
.note.gnu.pr[...] NOTE
.note.gnu.bu[...] NOTE
.note.ABI-tag NOTE
.gnu.hash GNU_HASH
.dynsym DYNSYM
.dynstr STRTAB
.gnu.version VERSYM
.gnu.version_r VERNEED
.rela.dyn RELA
.rela.plt RELA
.init PROGBITS
.plt PROGBITS 过程链接表
.plt.got PROGBITS
.plt.sec PROGBITS
.text PROGBITS 程序代码指令
.fini PROGBITS
.rodata PROGBITS 只读数据
.eh_frame_hdr PROGBITS
.eh_frame PROGBITS
.init_array INIT_ARRAY
.fini_array FINI_ARRAY
.dynamic DYNAMIC
.got PROGBITS
.data PROGBITS 已经初始化的全局变量和静态变量
.bss NOBITS 未初始化或初始化为0的全局变量和静态变量
.comment PROGBITS
.symtab SYMTAB
.strtab STRTAB 一个符号表存放程序中定义和引用的函数和全局变量信息;不包含局部变量信息
.shstrtab STRTAB
.debug 调试符号表;通过-g添加
.rel.text .text节中位置的列表;链接时,需要将修改这些位置
.rel.data 被模块引用和定义的所有全局变量的重定位信息
.line 源程序的行号和.text节中机器指令之间的映射,通过-g添加
strtab 字符串表;包含.symtab和.debug节中的符号表
.ctors 指向构造函数的指针
.dtors 指向析构函数的指针

text段

.txt .rodata .hash .dynsym .dynstr .plt .rel.got

data段

.data .dybanic .got.plt .bss

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#查询ELF文件的信息
readelf -a a.out
#查询节头表
readelf -S a.out
#查询程序头表
readelf -s a.out
#查询文件头数据
readelf -e a.out
#查询重定向入口
readelf -r a.out
#查询动态段
readelf -d a.out

符号

  • 模块定义被其他模块引用的全局符号。非静态函数和全局变量。
  • 模块引用其他模块定义的全局符号,这些符号也叫外部符号。其他模块的非静态函数和全局变量。
  • 模块内定义和引用的局部符号。static属性的函数和全局变量。

符号表

.systab节中包含ELF符号表

参考

ELF-WIKI