陳民禾——原創做品轉載請註明出處—— 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000編輯器
一.上週內容總結複習函數
上一週學習了Linux 如何存放和表示進程(用task_ struct 和thread_info ),如何建立進程(經過fork(),實際上最終是clone()),如何把新的執行映像裝入到地址空間(經過execO 系統調用族〉,如何表示進程的層次關係,父進程又是如何收集其後代的信息(經過wait()系統調用族),以及進程最終如何消亡〈強制或自願地調用exit()) 。學習
進程的狀態大體以下圖所示spa
二.幾個重要概念3d
可執行程序:可執行程序以C語言代碼爲例,通過編譯器的預處理,處理完以後把它編譯成彙編代碼,而後有個彙編器將它編譯成彙編代碼,而後,將其連接成可執行文件。調試
目標文件的格式ELF,常見的目標文件格式:A.out COFF後來發展爲PE和ELF,目標文件也常常叫作ABI ,也就是應用程序二進制接口,實際上在二進制兼容的格式這個目標文件已經適應了某種CPU體系結構上的二進制指令,好比說一個32位X86文件鏈接成arm可執行文件是不能夠的,在ELF文件中有三種可執行文件,可重定位文件:保存着代碼和適當的數據,用來和其餘的object文件一塊兒建立一個可執行文件或者是一個共享文件。可執行文件:保存着一個用來執行的程序,該文件指出了exec如何來建立程序進程映像共享object文件:保存着代碼和合適的數據,用來被下面兩個連接器鏈接,一個是鏈接編輯器,能夠和其餘的可重定位和共享object文件來建立其餘的object;第二個是動態連接器,聯合一個可執行文件和其餘共享的object文件來建立一個進程映像ELF目標文件格式:code
object文件參與程序的聯接(建立一個程序)和程序的執行(運行一個程序),orm
動態可執行文件:它要依賴這個可執行程序,須要其餘的動態連接庫,這個動態連接庫,某一個點它也要依賴其餘的動態連接庫,動態連接庫的動態連接庫,動態連接庫包括可執行文件,實際上動態連接庫的依賴關係會造成一個圖,ELF格式的文件,假如說都是同樣的,就會對ELF文件進行解析,看它依賴了哪些動態連接庫,這樣它就會加載。blog
三.重要知識和過程接口
可執行文件產生過程:好比咱們以一個hello world程序爲例,咱們能夠把.c文件作預處理
可執行文件和進程的地址空間:當一個可執行文件ELF加載到內存的時候,它是怎麼加載的呢,咱們加載的效果知道,把代碼的數據加載到一塊內存中來,把數據加載到內存中來,固然代碼有不少塊代碼,不少代碼段,加載進來以後默認elf加載到0x8048000從這個位置開始加載,那麼加載以後可能以前是一個ELF頭部文件的信息,通常來說,這個頭部大小的文件信息可能就是會有不一樣,因此加載時的入口點的位置可能不一樣,這個地方就是程序的實際入口,當啓動一個新的程序的時候,它就是從這個地方開始執行,加載到啓動一個新的進程,啓動一個剛加載過可執行文件的進程,一個新的進程只是fork了原來的一份,它的執行位置仍是執行了原來那個進程的位置,加載了新的可執行文件以後,開始執行的入口點,這個是一個靜態連接的ELF可執行文件,這個時候都已經幫咱們連接好了,從這裏開始一個文件一個文件的開始執行,怎麼壓棧出棧,怎麼來操做,能把整個程序執行完,也就是從main函數到main函數執行完畢。
裝載可執行程序以前的工做:咱們通常是經過share程序來執行一個可執行程序,當咱們裝載一個可執行程序,也就是咱們發起一個系統調用execve,咱們還須要準備哪些,這個share環境爲咱們準備了哪些可執行的上下文環境,這樣咱們就大概在用戶態的執行文件大概瞭解一下,而後咱們看一下一個execve,它怎麼把一個可執行文件在內核裏面裝載起來,又返回到用戶態。
四.實驗過程截圖及分析
打開窗口加載qemu,克隆新版本
查看makefile的代碼
查看關鍵代碼:父子進程
凍結窗口開始進行調試:
使用gdb設置斷點,能夠看到分別在sys_execve和load_elf_binary處設置斷點
查看附近的代碼:給新棧的賦值。
執行到start_thread的時候有一個問題:
new ip究竟是指向哪裏的?
用po(print object)指令:
po new_ip 能夠看到一個地址:0x80495ba
readelf -h hello 找到hello這個可執行程序的入口地址。 這是一個靜態編譯的可執行文件。
new ip是返回用戶態的第一條指令的地址。
五.學習本週知識的總結
用一個比較形象的比喻就是實際上咱們把原來的可執行程序,也就是share可執行程序,int 0x80進入到這個execve的系統調用入睡,當他入睡的時候加載到一個新的可執行程序,加載到新的可執行程序,return 返回以後,也就是它醒來了,蝴蝶執行了在蝴蝶內部的程序,它若是加載莊子,這二者老是想相對的,但都是同一進程,只是把進程裏面的可執行程序給替換掉了,這就是咱們對進程如何加載和運行的一個基本的描述。