(1)bash進程調用fork()系統調用建立一個新的進程
(2)新的進程調用execve()系統調用執行指定的ELF文件,原先的bash進程繼續返回等待剛纔啓動的新進程結束,而後繼續等待用戶輸入命令。
(3)execve()系統調用相應的入口是sys_execve(),sys_execve()進行一些參數的檢查複製後,調用do_execve()。
(4)do_execve()讀取128個字節的文件頭部,調用search_binary_handle()。
(5)search_binary_handle()經過魔數肯定文件格式,並調用相應的裝載過程:
1.檢查ELF可執行文件格式的有效性,好比說魔數、程序頭中段的數量。
2.尋找動態連接「interp.」段,設置動態連接器路徑。
3.根據ELF可執行文件的程序頭表的描述,對ELF文件進行映射,好比代碼、數據、只讀數據。
4.初始化ELF進程環境,好比進程啓動時EDX寄存器的地址應該是DT_FINI的地址。
5.將系統調用的返回地址修改爲ELF可執行文件的入口點,這個入口點取決於程序的連接方式,對於靜態連接的ELF可執行文件,這個程序入口就是ELF文件的文件頭中e_entry所指的地址;對於動態連接的ELF可執行問文件,程序的入口點是動態連接器。
(6)上訴步驟執行完,返回do_execve再返回至sys_execve()時,系統調用的返回地址改爲了被裝載的ELF程序的入口地址了,因此當sys_execve()系統調用從內核態返回到用戶態時,EIP寄存器直接跳轉到了ELF程序的入口地址,因而新的程序開始執行,ELF可執行文件裝載完成。linux
這一章中,探討了程序運行時如何使用內存空間的問題,即進程虛擬地址空間問題。接着圍繞程序如何被操做系統裝載到內存中進行運行,介紹了覆蓋裝入和頁映射的模式,分析以頁映射的方式將程序映射至進程地址空間的好處,並從操做系統的角度觀察進程如何被創建,當程序運行時發生頁錯誤該如何處理等。
還詳細介紹了虛擬地址空間分佈,操做系統如何爲程序的代碼、數據、堆、棧在進程地址空間中分配,它們是如何分佈的。最後兩個章節分別深刻介紹了Linux和Windows程序如何裝載並運行ELF個PE程序。這章中,咱們假設程序都是靜態連接的,那麼它們都只有一個單獨的可執行文件模塊。程序員
《程序員的自我修養》shell