天天看点

Linux 可执行文件 ELF结构 及程序载入执行

    Linux下ELF文件类型分为以下几种:

    1、可重定位文件,比如SimpleSection.o;

    2、可运行文件,比如/bin/bash。

    3、共享目标文件,比如/lib/libc.so。

    在Linux 可重定位文件 ELF结构一文中,我们已经分析了可重定位文件ELF结构。

本文分析可运行文件的ELF结构。

    首先附上源码:

    SectionMapping.c 

    使用命令gcc -static SectionMapping.c -o SectionMapping.elf。静态链接为可运行文件。

    接着使用命令readelf -S SectionMapping.elf得到Section Table。例如以下:

                                     表 1

    这个可运行文件共同拥有33个Section。

    接着我们使用readelf -h SectionMapping.elf。读取elf可运行文件头部信息。

例如以下图:

Linux 可执行文件 ELF结构 及程序载入执行

                                     图 1

    能够对照,Linux 可重定位文件 ELF结构,这里多了program header。

    Entry point address:程序的入口地址是0x401058,使用objdump -d SectionMapping.elf | less,能够查看到程序的入口地址是<_start>。

Linux 可执行文件 ELF结构 及程序载入执行

                                           图 2

    Start of program headers:program headers的偏移。由于头文件大小为64,所以program headers紧挨着头文件存放。

    Size of program headers:program headers的大小。为56个字节。

    Number of section headers:program headers的数量。

为6个。

    在表1中。第一个section在文件里的偏移是0x190。头文件大小为64 + program header大小为56 * program header数量6 = 400 = 0x190。

    然后,我们使用命令readelf -l SectionMapping.elf。我们会得到program header部分。例如以下图:

Linux 可执行文件 ELF结构 及程序载入执行

                                 图  3

    从图中可见,分为6个Segment。

注意表1中每一个段叫Section。

    Offset:这个Segment在文件里偏移。

    VirtAddr:这个Segment在虚拟地址的偏移。

    FileSiz:在ELF文件里所占的长度。

    MemSiz:在进程虚拟空间所占的长度。

    我们发现第二个Segment,MemSiz > FileSiz,表示在内存中分配的空间大小超过文件实际大小。

超过的部分所有初始化为0。作为BSS段。由于数据段和BSS段的唯一差别是,数据段从文件里初始化内容,BSS段内容所有初始化为0。

    我们主要关心前两个Segment。第一个是代码段,虚拟地址从0x00400000到0x004c1026。文件偏移从0x00000000到0x000c1026。

    第二个是数据段。虚拟地址为从0x006c1ef0到0x006c1ef0+0x4408=0x6c62f8。

文件偏移从0x000c1ef0到0x000c1ef0+0x1800=0x000C36f0。

    结合表1和两个Segment的文件偏移。能够得出:

    第一个Segment从第0个Section到第15个Section。(0x00000000-0x000c1026)

    第二个Segment从第16个Section到26个Section。

(0x000c1ef0-0x000C36f0)

    以上分析的都是静态状态下的程序,以下我们看看动态下的进程的空间是怎么分配的。

    首先使用命令, ./SectionMapping.elf &,输出例如以下:

Linux 可执行文件 ELF结构 及程序载入执行

    然后使用命令:cat /proc/2184/maps,输出例如以下:

Linux 可执行文件 ELF结构 及程序载入执行

                                    图 4

    静态时。我们计算出的两个Segment的虚拟空间的偏移分别为:

    第一个是代码段。虚拟地址从0x00400000到0x004c1026。

在图4中,由于要页面对齐,所以分配了0x400000到0x4c2000。

    第二个是数据段,虚拟地址为从0x006c1ef0到0x006c1ef0+0x4408=0x6c62f8。在图4中。由于要页面对齐,所以分配了0x6c1000到0x6c4000。注意。0x6c62f8大于0x6c4000。详细原因以后再分析。

    第三个紧接着是堆。用于动态分配内存。

    第四个是栈。用于存放局部变量。

    总体的结构例如以下图:

Linux 可执行文件 ELF结构 及程序载入执行

    程序运行的过程:建立虚拟空间(分配一个页文件夹)-> 建立虚拟空间与可运行文件映射(页文件夹项指向磁盘的程序) -> 跳到程序入口 -> 缺页异常-> 在内存中寻找空暇页。将相应的页换入 -> 建立映射 -> 開始运行。

下一篇: Tomcat连接池