首页 > 其他分享 >【ELF系列】一文手撕ELF文件

【ELF系列】一文手撕ELF文件

时间:2024-09-03 18:13:51浏览次数:12  
标签:文件 系列 一文 Section ELF Header Table 加载

一、ELF文件是什么

二、ELF可重定位文件
    2.1 .shstrtab和.strtab
    2.2 .rel.text和.symtab
    2.3 .text节

三、ELF可执行文件

四、 参考

原创 嵌入一下? 谦益行

在一文了解ECU软件刷写文件HEX和S19格式 (qq.com)中介绍汽车控制器的刷写软件的格式,不管是编译生成的目标软件格式是哪种,同时都会生成ELF文件,ELF文件是什么?下文将进行详细介绍:

一、ELF文件是什么

ELF(Executable Linkble Format)是一种Unix-like系统上的二进制文件格式标准。
ELF标准中定义的采用 ELF 格式的文件分为4类:

ELF文件格式提供了两种不同的视角,在汇编器和链接器看来,ELF文件是由Section Header Table描述的一系列Section的集合;而执行一个ELF文件时,在加载器(Loader)看来,它是由Program Header Table描述的一系列Segment的集合 ,如下所示:

左边是从汇编器和链接器的视角来看这个文件,开头的 ELF Header 描述了体系结构和操作系统等基本信息,并指出 Section Header Table 和 Program Header Table 在文件中的什么位置,Program Header Table在汇编和链接过程中没有用到,所以是可有可无的,Section Header Table 中保存了所有 Section 的描述信息。

右边是从加载器的视角来看这个文件,开头是 ELF Header,Program Header Table 中保存了所有 Segment 的描述信息,Section Header Table 在加载过程中没有用到,所以是可有可无的。注意 Section Header Table 和 Program Header Table 并不是一定要位于文件开头和结尾的,其位置由 ELF Header 指出,上图这么画只是为了清晰。

我们在汇编程序中用 .section 声明的 Section 会成为目标文件中的Section,此外汇编器还会自动添加一些 Section(比如符号表)。

Segment 是指在程序运行时加载到内存的具有相同属性的区域,由一个或多个 Section 组成,比如有两个 Section 都要求加载到内存后可读可写,就属于同一个 Segment。有些 Section 只对汇编器和链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何Segment。

目标文件需要链接器做进一步处理,所以一定有 Section Header Table;可执行文件需要加载运行,所以一定有 Program Header Table;而共享库既要加载运行,又要在加载时做动态链接,所以既有Section Header Table 又有 Program Header Table。

二、ELF可重定位文件

下面用 readelf 工具读出目标文件 max.o 的 ELF Header 和 Section Header Table,然后我们逐段分析。

接下来我们来看 Section Header Table 格式

从 Section Header 中读出各 Section 的描述信息,其中:

.text 和 .data 是我们在汇编程序中声明的 Section,而其它 Section 是汇编器自动添加的。

Addr是这些段加载到内存中的地址(我们讲过程序中的地址都是虚拟地址),加载地址要在链接时填写,现在空缺,所以是全0。

Off和Size两列指出了各Section的文件地址,比如.data从文件地址0x60开始,一共0x38个字节,回去翻一下程序,.data中定义了14个4字节的整数,一共是56个字节,也就是0x38个。

根据以上信息可以描绘出整个目标文件的布局。

这个文件不大,我们直接用hexdump或者使用010 Editor工具把目标文件的字节全部打印出来看,如下所示:

2.1 .shstrtab和.strtab

.shstrtab.strtab 这两个 Section 中存放的都是 ASCII 码:

可见 .shstrtab中保存着各Section的名字, .strtab中保存着程序中用到的符号的名字 。每个名字都是以’\0’结尾的字符串。
我们知道,C语言的全局变量如果在代码中没有初始化,就会在程序加载时用0初始化。这种数据属于.bss段,在加载时它和.data段一样都是可读可写的数据,但是在ELF文件中 .data 段需要占用一部分空间保存初始值,而 .bss 段则不需要。
也就是说,.bss 段在文件中只占一个 Section Header 而没有对应的 Section,程序加载时 .bss 段占多大内存空间在 Section Header 中描述。在我们这个例子中没有用到 .bss 段,以后我们会看到这样的例子。

2.2 .rel.text和.symtab

我们继续分析 readelf 输出的最后一部分,是从 .rel.text .symtab 这两个 Section 中读出的信息。

.rel.text 告诉链接器指令中的哪些地方需要重定位,我们在下一节讨论。

.symtab 是符号表。Ndx 列是每个符号所在的 Section 编号,例如 data_items 在第 3 个 Section 里(也就是 .data ),各 Section 的编号见 Section Header Table 。Value 列是每个符号所代表的地址,在目标文件中,符号地址都是相对于该符号所在Section的相对地址,比如 data_items 位于 .data 段的开头,所以地址是0,_start 位于 .text 段的开头,所以地址也是0,但是 start_loop 和 loop_exit 相对于 .text 段的地址就不是0了。从 Bind 这一列可以看出 _start 这个符号是 GLOBAL 的,而其它符号是 LOCAL 的,GLOBAL 符号是在汇编程序中用 .globl 指示声明过的符号。

2.3 .text节

通过使用 objdump 工具可以把程序中的机器指令进行反汇编(Disassemble),得到其汇编代码,如下所示:

三、ELF可执行文件

