天天看點

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結構 及程式載入執行

    程式運作的過程:建立虛拟空間(配置設定一個頁檔案夾)-> 建立虛拟空間與可運作檔案映射(頁檔案夾項指向磁盤的程式) -> 跳到程式入口 -> 缺頁異常-> 在記憶體中尋找空暇頁。将相應的頁換入 -> 建立映射 -> 開始運作。