进程影像(一)——从代码到进程

一、源程序、目标代码

1、 先使用Dev-C++编写C代码:main.c和test.c

/*main.c*/

int add(int,int);

int mian()

{

return add(20,13);

}

/*test.c*/

int add(int i,iny j)

{

          int x=i+j;

          return x;

}

2、 将上述俩文件放到虚拟机的共享文件夹下(与虚拟机共享),或者通过邮箱发送在虚拟机中通过邮箱下载到与gcc同目录下。

 

3、 在gcc目录下打开终端,输入 #gcc –c main.c将产生main.c的目标文件main.o

 

4、 输入ls-l查看main.o文件大小

 

5、 用file命令来识别一个文件的类型

 

从上面的file命令执行结果看,main.o是一个编译成x86-64架构的指令、可重定位(relocatable)的目标文件。该文件按照ELF(Executable and linkable Format)的布局来存放在磁盘文件中,而且还保留着符号表。

二、目标代码

1、用objdump –d命令完成代码段的反汇编

 

            图2.1

总共只有0x19个字节(0~0x18)的指令序列,最左边是字节偏移量,中间是二进制代码,右边是汇编代码。

2、用objdump –hrt main.o来了解更多关于这个目标文件的信息。

 

            图2.2

  因为使用-h (--headers/--section-headers)参数,因此将打印出该ELF格式的目标文件中各个节(section)的头部摘要信息(节是代码组织的一个单位,即某段相同属性的代码或数据)。另外,使用了-r (--reloc)参数来显示重定位入口。第三个参数-t(--syms)显示符号表项(即SYMBOL TABLE部分)。

  上面的结果表明mian.o中包含7个节,各个节的信息按列划分为:Idx是编号,Name是节的名字、Size给出节的大小、VMA给出节在虚存空间的起点、LMA (LoadMemory Address)是装载地址(除基于ROM的系统外,通常与VMA相同)、File off是该节在文件中的偏移量、Algn是地址对齐方式(2的整数次幂)。各个节的第二行有CONTENTS、ALLOC、LOAD、RELOC、READONLY、CODE、DATA等属性说明。CODE表示本节包含可执行代码;DATA表示本节是可写数据;READONLY表示本节是只读区域;ALLOC表示本节将要占用内存空间;CONTENTS表示本节确实在文件中占用了空间。

  其中,编号为0的.text节是main.c编译后的x86-64平台上的可执行二进制代码,共有0x19个字节。经过链接后在运行时由程序装载器把它构造成进程的代码段。编号为1的.data是用于保存已初始化的全局变量和局部静态变量。但这里的main.c中没有带初始值的全局变量也没有静态局部变量,所以作为目标代码(甚至可执行文件)并不需要占用空间来保存这些信息,因此该section长度为0,否则它的长度是所有具有初始值数据所占空间大小。编号为2的.bss (Block Started by Symbol),保存未初始化的全局变量和局部静态变量。未初始化的全局变量和局部静态变量默认值都为0,本来它们也可以放在.data段,但因为它们都是0,所以为它们在.data段分配空间并且存放数据0是没有必要的。程序运行的时候这些变量的确是要占内存空间,所以目标文件必须记录所有未初始化的全局变量和局部静态变量的大小总和,记为.bss段。也就是说,.bss 段只是为未初始化的全局变量和局部静态变量预留位置而已,它并没有内容(该节标志中没有CONTENTS一项),在磁盘文件中也不占据空间。编号为3的.comment 包含0x2b个字节的注释。编号为4、5的.note是额外的编译器信息—例如程序的公司名、发布版本号等。由于是目标文件,所有的节都还未经过链接定位,也就是说还未布局,所以各个节的起始虚存地址VMA和物理地址LMA (Load Memory Address)都为无效的0(进行链接后将按照可执行文件的布局来确定地址)。

  SYMBOL TABLE包含所有的符号信息。各列分别是节内偏移、标记位、所在的节、对齐方式(或长度)和符号名。标记位共7位,第一位作用域可以是以下取值:局部的‘I’、全局的’g'、全局唯一的’u'、不是全局也不是局部’_'(空格)以及既是全局又是局部的"!'。第二位可以为GCC 中的弱符号’w'或强符号’_’。第三位可以是 constructor 符号’C’或普通符号’_'。第四位可以是警告符号’w'或普通符号'_'。第五位可以是间接引用符号’i'、需重定位的函数’T’或普通符号’_'。第六位可以是调试符号’d’、动态符号’D'或普通符号’_'。第七位可以是函数名’F’、文件名'f’、对象'0’或普通符号'_'。第三列给出了符号所在的节,如果是*ABS*表明这个符号是绝对符号(与各节无关),如果是*UND*则这个符号不在本目标文件中定义。本例子中大多数符号为调试符号。对于函数名和对象(变量)的符号,倒数第二列就不是对齐方式而是所占空间的长度。

