前言

ELF,全称Executable and Linking Format,旨在为不同操作环境下提供一组通用的ABI(二进制接口),也是目前Unix和类Unix操作系统使用的标准二进制格式。ELF文件格式定义了可执行程序的静态文件格式,包括文件信息头、段及节等结构,并约定了程序在运行时,程序文件的内容是如何动态加载到内存中以及起始运行地址。

ELF文件类型

ELF文件从字面的意义上来讲,描述的是可执行和链接格式,因此包括可执行文件、目标文件以及动态库都可以采用ELF文件格式进行存储。ELF标准中定义的ELF文件类型主要有以下四种:

ELF文件类型

类型标记

说明

可重定位文件

ET_REL

可重定位目标文件通常是还未被链接到可执行程序的一段位置独立的代码,如.o文件

可执行文件

ET_EXEC

即可运行的程序,是一个进程开始执行的入口,平时使用的shell、find等工具都属于此类

共享目标文件

ET_DYN

动态可链接目标文件,即共享库,会在程序运行时被装载并连接到程序的进程镜像中,如.so文件

核心转储文件

ET_CORE

在程序崩溃或者进程传递了一个SIGSEGV信号时,会在核心文件中记录整个进程的镜像信息,如Linux的进程Coredump文件

Linux下可以使用file命令来查看不同ELF文件类型的格式:

eigen后缀文档的python基本操作 eif后缀文件_可执行文件

ELF文件的内容

一个标准的ELF文件通常包含了如下几类信息:

  • 文件头信息:描述关于文件的整体信息,包括版本号、系统类型以及文件类型等信息;
  • 指令和数据:由编译器或汇编器生成的二进制指令和数据;
  • 符号信息:该模块中定义的全局符号,以及从其它模块导入的或者有链接器定义的符号;
  • 重定位信息:记录文件中符号的重定位信息,对于后续要链接的ELF文件,链接器会使用重定位信息对目标代码进行调整;
  • 调试信息:目标代码中与链接无关但会被调试器使用到的其它信息,包括源代码文件和行号信息、本地符号以及目标代码使用的数据结构描述信息。

为了管理上面的信息,ELF文件通常会将这些信息按照不同的属性,以段(Segment)或节(Section)的形式进行存储,常用的段或节包括代码段、数据段、.bss段等。

ELF文件与程序

在实际的开发过程中,我们可能更加关心程序中使用的代码和数据在ELF文件中是如何存储的,对应于上面的指令和数据部分。如下是一个简单的程序被编译成ELF文件后的结构:

eigen后缀文档的python基本操作 eif后缀文件_可执行文件_02

程序代码被编译后主要分为两种类型的数据:程序指令和程序数据,其中程序指令通常存储于代码段,程序数据按照其数据属性通常存储于数据段、.bss段等区域:

  • 代码段(.text):存储程序源代码编译后的机器指令;
  • 数据段(.data):存储已初始化全局变量和局部静态变量;
  • 未初始化数据段(.bss):存储未初始化的或初始化为0的全局变量和局部静态变量。

其它可执行文件格式

除了ELF文件格式外,还有一些其它的可执行文件格式:

  • a.out:Unix系统早期使用的可执行文件格式,尽管历史悠久,现在已经基本不使用这种格式,但是Linux编译时仍然会使用a.out作为程序的默认名称,算是一种致敬吧;
  • .COM:DOS时代使用的文件格式,学生时代如果玩过8086汇编,应该都会遇到;
  • PE(Portable Executable):Windows平台使用的可执行文件格式,典型文件后缀名.exe

相关参考

  • 《程序员的自我修养——链接、装载与库》
  • 《链接器和加载器》
  • 《Linux二进制分析》
  • 《ELF Object File Format》
  • 《ELF-64 Object File Format》