《Linux內核分析》第七週學習總結shell
——可執行程序的裝載函數
姓名:王瑋怡 學號:20135116學習
1、理論部分總結spa
(一)可執行程序的裝載操作系統
一、預處理、編譯、連接和目標文件的格式命令行
C代碼通過編譯器的預處理(.cpp),而後編譯成彙編代碼(.asm/.s),由彙編器成目標代碼(.o,二進制文件),再連接成可執行文件,最後由操做系統加載到內存中執行。翻譯
gcc -E hello.c -o hello.icode
gcc –S hello.i –o hello.sorm
.s文件
轉成二進制目標代碼gcc –c hello.s –o hello.oblog
.o文件
連接成最終的可執行文件(hello也是一個二進制文件)gcc hello.o –o hello
二、目標文件的格式ELF
(1)目標文件格式分類
(2)ABI和目標文件
ABI:應用程序二進制接口,在目標文件中二進制兼容模式
(3)ELF中三種目標文件
(4)ELF頭
*當建立或增長一個進程映像時,系統在理論上將拷貝一個文件的段到一個虛擬的內存段
三、靜態連接的ELF可執行文件與進程的地址空間
(二)可執行程序、共享庫和動態進程
一、裝載可執行程序以前的工做
(1)命令行參數和shell環境
$ ls -l /usr/bin
int main(int argc, char *argv[], char *envp[])
int execve(const char * filename,char * const argv[ ],char * const envp[ ])
庫函數exec*都是execve的封裝例程
(2)命令行參數和環境變量是如何保存和傳遞的
二、裝載時動態連接和運行時動態連接應用
動態連接分爲可執行程序裝載時動態連接和運行時動態連接
(三)可執行程序的裝載
一、execve系統調用的內核處理過程
(1)新的可執行程序起點——通常是地址空間爲0x8048000或0x8048300
(2)execve和fork都是特殊的系統調用——通常的都是陷入到內核態再返回到用戶態
fork兩次返回,第一次返回到父進程繼續向下執行,第二次是子進程返回到ret_from_fork而後正常返回到用戶態。
execve執行的時候陷入到內核態,用execve中加載的程序把當前正在執行的程序覆蓋掉,當系統調用返回的時候也就返回到新的可執行程序起點。
sys_execve內部會解析可執行文件格式
do_execve —> do_execve_common —> exec_binprm
search_binary_handler符合尋找文件格式對應的解析模塊
對於ELF格式的可執行文件fmt->load_binary(bprm);執行的應該是load_elf_binary其內部是和ELF文件格式解析的部分須要和ELF文件格式標準結合起來閱讀
*load_elf_binary中,調用了start_thread()函數,經過修改內核堆棧中EIP的值做爲新程序的起點
二、sys_execve的內部處理過程
return do_execve(getname(filename), argv, envp);
return do_execve_common(filename, argv, envp);
file = do_ open_exec(filename); //打開要加載的可執行文件,加載它的文件頭部
bprm->file = file;
bprm->filename = bprm->interp = filename->name; //建立了一個結構體bprm,把環境變量和命令行參數都copy到結構體中
ret = search_binary_handler(bprm); //尋找此可執行文件的處理函數 在其中關鍵的代碼
list_for_each_entry(fmt, &formats, lh);
retval = fmt->load_binary(bprm); //在這個循環中尋找可以解析當前可執行文件的代碼並加載出來,實際調用的是load_elf_binary函數
三、可執行程序的裝載與「莊生夢蝶」
莊周(調用execve的可執行程序)入睡(調用execve陷入內核),醒來(系統調用execve返回用戶態)發現本身是蝴蝶(被execve加載的可執行程序)
四、動態連接的可執行程序的裝載
*靜態連接:直接執行可執行程序的入口
*動態連接:裝載和連接以後ld將CPU的控制權交給可執行程序
二、實驗部分 ——Linux內核如何裝載和啓動一個可執行程序
(一)搭建環境
(查看代碼時,可使用shift+G直接跳到文件末尾)
(生成根文件系統時,將init hello放入rootfs地址中,這樣在執行exec文件時,就自動加載hello文件)
(二)使用gdb跟蹤sys_execve內核函數的處理過程
一、加載符號表,並鏈接到端口1234
二、設置斷點
三、執行
輸入c繼續運行,進入到sys_execve系統調用:
輸入s進行跟蹤:
new_ip是返回到用戶態的第一條指令的地址: