一、ELF概述

1、ELF的定义

ELF(Executable and Linkable Format)文件是一种目标文件格式,常见的ELF格式文件包括:可执行文件、可重定位文件(.o)、共享目标文件(.so)、核心转储文件等。

ELF主要用于Linux平台,Windows下是PE/COFF格式。

2、ELF文件的结构

一个完整的ELF文件一般会包括如下几个内容:ELF头、Section头、Program头和Section。

其中由Section头组成的集合称为Section头表,由Program头组成的集合称为Program头表。注意:数个连续的头称之为头表,头表是虚拟出来的定义,文件中不存在头表,只有头。

一个Section头指向一个Section,Section头中包括所指向Section的名字、类型、其在ELF文件中的偏移地址、大小等信息。

一个Program头指向一个Segment,Program头中包括所指向Segment的类型、其在ELF文件中的偏移地址、大小,映射到内存的虚拟地址等信息。一个Segment由一系列连续的Section构成,连续的Section拥有相同的权限,如只读、读写、可读可执行等;

一个ELF头内包含有:Section头表的在ELF文件中的偏移地址、单个Section头的大小、Section头表中Section头的个数;Program头表的在ELF文件中的偏移地址、单个Program头的大小、Program头表中Program头的个数;该ELF文件的类型,若是可执行文件的话,还包含的有程序的入口地址。

3、头的表示方法及其含义

1)变量及其大小:

2)ELF头


  1. #define EI_NIDENT 16
  2. struct Elf32_Ehdr //共52个字节 //Ehdr表示ELF header
  3. {
  4.   unsigned char  e_ident[EI_NIDENT];
  5.   Elf32_Half e_type; //类型包括:可执行文件、可重定向文件、共享目标文件等
  6.   Elf32_Half e_machine; //有X86、arm之类
  7.   Elf32_Word e_version;
  8.   Elf32_Addr e_entry; //可执行程序的入口地址
  9.   Elf32_Off e_phoff; //Program头表的偏移地址
  10.   Elf32_Off e_shoff; //Section头表的偏移地址
  11.   Elf32_Word e_flags;
  12.   Elf32_Half e_ehsize; //本结构体的size
  13.   Elf32_Half e_phentsize; //单个Program头的size
  14.   Elf32_Half e_phnum; //Segment头表中Segment头的个数
  15.   Elf32_Half e_shentsize; //单个Section头的szie
  16.   Elf32_Half e_shnum; //Section头表中Section头的个数
  17.   Elf32_Half e_shstrndx; //储存Section名字集合的Section的下标,指".shstrtab"的下标
  18. };

2)Section头


  1. struct Elf32_Shdr //共40个字节 //Shdl表示Section header
  2. {
  3.     Elf32_Word sh_name; //所指向Section的名字,如".text"、".data"、".bss"等
  4.     Elf32_Word sh_type; //所指向Section的类型,如:符号表、字符串表等
  5.     Elf32_Word sh_flags;
  6.     Elf32_Addr sh_addr;
  7.     Elf32_Off sh_offset; //所指向Section在ELF文件中的偏移量
  8.     Elf32_Word sh_size; //所指向Section的size
  9.     Elf32_Word sh_link; //和其关联的Section头的下标索引
  10.     Elf32_Word sh_info;
  11.     Elf32_Word sh_addralign; //字节对齐
  12.     Elf32_Word sh_entsize;
  13. };

3)Program头


  1. struct Elf32_phdr //32个字节 //phdr表示Program header
  2. {
  3.     Elf32_Word p_type; //如PT_LOAD表示,对应Segment可被加载到内存中
  4.     Elf32_Off p_offset; //Segment在ELF文件中的偏移量
  5.     Elf32_Addr p_vaddr; //Segment映射到内存后的虚拟地址
  6.     Elf32_Addr p_paddr; //Segment映射到内存后的物理地址,此时与虚拟地址相同
  7.     Elf32_Word p_filesz; //Segment在ELF文件中占用的size
  8.     Elf32_Word p_memsz; //Segment映射到内存后占用的size
  9.     Elf32_Word p_flage; //读、写、执行权限
  10.     Elf32_Word p_align; //字节对齐,p_vaddr和p_paddr对p_align取模后为0
  11. };