先看可执行文件header的变化:

在看section header的变化:

.text和.data的加载地址分别改成了 0x08048074 和 0x080490a0 。

.bss段没有用到,所以被删掉了。

.rel.text段就是用于链接过程的,链接完了就没用了,所以也删掉了。

在看多出来的两个program header

多出来的Program Header Table描述了两个Segment的信息。

.text段和前面的 ELFHeader、Program Header Table 一起组成一个 Segment(FileSiz指出总长度是0x9e);

.data段组成另一个Segment(总长度是0x38)。

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,也正是_start符号的地址和程序的入口地址。

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

四、 参考

[1] ELF文件详解—初步认识_code&poetry的博客-CSDN博客
[2] 词法分析、语法分析、语义分析 - JackYang - 博客园 (cnblogs.com)

本文引自:C编译过程 以及 ELF文件(学习笔记),作者: 嵌入一下?

标签:文件,系列,一文,Section,ELF,Header,Table,加载
From: https://www.cnblogs.com/o-O-oO/p/18394327

相关文章

  • 阿里云数据库使用感受--操作界面有点眼花缭乱 --3年的使用感受与反馈系列
    此篇是一个系列,专门剖析笔者在3年使用阿里云数据库中遇到的问题,并针对这些问题进行假设性的改进建议,大部分内容为真正使用过产品和服务后的感触,带有个人的一些主观观点,这也是不可避免的。此篇是本系列的第一篇,主要针对阿里云数据库系列产品中的产品界面进行一个使用后的主观的反馈......
  • 一文迅速上手 ESP32 bluedroid 蓝牙从机开发
    前言该博客主要针对希望迅速上手ESP32蓝牙从机开发人员,因此,很多蓝牙技术细节知识并不会进行介绍,仅仅介绍我认为需要了解的API函数和回调内容。本文主要是基于gatt_serverdemo来微调进行进行讲解。代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<i......
  • LangChain4j系列:带你入门LangChain4j框架
    LangChain4j框架是什么?LangChain4j于2023年初在ChatGPT的炒作中开始开发。思想来源于Python和JavaScriptLLM库,并加入创新思想,开发一款Java语言版本的LLMs库。LangChain4j的目标是简化Java应用程序集成LLMs所以LangChain4j就是一个通过抽象统一API、提供便捷可用......
  • arXiv最热NLP大模型论文:一文读懂大模型的prompt技术
    引言:探索高效提示方法的重要性在人工智能领域,大语言模型(LLMs)已经成为了自然语言处理(NLP)任务的重要工具。随着模型规模的不断扩大,如何高效地利用这些模型,尤其是在资源有限的情况下,成为了一个迫切需要解决的问题。提示方法(Prompting)作为一种新兴的范式,能够通过简洁的指令引导模型完成......
  • 阿里云数据库使用感受--客户服务问题深入剖析与什么是廉价客户 --3年的使用感受与反馈
    此篇是一个系列,专门剖析笔者在3年使用阿里云数据库中遇到的问题,并针对这些问题进行假设性的改进建议,大部分内容为真正使用过产品和服务后的感触,带有个人的一些主观观点,这也是不可避免的。此篇是本系列的第二篇,主要针对阿里云数据库系列产品中的产品客服服务长达3年的沟通交流产生的......
  • 芝士AI(paperzz)|论文写作必备指南,一文讲清楚,大学生进!
      众多资深研究人士达成一致的看法是,论文的最艰难一步往往在于启动这个过程。许多学子常常发现自己在精神上并未做好准备来面对这个挑战,因为大多数培训侧重于研究方法和进行实际研究,而很少涉及如何娴熟地书写论文这一方面。这种心理准备上的不足可能成为阻碍他们迈出第一步......
  • 【研判系列】研判事件汇总
    原创零漏安全1、木马后门程序ChopperWebshell检测2、webshellcaidao_client,木马后门程序ChopperWebshell检测3、木马后门程序ChopperWebshell检测4、webshellcaidao_client5、蚁剑webshell通信行为6、apachelog4j2远程代码执行漏洞7、sql注入oraclefuncc......
  • 一文教你10分钟快速玩转魔乐社区
    8月底,魔乐开发者社区上线,引起开发者的关注。据了解,在魔乐社区的平台上,每一位开发者都能找到所需的资源和工具,无论是数据集、模型库还是开发工具,魔乐社区都将提供一站式服务。那该怎么玩呢?来来来,跟随我的脚步,教你10分玩转魔乐开发者社区(modelers.cn)。魔乐社区的基础信息:概念:魔......
  • 科研绘图系列:python语言散点图和密度分布图(scatter & density plot)
    介绍散点图(ScatterPlot)是一种数据可视化技术,用于显示两个变量之间的关系。它通过在直角坐标系中绘制数据点来展示数据的分布和趋势。每个数据点在横轴(X轴)和纵轴(Y轴)上都有一个坐标值,分别对应两个变量的数值。密度分布图是一种统计图表,用于表示数据的分布情况。它通常用于......
  • 科研绘图系列:python语言tSNE散点图(tSNE scatter plot)
    介绍t-SNE(t-distributedStochasticNeighborEmbedding)是一种用于高维数据可视化的非线性降维技术。它由LaurensvanderMaaten和GeoffreyHinton在2008年提出。t-SNE的主要目的是将高维空间中的数据点映射到二维或三维空间中,同时尽可能保持数据点之间的相对距离,使得相......