ELF 之 Program Loading 教學文件, #3: Segment Type 與 Kernel Space Loader

jollen 發表於 March 9, 2007 7:46 PM

Segment Type

Program loading 時期會處理以下 4 種 segment:

#define PT_LOAD         1               /* Loadable program segment */
#define PT_DYNAMIC      2               /* Dynamic linking information */
#define PT_INTERP       3               /* Program interpreter */
#define PT_PHDR         6               /* Entry for header table itself */

簡要說明這 4 種 segment 的作用如下。

PT_LOAD:即 text segment 或 data segment。

PT_DYNAMIC:若 ELF 有此 segment,則表示 .dynamic section 會獨立成一個實體的 segment。PT_DYNAMIC 僅包含 .dynamic section。

PT_INTERP:紀錄 program interpreter 路徑與檔名的 segment。PT_INTERP 僅包含 .interp section。

PT_PHDR:Program header table segment。

Segment type 是很重要的資訊,kernel 的 ELF loader 與 program interpreter(ld.so)都是透過 segment type 來判斷 segment 的用途。

Kernelprogram interpreter 對不同的 segment 都有不同的處理方式。

另外,PT_NOTE 並不是一個必要的 segment,實際上它也沒有重要的作用,因此忽略不做討論。

更多有關 Kernel ELF Loader

回到 Jollen's blog「Process Creation」專欄所談論到的「Program 載入流程」裡,相當重要的一個觀念就是 "exec" system call。程式的載入涉及 exec systegm call service,exec system call 是 machine-dependent 的實作,以 x86 來說,此服務實作於 linux/arch/i386/kernel/process.c 檔案;在 SystemV ABI 規格中,program loading 的章節 被撰寫在 'processor-specific' 文件裡。

在目前所討論的 ELF loading 主題中,我們還看不到與 processor 相關的議題,例如 .got/.plt 節區的用途;相關的技術細節在此較不適合做深入討論,未來會以分享一份技術簡報的方式來呈現,並且以 ARM 做為討論標地。

Exec system call 叫用 kernel space 的 ELF loader 載入 ELF image,此觀念請參考 Jollen's Blog「Process Creation, #6:Exec System Call 的觀念」。我們整理過 kernel 的 ELF loader 所做的工作有:

1. 讀取 ELF image 的 segment 資訊(由 program header table)。

2. 讀出 segment 內容。

3. 判斷是否有 program interpreter;若有,再讀取 program interpreter。

4. 將讀取到的 segment 內容取代掉 current 的內容,這個動作就是 exec system call 的重要特性。

項目 1. 是由 ELF image 的 program header table 分析執行檔的 segment 資訊,並判斷 segment type;ELF loader 會依照 segment 的類型來做不同的處理,說明如後(項目 2.)。

項目 3. 則是在找到 PT_INTERP  segment 時,呼叫 interpreter loader 將 interpreter 載入。Program interpreter 我們先前曾提過,就是 ld.so(dynamic loader/linker),這個部份將在下一篇日記再做說明。

PT_INTERP

若 ELF loader 判斷此 segment 為 PT_INTERP,則叫用 interpreter 的 loading 來做載入的工作,在標準的 GNU/Linux 系統底下,由於 program interpreter 也是 ELF 格式,因此叫用 kernel 的 load_elf_interp() API(fs/binfmt_elf.c)將 program interpreter 讀取並載入。

PT_LOAD

若 ELF loader 判斷此 segment 為 PT_LOAD,表示這是 text segment 或 data segment,也就是最主要的程式碼與資料區段,此時便透過 do_mmap() 來將 text/data segment mapping 到記憶體。

依照 ELF 規格,text segment 會由 virtual address 0x0804_8000 的地方開始 mapping,data segment 則是緊接在 text segment 之後。

另外,text segment 與 data segment 都是 PT_LOAD 類型,因此需要根據 Flg 欄位的屬性來知道該 segment 是 text segment 還是 data segment。詳見前一篇日記有關 segment permissions 的說明。

小結

總結本專欄到目前為止所得到的資訊如下。灰色部份是 interpreter 負責的工作,將在下篇日記討論。

請注意,本日記是針對 kernel 本身所做的 ELF loading 工作來做整理,即 kernel-space 的 program loading。另外一半的 program loading 是由 user-space 的 dynamic loader/linker 所完成,這裡所提的 dynamic loader/linker 就是我們不斷提到的 program interpreter。

Segment Type Kernel or Program Interpreter
00 PHDR Interpreter 用來計算 base address 用。
01 INTERP Kernel ELF loader 用來載入 interpreter,並交由 interpreter 做 shared library 的 dynamic linking。
02 LOAD Kernel 將此 segment mapping 為新的 text segment 或 data segment。
03 LOAD Kernel 將此 segment mapping 為新的 text segment 或 data segment。
04 DYNAMIC 由 interpreter 處理

讀者留言 (0)

留言功能維護中。將於近日重新開放。

連絡作者

Jollen Chen,Moko365(仕橙3G教室)講師,熱愛研究 Linux 與 Android 技術。曾為 Motorola、HTC、Foxconn、LG、OPPO、騰迅、廣達電腦、緯創、仁寶等超過 50 家企業講授課程。目前在 MokoVersity 擔任軟體工程師,撰寫 Node.js 程式,也在幾家科技廠兼任 Android Framework 研發顧問。您可透過電子郵件 <jollen (at) jollen (dot) org> 或這裡與我連絡。