更详细内容请参考:ELF文件格式解析

4、实例解析

可执行文件中Program头表是必须的,可重定向文件(.o)中Section头表是必须的,共享目标文件(.so)中两者都是必须的。

1)可重定向文件分析

ELF头信息如下所示:

在此文件中,可看到其类型为REL, 即可重定向文件。其中Program头的个数为0,Section头的个数为8个,没有程序入口地址。

下图是8个Section头的详细信息:

其中Addr在此处被填充为了0的原因是,其目前并不需要被加载到内存中,在链接的时候才会被填充。

根据上述各Section的偏移量及size可推断出其在该可重定向文件中空间布局,如下表所示:

偏移量(Off) 大小(size) Section 备注
0x0 0x34 ELF头 0x34表示十进制的52,刚好为ELF头的大小
0x34 0x2a .text  
0x60 0x38 .data  
0x98 0x0 .bss  
0x98 0x30 .shstrtab  
0xc8 0x140 Section头表 一个Section头的大小为40个字节,共8个头,大小为0x140
0x208 0x80 .symtab  
0x288 0x28 .strtab  
0x2b0 0x10 .rel.text  

下面详述上面几种类型的Section:

Ⅰ .shstrtab

.shstrtab中存放着各个Section的名字。

Ⅱ .strtab

.symtab中存放着程序中用到的符号的名字。

Ⅲ .bss

程序中未初始化的全局变量都会被归类到bss段,并在程序加载的时候被初始化为0。

在加载.bss的时候和.data一样,都属于可读可写的数据,但在ELF文件中.data需要占用一段内存空间来保存变量的初始化值,而.bss却不需要。

也就是说,.bss只占用一个Section头的大小,而不需要对应的Section。如上表中可以看出.bss所描述Section的size为0。

Ⅳ .rel.text

.rel.text用于告诉链接器,哪些地方需要重定向。

Ⅴ .symtab

.symtab内存放着程序中用到的符号,包括变量符号、函数符号,如printf、main等。

.symtab有如下定义:


  1. struct Elf32_sym //
  2. {
  3.     Elf32_Word st_name; //符号的名字
  4.     Elf32_Addr st_value; //符号相对于其所在Section偏移的相对地址
  5.     Elf32_Word st_size; //符号的size
  6.     unsigned char st_info; //低四位表示符号的作用范围(全局或局部),高四位表示符号的类型(变量、函数等)
  7.     unsigned char st_other;
  8.     Elf32_Half st_shndx; //该符号的值在哪个Section下存储
  9. };

实例:

以上图中的data_items为例,其Ndx为3,表示其在第3个Section,即.data。data_items的value值为00000000,表示其相对于.data的偏移地址为0,即data_itms在.data的开头。

_start的value也为00000000,表示其在.text的开头,也即整个代码的入口是_start。

2)可执行文件分析

可执行文件的ELF头信息如下所示:

相对于可重定向文件来说,其类型变为了EXEC,少了两个Section header,多了两个Program头,并且有可执行程序的入口地址。

6个Section头如下所示:

从图中可以看出,.text和.data的Addr不再为0,有了实际的值,这便是在链接过程中装载上的。

.bss段因为没有使用到,所以被删除掉了。

.rel.text在链接之后,便完成了自己的使命,也就被删除掉了。

根据上述各Section的偏移量及size可推断出其在该可执行文件中空间布局,如下表所示:

偏移量(Off) 大小(size) Section 备注
0x0 0x34 ELF头 0x34表示十进制的52,刚好为ELF头的大小
0x34 0x40 Program头表 一个Program头的大小为32字节,共2个头,大小为0x40
0x74 0x2a .text  
0xa0 0x38 .data  
0xd8 0x27 .shstrtab  
0x100 0xf0 Section头表 一个Section头的大小为40个字节,共6个头,大小为0xf0
0x1f0 0xa0 .symtab  
0x290 0x40 .strtab  

