1. 程式人生 > >網易公開課《Linux核心分析》學習心得-Linux核心如何裝載和啟動一個可執行程式

網易公開課《Linux核心分析》學習心得-Linux核心如何裝載和啟動一個可執行程式

實驗

設定斷點sys_execeve,並繼續
這裡寫圖片描述
程式碼執行到了SyS_execve。在QEMU中執行exec,可以看到只能出現兩句,沒有完全執行完畢。
這裡寫圖片描述
設定斷點load_elf_binary和start_thread,並執行,可以看到程式碼停在了兩個斷點處。
這裡寫圖片描述
在程式碼停到SyS_execve處時候,list進入程式碼

1599            old = ACCESS_ONCE(mm->flags);
1600            new = (old & ~MMF_DUMPABLE_MASK) | value;
1601        } while (cmpxchg(&mm->flags
, old, new) != old); 1602 } 1603 1604 SYSCALL_DEFINE3(execve, 1605 const char __user *, filename, 1606 const char __user *const __user *, argv, 1607 const char __user *const __user *, envp) 1608 {

這段程式碼中DEFINE3中的filename對應檔名,argv對應環境變數,envp對應命令列
這裡寫圖片描述
繼續執行,進入do_execve的內部
這裡寫圖片描述


繼續執行直到start_thread,顯示的po new_ip中的記憶體地址是0x8048d0a。同時新開終端在menu檔案中執行readelf -h hello命令,可以發現入口點地址同樣是0x8048d0a。
這裡寫圖片描述
繼續執行直到程式碼執行完畢
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

分析

ELF

Linux的標準可執行格式是ELF,其格式為

:name:type:offset:string:mask:interpreter:flags

exec函式

所有的exec函式都是C庫定義的封裝例程,並利用execve()系統呼叫,也是Linux所提供的處理程式執行的唯一系統呼叫。ELF檔案會被預設對映到0x8048000這個地址。

sys_execve()服務例程接受下列引數:
- 可執行檔案路徑名的地址
- 以NULL結束的字串指標陣列的地址。每個字串表示一個命令列引數。
- 以NULL結束的字串指標陣列的地址。每個字串表示一個命令列引數。每個字串以NAME=value形式表示一個環境變數。

sys_execve()依次執行以下操作:
1. 動態地分配一個linux_binprm資料結構,並用新的可執行檔案的資料填充這個結構。
2. 呼叫path_lookup(),dentry_open()和path_release(),以獲得與可執行檔案相關的目錄項物件,檔案物件和索引節點物件。
3. 檢查是否可以由當前的程序執行該檔案,再檢查索引節點的i_writecount欄位,以確定可執行檔案沒有被寫入。
4. 在多處理器系統中,呼叫sched_exec()函式來確定最小負載CPU以執行程式。
5. 呼叫init_new_context()檢查當前程序是否使用自定義區域性描述符表。
6. 呼叫prepare_binprm()函式填充linux_binprm()資料結構。
7. 把檔案路徑名、命令列引數及環境串拷貝到一個或多個新分配葉框中。
8. 呼叫search_binary_handler()函式對formats連結串列進行掃描,並盡力應用每個元素的load_binary方法,把Linux_binprm資料結構傳遞給這個函式。只要load_binary方法成功應答了檔案的可執行格式,對formats的掃描就終止。
9. 如果在formats連結串列中,就釋放所分配的所有頁框並返回錯誤程式碼。
10. 否則,函式釋放linux_binprm資料結構,返回從這個檔案可執行格式的load_binary方法中所獲得的程式碼。

如果可執行檔案是靜態連結,可執行檔案對應的load_binary()需要將程式的正文段,資料段,bss段和堆疊段對映到程序線性區,然後把使用者態eip暫存器的內容設定為新程式的入口。

總結

程式是以可執行檔案的形式放到磁碟上的,可執行檔案既包括執行函式的目的碼,也包括這些函式所使用的資料。當裝入一個程式的時候,使用者可以提供影響程式執行方式的環境變數和命令列引數兩種資訊。
當execve()終止時,系統呼叫的程式碼不復存在,要執行的新成效已經被對映到程序的地址空間。這樣程式就可以成功運行了。