ELF文件格式与进程地址空间的联系
http://blog.csdn.net/q_l_s/article/details/52597330
三、分析在fork產(chǎn)生新進(jìn)程中ELF文件格式與進(jìn)程地址空間的聯(lián)系
1、進(jìn)程的虛擬地址空間
????每個程序都有自己的虛擬地址空間(Virtual Address Space),大小由硬件平臺(CPU位數(shù))決定。 如32位平臺下每個程序都有4G虛擬空間。但4G空間不是都分配給程序的用戶空間,還有系統(tǒng)的虛擬空間。如Linux系統(tǒng)默認(rèn)情況下高1G為系統(tǒng)的虛擬地址空間,低3G為用戶空間。 這也就是說每個進(jìn)程原則上最多可使用3G的虛擬空間。
2、?進(jìn)程裝載
????覆蓋裝入(Overlay)和頁映射(Paging)是兩種典型的動態(tài)裝載方法。現(xiàn)在前者已經(jīng)不用了。???
????創(chuàng)建一個進(jìn)程,然后裝載相應(yīng)的可執(zhí)行文件并且執(zhí)行。上述過程最開始只需要做三件事情:
①創(chuàng)建一個獨(dú)立的虛擬地址空間。主要是分配一個頁目錄(Page Directory)。
②讀取可執(zhí)行文件的頭,并且建立虛擬空間和可執(zhí)行文件的映射關(guān)系。主要是把可執(zhí)行文件映射到虛擬地址空間,即做虛擬頁和物理頁的映射,以便“缺頁”時載入。
③將CPU的指令寄存器設(shè)置成可執(zhí)行文件的入口地址,啟動運(yùn)行。從ELF文件中的入口地址開始執(zhí)行程序。
3、過程分析
????在bash下執(zhí)行一個程序時,Linux是怎樣裝載這個ELF文件并執(zhí)行的呢?
? ??首先bash調(diào)用fork()系統(tǒng)調(diào)用創(chuàng)建一個新的進(jìn)程,然后新的進(jìn)程調(diào)用execve()系統(tǒng)調(diào)用執(zhí)行指定的ELF文件。 bash進(jìn)程繼續(xù)返回等待新進(jìn)程執(zhí)行結(jié)束,然后重新等待用戶輸入命令。execve()系統(tǒng)調(diào)用被定義在unistd.h,它的原型如下:
????int execve(const char *filenarne, char *const argv[], char *const envp[]);
????它的三個參數(shù)分別是被執(zhí)行的程序文件名、執(zhí)行參數(shù)和環(huán)境變最。Glibc對execvp()系統(tǒng)調(diào)用進(jìn)行了包裝,提供了execl(), execlp(), execle(), execv()和execvp()等5個不同形式的exec系列API,它們只是在調(diào)用的參數(shù)形式上有所區(qū)別,但最終都會調(diào)用到execve()這個系統(tǒng)中。
????調(diào)用execve()系統(tǒng)調(diào)用之后,再調(diào)用內(nèi)核的入口sys_execve()。 sys_execve()進(jìn)行一些參數(shù)的檢查復(fù)制之后,調(diào)用do_execve()。 因?yàn)榭蓤?zhí)行文件不止ELF一種,還有Java程序和以“#!”開始的腳本程序等, 所以do_execve()會首先檢查被執(zhí)行文件,讀取前128個字節(jié),特別是開頭4個字節(jié)的魔數(shù),用以判斷可執(zhí)行文件的格式。 如果是解釋型語言的腳本,前兩個字節(jié)“#!"就構(gòu)成了魔數(shù),系統(tǒng)一旦判斷到這兩個字節(jié),就對后面的字符串進(jìn)行解析,以確定程序解釋器的路徑。
????當(dāng)do_execve()讀取了這128個字節(jié)的文件頭部之后,然后調(diào)用search_binary_handle()去搜索和匹配合適的可執(zhí)行文件裝載處理過程。Linux中所有被支持的可執(zhí)行文件格式都有相應(yīng)的裝載處理過程,search_binary_handle()會通過判斷文件頭部的魔數(shù)確定文件的格式,并且調(diào)用相應(yīng)的裝載處理過程。如ELF用load_elf_binary(),a.out用load_aout_binary(),腳本用load_script()。其中ELF裝載過程的主要步驟是:
????①檢查ELF可執(zhí)行文件格式的有效性,比如魔數(shù)、程序頭表中段(Segment)的數(shù)量。
????②尋找動態(tài)鏈接的”.interp”段(該段保存可執(zhí)行文件所需要的動態(tài)鏈接器的路徑),設(shè)置動態(tài)鏈接器路徑。
????③根據(jù)ELF可執(zhí)行文件的程序頭表的描述,對ELF文件進(jìn)行映射,比如代碼、數(shù)據(jù)、只讀數(shù)據(jù)。
????④初始化ELF進(jìn)程環(huán)境,比如進(jìn)程啟動時EDX寄存器的地址應(yīng)該是DT_FINI的地址(結(jié)束代碼地址)。
????⑤將系統(tǒng)調(diào)用的返回地址修改成ELF可執(zhí)行文件的入口點(diǎn),這個入口點(diǎn)取決于程序的鏈接方式,對于靜態(tài)鏈接的ELF可執(zhí)行文件,這個程序入口就是ELF文件的文件頭中e_enEry所指的地址;對于動態(tài)鏈接的ELF可執(zhí)行文件,程序入口點(diǎn)是動態(tài)鏈接器。
????當(dāng)ELF被load_elf_binary()裝載完成后,函數(shù)返回至do_execve()在返回至sys_execve()。在load_elf_binary()中(第5步)系統(tǒng)調(diào)用的返回地址已經(jīng)被改成ELF程序的入口地址了。 所以當(dāng)sys_execve()系統(tǒng)調(diào)用從內(nèi)核態(tài)返回到用戶態(tài)時,EIP寄存器直接跳轉(zhuǎn)到了ELF程序的入口地址,于是新的程序開始執(zhí)行,ELF可執(zhí)行文件裝載完成。
總結(jié)
以上是生活随笔為你收集整理的ELF文件格式与进程地址空间的联系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS实现转动随机数抽奖的特效代码
- 下一篇: jsp页面定义的map