2个Program头如下所示:

结合Program头和Section的空间布局表可以看出,ELF头、Program头表和Section头表共同组成了第一个Segment;.data单独组成了另一个Segment。

VirtAddr列指出第一个Segment加载到虚拟地址0x0804 8000(注意在x86平台上后面的PhysAddr列是没有意义的),第二个Segment加载到地址0x0804 90a0。

Flg列指出第一个Segment的访问权限是可读可执行,第二个Segment的访问权限是可读可写。

最后一列Align的值0x1000(4K)是x86平台的内存页面大小。在加载时要求文件中的一页对应内存中的一页,对应关系如下图所示:

这个可执行文件很小,总共也不超过一页大小,但是两个Segment必须加载到内存中两个不同的页面,因为MMU的权限保护机制是以页为单位的,一个页面只能设置一种权限。

此外还规定每个Segment在文件页面内偏移多少加载到内存页面仍然偏移多少,比如第二个Segment在文件中的偏移是0xa0,在内存页面0x0804 9000中的偏移仍然是0xa0,所以是从0x0804 90a0开始,这样规定是为了简化链接器和加载器的实现。

从上图也可以看出.text段的加载地址应该是0x0804 8074,这也正是程序的入口地址。

原来目标文件符号表中的Value都是相对地址,现在都改成绝对地址了。此外还多了三个符号__bss_start、_edata和_end,这些是在链接过程中添进去的,加载器可以利用这些信息把.bss段初始化为0。

5、可执行ELF文件的装载过程

​

附录

1)Section与Segment的英文含义

section和segment都有部分的意思,但

section指的“部分”是不同质的,如:The TOEFL is divided into three sectiond, namely listening, structure and reading.在这里托福考试是由三部分组成的,这三部分是不一样的,即不同质的。

而segment指的“部分”是同质的,如:I want the middle segment of the rope. 我想要中间那段绳...

2)段错误(Segment Error)

当程序试图访问不允许访问的内存位置,或试图以不允许的方式访问内存位置(例如尝试写入只读位置,或覆盖部分操作系统)时会发生段错误。

常见的段错误,包括:

1)使用未经初始化及或已经释放的指针地址

2)访问受系统保护的内存地址

3)写入只读的内存地址

4)数组越界

5)堆栈溢出

参考资料:

1.ELF文件解析和加载(附代码)

2.ELF文件格式解析(完)

3.ELF文件详解—初步认识

</article>

[转帖]ELF文件详解的更多相关文章

  1. Linux环境下:程序的链接, 装载和库[ELF文件详解]

    编译过程拆解 预处理处理生成.i文件, .i文件还是源码文件 将所有的宏定义#define展开. 处理#if, #else, #endif等条件编译指令 处理#include, 原地插入文件 cpp ...

  2. ELF文件解析(二):ELF header详解

    上一篇讲了ELF文件的总体布局,以及section和segment的概念.按照计划,今天继续讲 ELF header. 讲新的内容之前,先更正一个错误:上一篇中讲section header tabl ...

  3. Angular Npm Package.Json文件详解

    Angular7 Npm Package.Json文件详解   近期时间比较充裕,正好想了解下Angular Project相关内容.于是将Npm官网上关于Package.json的官方说明文档进行了 ...

  4. Android逆向之旅---SO(ELF)文件格式详解(转)

    第一.前言 从今天开始我们正式开始Android的逆向之旅,关于逆向的相关知识,想必大家都不陌生了,逆向领域是一个充满挑战和神秘的领域.作为一名Android开发者,每个人都想去探索这个领域,因为一旦 ...

  5. Android逆向之旅---SO(ELF)文件格式详解

    第一.前言 从今天开始我们正式开始Android的逆向之旅,关于逆向的相关知识,想必大家都不陌生了,逆向领域是一个充满挑战和神秘的领域.作为一名Android开发者,每个人都想去探索这个领域,因为一旦 ...

  6. web.xml文件详解

      web.xml文件详解 Table of Contents 1 listener. filter.servlet 加载顺序 2 web.xml文件详解 3 相应元素配置 1 listener. f ...

  7. Linux中/proc目录下文件详解

    转载于:http://blog.chinaunix.net/uid-10449864-id-2956854.html Linux中/proc目录下文件详解(一)/proc文件系统下的多种文件提供的系统 ...

  8. SUBLIME TEXT 2 设置文件详解

    SUBLIME TEXT 2 设置文件详解 Preferences.sublime-settings文件: // While you can edit this file, it’s best to ...

  9. [转]AndroidManifest.xml文件详解

    转自:http://www.cnblogs.com/greatverve/archive/2012/05/08/AndroidManifest-xml.html AndroidManifest.xml ...

  10. delphi 资源文件详解

    delphi资源文件详解 一.引子: 现在的Windows应用程序几乎都使用图标.图片.光标.声音等,我们称它们为资源(Resource).最简单的使用资源的办法是把这些资源的源文件打入软件包,以方便 ...

