dcb是什么意思(详细解释可执行文件的结构)
admin
2023-08-26 06:23:50

程序员编写的程序需要翻译成可执行文件,然后才能被操作系统执行。对于用C语言编写的程序,这个翻译过程包括预编译、编译、汇编和链接。

在PC平台上,不同的操作系统可能有不同的可执行文件格式。

对于Windows操作系统:常见的可执行文件格式是PE格式,例如exe文件就是PE格式。

对于Linux和Unix操作系统:可执行文件格式是ELF格式,比如常见的/bin/bash就是ELF格式。

PE格式和ELF格式很相似,因为它们都是COFF文件格式的变体,其他很多可执行文件格式都是COFF文件格式的变体。

本文主要阐述ELF文件的结构,其他可执行文件格式的概念都差不多,只是细节有些不同。

下面是C语言的代码,文件名是SimpleSection。c .本文围绕这个代码片段阐述ELF文件的结构。

intprintf(const char *格式,);intglobal _ init _ var=84//全局变量intglobal _ uninit _ var//全局未初始化变量Voidfunc1 (inti) {printf ('%d \ n 'I);} int main(void){ static intstatic _ var=85;//静态变量Static _ var 2;//静态inta=1;intbfunc 1(static _ var static _ var 2 a b);return1}

ELF文件类型

不仅可执行文件是ELF格式,还有可重定位文件和共享库文件,所以ELF文件类型可以分为以下三种:

可重定位目标文件:

上面提到的SimpleSection.c文件经过编译汇编生成SimpleSection.o文件。这个文件是一个可重定位的目标文件,它包含代码和数据。这个目标文件没有被链接,所以它可以与其他目标文件或共享库链接成一个可执行文件,链接过程将被重新定位。

您可以执行文件简化。o命令来验证这个文件的类型。命令结果如下所示:

SimpleSection.o:ELF64位LSBrelocatable,x86-64,版本1(SYSV),notstripped

可执行文件:

这样的文件可以直接被操作系统执行,比如/bin/bash。

您可以执行[file/bin/bash]命令来验证这个文件的类型。命令结果如下所示:

/bin/bash : elf 64-bit LSBexecutable,x86-64,版本1(SYSV),动态链接(usessharedlibs),forGNU/Linux2.6.32,BuildID[sha1]=8 BD 6b 05295658d 71 a9 ff 4 eed 7 ca e55609 a 703623,已剥离.

共享目标文件:

包含代码和数据,有两种使用场景。

1.链接器将这类文件与其他可重定位的目标文件和共享目标文件(即共享库)链接起来,生成新的目标文件。

2.动态链接器将这类文件与可执行文件结合起来,实现运行时链接。

执行命令[file/usr/lib64/ld-2.17.so]来验证该文件的类型。命令结果如下所示:

/usr/lib 64/LD-2.17 . so : elf 64-bit LSBsharedobject,x86-64,版本1(SYSV),动态链接,BuildID[sha1]=a 9980 cf 253 c 79740 e 69 f 70 dcb 8 FEA 7 b 8 C2 f 641 b 5,notstripped

ELF文件类结构

下图显示了ELF文件结构。

ELF文件结构

从上图可以看出,一个ELF文件由一个ELFHeader、一个Sectionheadertable和多个sections组成。

ELF文件头(ELFHeader):包含了整个文件的基本属性,比如段表的起始位置,段表的大小,ELF文件的版本,目标机器型号,程序入口地址等等。

节表(Sectionheadertable):包括所有段的属性信息,描述每个段的名称、段的长度、段在文件中的起始位置以及读写权限。

节(Section):ELF文件的核心内容,一个ELF文件包含许多节,不同类型的节包含不同的内容。例如,文本表示包含代码的代码段。

不同的ELF文件类型(可重定位目标文件、共享库目标文件、可执行文件)包含不同的部分,但至少包括代码和数据部分。

在编译时,可以增加编译选项来控制生成或者去掉某些节,通常这些节都是辅助作用,可有可无。

ELF文件头(ELFHeader):

可以通过readelf-h来查看文件头信息,如下图所示


ELF文件头信息

如上图所示,文件头包括了很多属性,下面逐个阐述各个属性。

Magic:ELF文件的魔幻数。

通过Magic不光可以指示这个文件是不是ELF文件,还能确定其它的信息。

Magic大小为16个字节,前7个字节有意义,后面的9个字节都是0,从前7个字节中可以解析出Class,Data,Version,OS/ABI,ABIVersion这个5个属性,其中前4个字节:7f454c46是固定的,所有的ELF文件类型都一样,第5个字节表示32位还是64位,01表示32位,02表示64位,第6个字节表示内存存储方式是大端还是小端的,第7个字节表示ELF的主版本号,一般是1。

