Linux內核如何裝載和啓動一個可執行程序

原創做品 轉載請註明出處linux

賀邦 《Linux內核分析》MOOC課程:http://mooc.study.163.com/course/USTC-1000029000git

第七講 Linux內核如何裝載和啓動一個可執行程序github


 

1、理論知識shell

Linux中,能夠從c源代碼生產一個可執行程序,這其中要通過預處理、編譯和連接的過程。能夠參考如下圖來理解這個過程:c#

其中,目標文件中至少有編譯後的機器指令代碼、數據,也還包括了連接時所需要的一些信息,好比符號表、調試信息、字符串等。這Linux中,可執行文件的格式如今主要是ELF格式(對應於Windows中PE格式)。ELF的格式以下:函數

連接,是收集、組織程序所需的不一樣代碼和數據的過程,以便程序能被裝入內存並被執行。連接過程分爲兩步:1.空間與地址分配;2.符號解析與重定位。設計

在Linux中,一個程序的執行是作爲一個新的進程,使用execve系統調用完成的。execve對應的系統調用是sys_execve,在其內部會解析可執行文件格式。對應的內核代碼,就是,在search_binary_handler中尋找符合文件格式對應的解析模塊。3d

對於ELF文件,retval = fmt->load_binary(bprm)實際上執行的就是load_elf_binary,其內部就是按照ELF文件格式來加載ELF文件的。這裏,咱們也能夠看到Linux是能夠支持多種可執行文件格式的,全部的格式處裏信息用一個結構體存儲在一個鏈表中,其中的load_binary是一個函數指針,對應於該中格式的可執行文件的加載方式;要想支持一種新的可執行文件,只須要向鏈表中註冊一個新的format結構體就能夠了,此種設計相似觀察者模式,具備很好的擴展性。指針

 

2、實驗過程調試

打開實驗樓中的虛擬機,在shell中依次運行如下命令,獲取本次實驗的代碼,並編譯運行

cd LinuxKernel

rm menu -rf

git clone https://github.com/mengning/menu.git

cd menu

mv test_exec.c test.c

make rootfs 

效果以下:

 

關閉QEMU窗口,在shell窗口中,cd LinuxKernel回退到LinuxKernel目錄,使用下面的命令啓動內核並在CPU運行代碼前停下以便調試:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S 

接下來,咱們就能夠水平分割一個新的shell窗口出來,依次使用下面的命令啓動gdb調試

gdb

(gdb) file linux-3.18.6/vmlinux

(gdb) target remote:1234

並在系統調用sys_execve的入口處設置斷點

(gdb) b sys_execve

繼續運行程序,在QEMU窗口中輸入exec,系統就會停在上面設置的斷點處,如圖:

 

接下來咱們能夠單步跟蹤sys_execve的內核代碼,也能夠經過設置如下斷點

b load_elf_binary

b start_thread

來完整地跟蹤進程的建立和啓動代碼!

 

3、總結

Linux系統能夠經過execve API啓動一個新進程,該API又呼叫sys_execve系統調用,負責將新的程序代碼和數據替換到新的進程中,打開可執行 文件,載入依賴的庫文件,

申請新的內存空間,最後執行 start_thread(regs, elf_entry, bprm->p) ,設置 new_ip, new_sp ,完成新進程的代碼和數據替換,而後返回,接下來就是執行新的進程代碼了。

相關文章
相關標籤/搜索