Skip to content

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头表示例:

shell
readelf -h a.out

输出示例:

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:线程局部存储段

示例 ​

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

shell
readelf -l a.out

输出示例:

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解释器 ​

ELF layout
名字类型说明
NULL
.interpPROGBITS
.note.gnu.pr[...]NOTE
.note.gnu.bu[...]NOTE
.note.ABI-tagNOTE
.gnu.hashGNU_HASH
.dynsymDYNSYM
.dynstrSTRTAB
.gnu.versionVERSYM
.gnu.version_rVERNEED
.rela.dynRELA
.rela.pltRELA
.initPROGBITS
.pltPROGBITS过程链接表
.plt.gotPROGBITS
.plt.secPROGBITS
.textPROGBITS程序代码指令
.finiPROGBITS
.rodataPROGBITS只读数据
.eh_frame_hdrPROGBITS
.eh_framePROGBITS
.init_arrayINIT_ARRAY
.fini_arrayFINI_ARRAY
.dynamicDYNAMIC
.gotPROGBITS
.dataPROGBITS已经初始化的全局变量和静态变量
.bssNOBITS未初始化或初始化为0的全局变量和静态变量
.commentPROGBITS
.symtabSYMTAB
.strtabSTRTAB一个符号表存放程序中定义和引用的函数和全局变量信息;不包含局部变量信息
.shstrtabSTRTAB
.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

shell
#查询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