Type:ELF文件类型

包括以下几种文件类型:

REL:可重定位目标文件。

EXEC:可执行文件。

DYN:共享目标文件即共享库。

Machine:机器类型

包括ELF文件适用的CPU类型,有以下几种:

M32(AT&TWE32100)

SPARC

Interx86

Motorola68000

Motorola88000

Inter80860

EntryPointaddress:程序的入口虚拟地址

操作系统加载可执行文件后,从这个地址开始执行指令,可重定位目标文件一般没有入口地址,因此为0。

StartOfprogramheaders:程序头表在文件中的偏移量即开始位置。

StartOfSectionheaders:节表在文件中的偏移量即开始位置。

Flags:用来标识与平台相关的属性。

SizeOfthisheader:ELF文件头(ELFHeader)的大小。

SizeOfprogramheaders:程序头表的大小。

NumberOfprogramheaders:程序头表中程序头的个数。

SizeOfSectionHeaders:节表的大小。

NumberOfSectionHeaders:节表中节的个数

Sectionheaderstringtableindex:节名字符串表(shstrtab)在节表中的索引。

总体来说,通过ELF文件头(ELFHEADER)可以确定ELF文件类型,适用的CPU类型,文件版本,程序头表的起始位置,程序头表中程序头的个数,程序头表的大小,节表的起始位置,节表中节的个数,节表的大小,第一条执行的指令的起始位置等。


节表(Sectionheadertable):

通过文件头(ELFHeader)可以确定节表的开始位置和大小,节表由多个固定大小的节表项组成,每个节表项包括了节的属性信息,可以通过readelf-S查看ELF文件的节表,如下图所示:

节表

如上图所示,节表里总共有13个选项,第0项是空的,因此节表中总共12个有效的节表项,每一项长度都是固定的,包括了10个属性:Name,Type,Address,Offset,Size,EntSize,Flags,Link,Info,Align,下面来逐个阐述节的各个属性。

Name:节名

节名存储在【节名字符串表】(.shstrtab表)中,这里显示的名称就来自于.shstrtab表。

Type:节的类型

1.NULL表示无效节。

2.PROGBITS表示该节为程序节,例如代码节,数据节都是这种类型。

3.SYMTAB表示该节为符号表,程序中的变量和函数就属于符号,存储在符号表。

4.STRTAB表示该节为字符串表,用于存储除了节名以外的各类字符串如变量名,函数名。

5.RELA重定位表,表示该节包含重定位信息。

7.HASH表示该节为符号表的哈希表,主要用来用于加快符号的查找速度。

8.DYNAMIC动态链接信息节。

9.NOTE提示性信息节。

10.NOBITS表示该节在文件中的没有内容,不占用存储空间,比如.bss段。

11.REL该节包含了重定位信息。

12.SHLIB保留。

13.DNYSYM动态链接的符号表。

Address:节的虚拟地址。

如果该节可以被加载到内存,该地址就是节被加载到进程虚拟地址空间的虚拟地址,否则地址为0。

Offset:节在文件中的开始位置。

如果该节在文件中存储,这个值表示该节在文件中的开始位置,如果该节不在文件中存储例如.bss节,这个值就没有任何意义。

Size:节的大小,即使节不在文件中存储也可以有大小,例如.bss节不在文件中存储,但是有大小,这个大小主要是指明加载到内存时,分配的内存大小。

EntSize:节的每一项的大小。

有些节由固定大小的项构成,对于这些节来说,EntSize表示项的大小,如果为0表示该节包含的项的大小不固定。

Flags:节在进程虚拟地址空间的属性。

比如该节是否可写,是否可执行等,当然只有节能够被加载到内存时,这个Flags才有效,例如.text,.data,有以下几个值:

1.WRITE:该节在虚拟地址空间可写,一般指数据节。

2.ALLOC:该节在虚拟地址空间需要分配空间,只有节能够被加载到内存时,才有这个属性。

3.EXECINSTR:该节在虚拟地址空间可以被执行,一般指代码节。

Link:不同类型的节含义不同。

当节类型(Type)为DYNAMIC时:用于表示该节使用的字符串表在节表中的索引。

当节类型(Type)为HASH时:用于表示该节使用的符号表在节表中的索引。

当节类型为REL,RELA时:用于表示该节使用符号表在节表中的索引。