随机推荐

  1. 启动多个redis进程

    启动时指定端口 启动时指定端口可在一台服务器启动多个redis进程 cd /opt/work/redis/bin./redis-server ../conf/redis.conf --port 638 ...

  2. 3大方面升级华为云CCE集群体验,助力集群高效运维管理

    本文分享自华为云社区<华为云从心打造CCE集群升级体验,助力集群高效运维管理>,作者:云容器大未来 . 在云原生时代浪潮的推动下,Kubernetes的发展日新月异,更新的集群版本可以带来 ...

  3. 【好书推荐】《Python黑魔法指南》-附高清PDF版

    摘要:<Python 黑魔法手册.pdf >作者(明哥)是一个从事云计算多年的 Python 重度用户,它把自已多年的 Python 编码经验整理成小册子,没有长篇大论,半天就能全能掌握, ...

  4. 华为云原生数据仓库GaussDB(DWS)深度技术解读:融、快、大、稳、易

    摘要:云原生数据仓库GaussDB(DWS)架构师应邀为大家解读数仓深度技术. "云原生"在2020年成为备受瞩目的热词,云原生在确保企业数字化转型中资源快速供给.按需使用的同时, ...

  5. 提升漏洞修复率,DevSecOps真的很有一套

    摘要:在业务应用交付规模不断扩大.交付速度不断提高.开发运营场景一体化的大环境下,安全问题你真的重视么? 本文分享自华为云社区<HDC.Cloud2021 | 提升漏洞修复率,DevSecOps ...

  6. Kafka 源码解析:Server 端的运行过程

    摘要:Kafka网络模块之Server端,介绍Server端启动.接收请求和处理请求的过程. 本文分享自华为云社区<Kafka网络模块-Server端>,原文作者:中间件小哥 . Sock ...

  7. JavaScript继承的实现方式:原型语言对象继承对象原理剖析

    面向对象编程:继承.封装.多态. 对象的继承:A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法.这对于代码的复用是非常有用的. 在经典的面向对象语言中,您可能倾向于定义类对象,然后您 ...

  8. DarkMode(3):sass函数实实现深色模式操作

    上文<DarkMode(2):深色模式解决方案--css颜色变量实现Dark Mode>,完全基于样色抽离变量,然后使用预处理其,生成两套样式.切换样式文件. sass自定义函数与mixi ...

  9. 火山引擎DataTester:小改动带来大收益,A/B实验助力幸福里APP精准优化

      幸福里APP是抖音集团旗下开发运营的集内容.社区.工具于一体的房产信息综合平台,基于个性化推荐引擎向用户推荐优质的房产内容房源信息.本文将介绍幸福里APP应用火山引擎A/B测试DataTester ...

  10. Solon v1.11.3 发布,第101个发布版本喽

    一个更现代感的 Java 应用开发框架:更快.更小.更自由.没有 Spring,没有 Servlet,没有 JavaEE:独立的轻量生态.主框架仅 0.1 MB. @Controller public ...