本例中目标文件中含有未确定(Unresolved,也有称为未分析、未决断)的地址。RELOCATION RECORDS FOR [.text]以及RELOCATION RECORDS FOR [.eh_frame]是text和eh frame两个节的重定位表。例如,图2.2中RELOCATION RECORDS FOR [.text]里的两个地址 0000 0000 0000 0013对应地在图2.1偏移为0x13的位置都为“00 00 00 00”,本来应该是字符串add函数的地址,它们需要在链接后重新定位——所以它们在重定位表中指出(等到生成可执行文件的时候这两个地址就不为0)。

  根据上面的信息,可以大致绘制出这个目标文件的磁盘布局情况(使用readelf -S 命令可以全面查看节的更多信息),如图2.3所示。

 

              图2.3

3、用objdump –s main.o查看.text代码以及.comment等部分的二进制编码内容

三、可执行文件与进程影像

1、 生成可执行文件

 

  链接后的可执行文件main 使用ELF格式。ELF格式的文件可以用于多种用途——可执行文件(Executable File)、可重定位文件(Relocatable File)、共享目标文件(Shared Object File)和核心转储文件(Core Dump File)。用file 命令可以证实main确实是ELF格式的可执行文件(Executable)。

2、 用readlelf -S命令查看main的“节”的情况(也可用objdump –h命令)

  我们发现这里的.text节和目标里的.text大小部分发生了改变,.text的大小0x195比目标文件里的0x19字节大太多了(因加入入口初始化代码)。应注意节是编译器进行编号的,并不是按照各个节在文件或在虚存空间中的位置排序的。

3、 用objdump –t main查看符号表

               图3.1

4、 用readelf –l main 查看ELF可执行文件的程序头(Program file)里描述的与装入过程有关的信息,告知操作系统如何将它们映射到虚拟空间中。

 

                  图3.2

  从图3.1看出main函数地址为0x0000000000001129,与图3.2的Entry point 0x1040地址不一致,这是因为入口地址指向的是编译器提供的一段初始化代码(叫做_tart函数,符号表给出的地址是0x0000000000001040)。

  从图3.2的输出可以看出有13个段(Segment),从装载的角度上看,只需要关心“LOAD”类型的段,其他诸如“NOTE”或“GNU_STACK”等只是在装载过程中起辅助作用。这两个需要装载的段对应编号为02、03、04和05,于是可以在“Section to Segmentmapping”里面找出这两个段包含哪些节。因此可以将编号为02的段所对应的节:

 

装入到虚存空间的某个区域中,而且此虚存空间区域的属性需要设置为“R”——表示只读。具体装入操作需要将文件中偏移0x0000000000000000 (Offset)开始的0x00000000000005c8 (FileSiz)个字节装入到虚存空间0x0000000000000000( VirtAddr)位置处,占用0x00000000000005c8 (Memsize)的内存空间。编号为03、04、05段类似,在这里就不具体说明了。

5、运行可执行文件

 

                    图5.1

  用跟踪工具strace命令查看启动过程中执行的系统调用。从图5.1运行strace ./main命令之后的输出可以看出,在shell命令行下执行main可执行文件的基本流程。Shell作为父进程调用了fork系统调用将自己复制一份后产生子进程,该子进程再执行execve系统调用,将使用main可执行文件重建进程内存的映像。在执行过程中涉及不少文件和内存相关的系统调用。最后exit_group(33)(33=20+13)退出程序。

posted @ 2020-11-23 22:37  lanliuliu  阅读(191)  评论(0编辑  收藏  举报