当节类型为SYMTAB,DYNSYM时:操作系统相关的。

对于其它节,值为UNDEF。

Info:不同类型的节含义不同。

当节类型为DYNAMIC时,值为0。

当节类型为HASH时,值为0

当节类型为REL,RELA时,该重定位表所作用的节在节表中的下标。

当节类型为SYMTAB,DYNSYM时,操作系统相关的。

对于其它节,值为0。

Align:每个节的对齐大小。

有些节要求节的起始位置,必须是Align的整数倍,例如Align=8表示节的起始位置必须是8个整数倍,通常Align是2的整数倍,如果Align为0或者1表示节没有对齐要求。

总体来说,通过节表可以知道每个节在文件中的起始位置,节的大小,节是不是可以被加载到内存,节加载到内存后的权限,节加载到内存后的虚拟地址,节如果用到其它节,则可以知道其它节在节表中的索引,这样就可以在节表中通过索引找到其它节。

代码节,数据节(.text,.data,.bss):

代码节通常的名字为.code或者.text,数据节分为.data和.bss两部分,如下图

程序对应的节

.text节用于存储机器指令,如上图黄色字体部分,包括函数等。

.data节用于存储已经初始化的全局变量和静态变量,如上图绿色字体部分,函数的局部变量存储在栈中,不在.data中存储。

.bss节用于存储未初始化的全局变量和静态变量,如上图蓝色字体部分,bss节在文件中不占用存储空间,只是一个名义上占个位置而已,当程序被加载到内存时,会在内存分配bss段,将未初始化的全局变量和静态变量存储在那里。


重定位表(.rela):

在代码节和数据节中,有些函数或者变量定义在其它的目标文件中,因此在链接时,需要将这些函数和变量进行重定位,重定位时依据的信息就在重定位表中。

对于代码节,它的重定位信息在.rela.text中,对于数据节,它的重定位信息在.rela.data中。

对于重定位表,因为它用到了符号表,它的Link属性表示符号表在节表中的索引,Info表示这个重定位表作用于哪个节,如下图所示,.rela.text中Link为11,从节表中查找第11项就可以定位到符号表,Info为1,从节表中查找第1项就可以定位到代码节,表示重定位表作用于索引为1的代码节。

重定位表定位符号表和代码节

字符串表(.strtab和.shstrtab):

一个程序中会出现很多字符串,例如变量名,函数名,这些名称的长度通常是不固定的,因此一个节中如果要存储这些信息的话,节的大小就需要是动态的,一种常见的做法是将所有不固定的字符串单独用字符串表进行存储,其它的节可以用一个偏移量来表示字符串,这样除了字符串表外,其它的节的长度都是固定的了,便于文件的处理。

其它的节知道了字符串的偏移量后,就可以到字符串表中进行查找,由于字符串的最后一个字符是\0,就可以从偏移量开始截取字符串到\0,一个完整的字符串就可以得到了。

在ELF文件中,字符串表有.strtab和.shstrtab两种,.strtab用于保存普通的字符串,比如变量,函数的名称,.shstrtab通常用于保存节表中用到的字符串,比如节的名称。

符号表(.symtab):

链接过程本质上就是将多个目标文件粘合在一起,就像搭建积木一样,每个积木就是一个目标文件,每个积木都有凹凸部分,这样不同的积木之间才能粘合在一起,目标文件的凹凸部分就是函数或者变量地址,重定位的过程就是替换地址的过程。

一个目标文件A定义了函数func1,另外一个目标文件B引用了函数func1,func1是函数的名字,对于变量也是类似,函数和变量叫做符号,函数名和变量名就叫做符号名。

每个目标文件都有一个符号表,每个符号表中记录了目标文件用到的所有符号,每个符号都对应一个符号值,对于变量和函数来说,符号值就是变量和函数的地址。

符号表中除了函数和变量外,还有其它不常用到的符号,经过统一整理后,可以对所有的符号进行如下分类:

强符号:定义在本目标文件中的全局符号并且已经初始化,这些符号可以被其它目标文件引用,例如SimpleSection.c中的func1,main,global_init_var。

弱符号:定义在本目标文件中的全局符号但是没有初始化,这些符号可以被其它目标文件引用,例如SimpleSection.c中的global_uninit_var。

强引用:声明在本目标文件中的全局符号,但并未定义在当前目标文件,这个符号引用了其他目标文件中的符号,例如SimpleSeciton.c的printf函数,对于变量来说,可以通过extern关键字进行声明。

对于强引用,如果链接过程中,在其它目标文件中没有找到该引用,则报找不到符号的错误。

