ELF文件系列第三篇ELF文件静态结构中的节
节概述
在ELF文件中可以包含很多“节”(section),所有这些“节”都记录在一张称为“节头表”(section header table)的数组里。节头表的每一个表项是一个 Elf32_Shdr 结构,通过每一个表项可以定位到对应的节。
在 ELF 文件头中, e_shoff 成员给出节头表在 ELF 文件中相对于文件开始处的偏移量;e_shnum 成员指明节头表中包含多少个表项;e_shentsize 成员指明了每一个表项的大小。
节头表数组中,某些表项的索引值被保留,有特殊的含义。ELF 文件的节头表中不会出现索引值为以下各值的表项:
名字 |
SHN_UNDEF |
SHN_LORESERVE |
SHN_LOPROC |
SHN_HIPROC |
SHN_ABS |
SHN_COMMON |
SHN_HIRESERVE |
|
---|---|---|---|---|---|---|---|---|
值 |
0 |
0xff00 |
0xff00 |
0xff1f |
0xfff1 |
0xfff2 |
0xffff |
SHN_UNDEF
该值被定义为 0,它表示一个未定义的、不存在的节的索引。尽管索引值 0 是一个未定义的保留值,但在节头表中的索引还是会从 0 开始, 0 号表项的意义将在后面说明。
SHN_LORESERVE:被保留索引号区间的下限。
SHN_LOPROC:为特定处理器定制节所保留的索引号区间的下限。
SHN_HIPROC:为特定处理器定制节所保留的索引号区间的上限。
SHN_ABS:此节中所定义的符号有绝对的值,这个值不会因重定位而改变。
SHN_COMMON:此节中所定义的符号是公共的,比如 FORTRAN COMMON 符号或者未分配的 C 外部变量。
SHN_HIRESERVE:被保留索引号区间的上限。
除 0 以外,节头表中所有保留的索引值都位于 SHN_LORESERVE ~SHN_HIRESERVE 范围之间。与索引值”0”不同,这些大数值的索引并不出现在节头表中。
通常,目标文件中含有众多的“节”,“节”区是文件中最大的部分,它们需要满足下列这些条件:
- ELf文件中的每一个节一定对应有一个节头,节头中有对节的描述信息;但有的节头可以没有对应的节,而只是一个空的头。
- 每一个节所占用的空间是连续的。
- 各个节之间不能互相重叠。
- 在ELF文件中,节与节之间可能会存在一些多余的字节,这些字节不属于任何节。
节头的结构
可以用以下这个数据结构体来描述节头。
typedef struct { // 下面一些数据类型的大小在第二篇中有介绍Elf32_Word sh_name;Elf32_Word sh_type;Elf32_Word sh_flags;Elf32_Addr sh_addr;Elf32_Off sh_offset;Elf32_Word sh_size;Elf32_Word sh_link;Elf32_Word sh_info;Elf32_Word sh_addralign;Elf32_Word sh_entsize;
} Elf32_Shdr;
各个成员的含义如下:
h_name:本节的名字。名字并不存储在这里,它仅是一个索引号,指向“字符串表”节中的某个位置,那里存储了一个节名字符串。
sh_type: 本节的类型。下表给出了所有的节类型。
名字 |
值 |
解释说明 |
SHT_NULL |
0 |
此值表明本节头是个无效的节头,它也没有对应的节。 |
SHT_PROGBITS |
1 |
本节所含有的信息的格式和含义都由程序来决定。 |
SHT_SYMTAB /SHT_DYNSYM |
2/11 |
这两类节都含有符号表,只能各包含一个这两种节。SHT_SYMTAB 提供的符号用于在创建ELF文件的时候编辑连接,在运行期间也有可能会用于动态连接 |
SHT_STRTAB |
3 |
本节是字符串表,ELF文件中可包含多个字符串表节 |
SHT_RELA |
4 |
重定位节,一个ELF文件可能含有多个重定位节 |
SHT_HASH |
5 |
本节包含一张哈希表,所有参与动态连接的ELF文件都必须要包含一个符号哈希表。目前,一个ELF文件中最多只能有一个哈希表 |
SHT_DYNAMIC |
6 |
动态连接信息。一个ELF文件中最多只能有一个 。 |
SHT_NOTE |
7 |
本节包含的信息用于以某种方式来标记本文件 |
SHT_NOBITS |
8 |
这一节的内容是空的,节并不占用实际的空间。 |
SHT_REL |
9 |
本节是一个重定位节 |
SHT_SHLIB |
10 |
此值是一个保留值,暂未指定语义。 |
SHT_LOPROC~SHT_HIPROC |
0x70000000~0x7fffffff |
SHT_LOPROC~SHT_HIPROC区间是为特殊处理器节类型的保留值。 |
SHT_LOUSER~SHT_HIUSER |
0x80000000~0xffffffff |
SHT_LOUSER~SHT_HIUSER,由应用程序自定义区间类型,是一段保留值。 |
sh_flags :本节的一些属性,由一系列标志比特位组成,以下是这些标志位的列表及含义。
名字 |
值 |
|
SHF_WRITE |
0x1 |
如果此标志被设置,表示本节所包含的内容在进程运行过程中是可写的。 |
SHF_ALLOC |
0x2 |
如果此标志被设置,表示本节内容在进程运行过程中要占用内存单元。 |
SHF_EXECINSTR |
0x4 |
如果此标志被设置,表示此节内容是指令代码。 |
SHF_MASHPROC |
0xf0000000 |
所有被此值所覆盖的位都是保留做特殊处理器扩展用的。 |
sh_addr:如果本节的内容需要映射到进程空间中去,此成员指定映射的起始地址;如果不需要映射,此值为 0。
sh_offset:指明了本节第一个字节相对于文件开头的偏移量。单位是字节。如果该节的类型为 SHT_NOBITS 的话,表明这一节的内容是空的,节并不占用实际的空间,这时 sh_offset 只代表一个逻辑上的位置概念,并不代表实际的内容。
sh_size:指明节的大小,单位是字节。如果该节的类型为 SHT_NOBITS,此值仍然可能为非零,但没有实际的意义。
sh_link: 此成员是一个索引值,指向节头表中本节所对应的位置。根据节的类型不同,本成员的意义也有所不同,具体见下表。
sh_info: 此成员含有此节的附加信息,根据节的类型不同,本成员的意义也有所不同。
sh_type | sh_link | sh_info |
SHT_DYNAMIC | 本节中项目的字符串表在节头表中相应的索引值 | 0 |
SHT_HASH | 本节中哈希表的符号表在节头表中相应的索引值 | 0 |
SHT_REL /SHT_RELA | 相应符号表在节头表中的索引值 | 本重定位节所应用到目标节在节头表中的索引值 |
SHT_SYMTAB/SHT_DYNSYM | 相关字符串表的节头索引 | 符号表中最后一个本地符号的索引值加 1 |
其它 | SHN_UNDEF | 0 |
sh_addralign
此成员指明本节内容如何对齐字节,即该节的地址应该向多少个字节对齐。也就是说,本节内容在进程空间中的映射地址 sh_addr 必须是一个向sh_addralign 对齐,即能被 sh_addralign 整除的值。目前,sh_addralign 只能取 0、1或者 2 的正整数倍。如果该值为 0 或 1,表明本节没有字节对齐约束。
sh_entsize
有一些节的内容是一张表,其中每一个表项的大小是固定的,比如符号表。对于这种表来说,本成员指定其每一个表项的大小。如果此值为 0 则表明本节内容不是这种表格。
索引值0节头项内容
下面说一下索引值为 0 的节头表项,它并不表达实际的内容,只是一个空的表项,内容见下表。
名字 | 值 | 意义 | 名字 | 值 | 意义 |
sh_name | 0 | 无名字 | sh_size | 0 | 无大小 |
sh_type | SHT_NULL | 非活动类型 | sh_link | SHN_UNDEF | 无节头表对应项 |
sh_flags | 0 | 无标志 | sh_info | 0 | 无附加信息 |
sh_addr | 0 | 无地址 | sh_addralign | 0 | 无对齐格式 |
sh_offset | 0 | 无文件内偏移量 | sh_entsize | 0 | 无表项大小 |
特殊节
在 ELF 文件中有一些特定的节是预定义好的,其内容是指令代码或者控制信息,这些节专门为操作系统使用。在构建可执行程序时,连接器(linker)可能需要把一些独立的目标文件和库文件连接在一起,在这个过程中,连接器要解析各个文件中的相互引用,调整某些目标文件中的绝对引用,并重定位指令码。每种操作系统都有自己的一套连接模型,但总的来说,不外乎静态和动态两类:
静态连接 :所有的目标文件和动态连接库被静态地绑定在一起,所有的符号都被解析出来。所创建的目标文件是完整的,运行时不依赖于任何外部的库。
动态连接 :所有的目标文件、系统共享资源以及共享库以动态的形式连接在一起,外部库的内容没有完整地拷贝进来。如果创建的是可执行文件的话,程序在运行的时候,在构建时所依赖的那些库必须在系统中能找到,把它们一并装载之后,程序才能运行起来。运行期间如何解析那些动态连接进来的符号引用,不同的系统有各自不同的方式。
动态连接过程所需要的信息由.dynsym、.dynstr、.interp、.hash、.dynamic、.rel、.rela、.got、.plt 等节提供。.init 和.fini 节用于进程的初始化和终止过程。
名字 |
类型 |
属性 |
|
.bss |
SHT_NOBITS |
SHF_ALLOC+SHF_WRITE |
包含未初始化的全局变量。可执行程序在开始运行的时候,系统会把这一段内容清零。但是,在运行期间的 bss 段是由系统初始化而成的,在ELF文件中.bss 节并不包含任何内容,其长度为 0,所以它的节类型为 SHT_NOBITS。 |
.comment |
SHT_PROGBITS |
无 |
本节包含版本控制信息。 |
.data .data1 |
SHT_PROGBITS |
SHF_ALLOC+SHF_WRITE |
|
这两个节用于存放程序中被初始化过的全局变量。在ELF文件中,它们是占用实际的存储空间的,与.bss 节不同。 | |||
.debug |
SHT_PROGBITS |
无 |
调试信息,内容格式没有统一规定。 |
.dynamic |
SHT_DYNAMIC |
SHF_ALLOC+[SHF_WRITE] | 本节包含动态连接信息 |
.dynstr |
SHT_STRTAB |
SHF_ALLOC |
含有用于动态连接的字符串,一般是那些与符号表相关的名字 |
.dynsym |
SHT_DYNSYM |
SHF_ALLOC |
此节含有动态连接符号表。 |
.fini |
SHT_PROGBITS |
SHF_ALLOC+SHF_EXECINSTR |
此节包含进程终止时要执行的程序指令。当程序正常退出时,系统会执行这一节中的代码。 |
.got |
SHT_PROGBITS |
SHF_ALLOC+SHF_WRITE |
此节包含全局偏移量表。 |
.hash |
SHT_HASH |
SHF_ALLOC |
本节包含一张符号哈希表。 |
.init |
SHT_PROGBITS |
SHF_ALLOC+SHF_EXECINSTR |
此节包含进程初始化时要执行的程序指令。当程序开始运行时,系统会在进入主函数之前执行这一节中的代码。 |
.interp |
SHT_PROGBITS |
[SHF_ALLOC] |
此节含有 ELF 程序解析器的路径名。 |
.line |
SHT_PROGBITS |
无 |
本节也是一个用于调试的节,它包含那些调试符号的行号,为程序指令码与源文件的行号建立起联系。其内容格式没有统一规定。 |
.note |
SHT_NOTE |
无 |
注释节详细描述 |
.plt |
SHT_PROGBITS |
SHF_ALLOC+SHF_EXECINSTR |
此节包含函数连接表。 |
.relname .relaname |
SHT_REL /SHT_RELA |
[SHF_ALLOC] |
重定位信息。注意,这两个节的名字中”name”是可替换的部分,执照惯例,对哪一节做重定位就把”name”换成哪一节的名字。比如,.text 节的重定位节的名字将是.rel.text 或.rela.text。 |
.rodata .rodata1 |
SHT_PROGBITS |
SHF_ALLOC |
|
本节包含程序中的只读数据,在程序装载时,它们一般会被装入进程空间中那些只读的段中去。 | |||
.shstrtab |
SHT_STRTAB |
无 |
本节是“节名字表”,含有所有其它节的名字。 |
.strtab |
SHT_STRTAB |
[SHF_ALLOC] |
本节用于存放字符串,主要是那些符号表项的名字。 |
.symtab |
SHT_SYMTAB |
[SHF_ALLOC] | 本节用于存放符号表。 |
.text |
SHT_PROGBITS |
SHF_ALLOC+SHF_EXECINSTR |
本节包含程序指令代码。 |
以点号”.”为前缀的节名字是为系统保留的。应用程序也可以构造自己的段,但最好不要取与上述系统已定义的节相同的名字,也不要取以点号开头的名字,以避免潜在的冲突。注意,目标文件中节的名字并不具有唯一性,可以存在多个相同名字的节。
ELF文件系列第三篇ELF文件静态结构中的节相关推荐
- [深度][PyTorch] DDP系列第三篇:实战与技巧
[深度][PyTorch] DDP系列第三篇:实战与技巧 转自:https://zhuanlan.zhihu.com/p/250471767 零. 概览 想要让你的PyTorch神经网络在多卡环境上跑 ...
- 深入理解javascript作用域系列第三篇
前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇--声明提升(hois ...
- C++之文件操作探究(三):写文件——二进制文件
相关博文:C++之文件操作探究(一):写文件--文本文件 相关博文:C++之文件操作探究(二):读文件--文本文件 相关博文:C++之文件操作探究(三):写文件--二进制文件 相关博文:C++之文件操 ...
- javascript面向对象系列第三篇——实现继承的3种形式
前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.开宗明义,继承是指在原有对象的基础上,略作修改,得到一个新的对象.javascript主要包括类式继承.原型继承和拷贝继承这三种 ...
- ROS系列教程三:roslaunch文件及参数服务器
一.标签简介 1.<launch> ... </launch> : 根标签,一般写在整个launch文件的头尾,斜杠/代表结束: 2.<node> :启动节点,如果 ...
- 初学Python——文件操作第三篇
一.引言 什么?有了第二篇文件操作还不够?远远不够!而且在读完第三篇文件操作还是不够.关于文件的操作,后续的学习中将不断学习新的操作方式,使用更加合适的方法. 进入正题,上一篇讲到,Python对文件 ...
- Python之路【第三篇】:文件操作
一.文件操作步骤 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 歌名:<大火> 演唱:李佳薇 作词:姚若龙 作曲:马奕强 歌词: 有座巨大的停了的时钟 倾倒在赶 ...
- UR机械臂+RG2机械手控制 学习及实际控制 系列第三篇-1
1.机械臂UR的控制包括两种,一种是通过终端控制 比较笨重不方便,用于测试使用,另一种是通过ros例程包,订阅位置信息控制机械臂的移动,moveit自动规划机械臂的路径,并躲过设置好的盒子(box) ...
- 【Windows编程】系列第三篇:文本字符输出
2019独角兽企业重金招聘Python工程师标准>>> 上一篇我们展示了如何使用Windows SDK创建基本控件,本篇来讨论如何输出文本字符. 在使用Win32编程时,我们常常要输 ...
最新文章
- Linux下多播的配置【十全十美】
- IntelliJ IDEA WEB项目的部署配置
- java poi 读取xlsx文件_使用POI读取xlsx文件(SXSSFWorkbook)
- 快速谱峭度matlab,一种基于快速谱峭度分析的泵潜在空化故障检测方法与流程
- 重磅!神策智能推荐获 2019 大数据“星河奖”
- 修改IIS7并发连接数目限制
- 【JDK源码】java.lang包常用类详解
- 数据库-null值处理及元数据
- RAC环境创建本地数据文件的解决方法
- 如何优雅的处理异常(java)
- (25)软件工程开发规范
- 自己动手写操作系统——开发环境搭建
- f1c100s 调试问题汇总
- Android 接入穿山甲SDK之激励视频广告
- CRC32绕过RAR密码
- GPU中实现反距离加权插值(IDW)
- jQuery学习之旅 Item1 选择器【一】
- Fortran简明自学手册
- Ubuntu14.04 64位+Python3.4环境下安装matplotlib的方法
- 耦合和解耦的概念解析!
热门文章
- zookeeper c api主备切换例子
- 计算广告(一)【Ad Click Prediction: a View from the Trenches】工程实践视角下的广告点击率预估
- 代码的好味道和坏味道之22种坏味道
- 一键清除maven仓库中下载失败的jar包
- java中substract,【vapor和evaporate都有蒸发的意思,那怎样区分它们
- ArcGIS教程:趋势分析
- 整理的5种真实的判断IE9浏览器方法
- acrobat pro dc 2015打开文件出现内容准备进度的解决方法
- 强化学习在人岗匹配系统中的应用
- 华为OceanStor全闪存技术论坛登陆上海滩:探寻智能时代闪存普惠