弱引用:通过__attribute__((weakref))方式声明弱引用,这个符号引用了其他目标文件中的符号,例如__attribute__((weakref))voidfoo();就声明了foo函数就是一个弱引用。

对于弱引用,如果静态链接或者加载链接时,在其它目标文件中没有找到该引用,则不会报错,因此弱引用可以用于动态链接。

局部符号:在目标文件中可见,其它目标文件不可见,比如SimpleSection.c中的static_var和static_var2。

链接过程中比较关心的符号就是强符号,弱符号,强引用,弱引用,局部符号则是次要的,它们对其它目标文件是不可见的。

可以通过readelf-s查看符号表信息

符号表信息

由上图得知,SimpleSection.o总共有16个符号,每个符号都有几个属性,下面对属性介绍如下:

Size:符号大小。

对于包含数据的符号,这个值表示数据类型的大小,例如一个double类型占用8个字节。

Type:符号类型。

有以下几种符号类型:

NOTYPE表示未知类型符号,一般指的是符号定义在其他目标文件中,例如强引用,弱引用。

OBJECT表示数据对象,比如变量,数组等。

FUNC表示函数或者其它可执行代码。

SECTION表示一个节,符号的Bind属性必须是Local,即它必须是一个局部符号。

FILE表示一个文件名,一般为该目标文件对应的源文件名。

Bind:符号绑定信息。

Local表示局部符号,只在当前目标文件可见,其它目标文件不可见。

GLOBAL表示全局符号可以是强符号,也可是是强引用。

WEAK表示弱引用。

Ndx:符号所在节的信息。

ABS表示该符号包含一个绝对的值,比如表示文件名的符号就属于这种类型。

COM表示该符号是一个”COMMON”块类型的符号,一般来说,未初始化的全局符号就是这种类型。

UND表示该符号未定义,该符号在当前目标文件中被引用了,但是没有在目标文件中定义。

其它,表示符号所在节在节表中的下标。

Name:符号名。

通常存储于字符串表(.strtab)。

Value:符号值。

当Ndx的值是节表索引时,可以知道这个符号在哪个节中,例如SimpleSection.o中的func1函数,func1这个符号它的Ndx就是1,通过1可以在节表中找到代码节.text,此时符号值就是func1在.text节中偏移量。

当Ndx是COM时,符号值就是该符号的对齐属性。

当文件是可执行文件,符号值就是符号的虚拟地址。

除了在符号表中定位的符号外,还有些特殊符号。

特殊符号不在符号表中定义,但是程序中可以直接引用它,这些特殊符号通常被定义在链接器的链接脚本中,因此这些符号类似与内置符号,不需要在符号表中定义,由如下几类特殊符号:

__executable_start:表示程序的起始地址,是程序的最开始地址。

__etext或_etext或etext:表示代码段的结束地址。

_edata或edata:表示数据段的结束地址。

_end或end:程序的结束地址。

以上地址都是程序被装载时的虚拟地址。


其它节:

rodata1:

只读数据节,比如字符串常量,全局const变量都存储在这里。

comment:

存储编译器版本信息。

.debug:

存储调试类信息。

.hash:

符号哈希表,用于加速符号的查找过程。

.line:

调试时的行号表,即源代码和编译后的指令的对应表。

.note:

额外的编译器信息,比如程序的公司名,发布版本号等。

.plt:

动态链接的跳转表。

.got:

全局入口表,用于动态链接跳转到变量和函数。

番外篇

其它常用的查看ELF文件信息命令

通过objdump-h命令可以查看ELF文件的各个常用的节的信息

可以通过objdump-s-d查看ELF文件头信息,符号表,以及反汇编指令。

相关内容

热门资讯

金花创建房间/微信金花房卡怎么... 1.微信渠道:(荣耀联盟)大厅介绍:咨询房/卡添加微信:88355042 2.微信游戏中心:打开微...
金花房间卡/金花房卡如何购买/... 金花房间卡/金花房卡如何购买/新超圣金花房卡正版如何购买新超圣是一款非常受欢迎的游戏,咨询房/卡添加...
牛牛创建房间/金花房卡批发/神... 微信游戏中心:神牛大厅房卡在哪里买打开微信,添加客服【88355042】,进入游戏中心或相关小程序,...
链接牛牛/牛牛房卡游戏代理/鸿... 鸿运大厅房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根...
科技实测!牛牛房卡怎么获得/乐... 微信游戏中心:乐酷大厅房卡在哪里买打开微信,添加客服【88355042】,进入游戏中心或相关小程序,...