1. 程式人生 > >2018-2019-1 20189206 《Linux核心原理與分析》第六週作業

2018-2019-1 20189206 《Linux核心原理與分析》第六週作業

linux核心分析學習筆記 ——第五章 系統呼叫的三層機制

學習重點——深入理解系統呼叫的過程


給MenuOS新增命令

新增命令的方式較為簡單,在LinuxKernel/menu/test.c目錄下,開啟test.c,main函式中的MenuConfig就是對應的系統呼叫的功能增加,之後在上面給出具體實現即可。之後就可以在MenuOS中使用該系統呼叫函式。

使用gdb跟蹤核心函式sys_getuid

上面在MenuOS中添加了功能,我這裡改成了getuid獲得當前使用者的id號,除錯步驟和實驗三基本一樣

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

凍結核心執行,然後利用gdb除錯工具,載入核心,連線埠1234
file linux-3.18.5/vmlinux
target remote:1234

之後在系統呼叫sys_getuid處設定斷點,當啟動MenuOS呼叫功能Getuid後 一旦呼叫系統函式,程式暫停。可以看到程式停在了sys_getuid處,但該系統呼叫是利用巨集函式實現的,經過預編譯處理後是sys_getuid的形式。

system_call位置設定斷點並不能停下,還是會停在sys_getuid這裡,因為system_call並不是一個正常的函式,只是一段彙編程式碼的起點,內部沒有嚴格的函式呼叫堆疊機制,所以gdb不能完成跟蹤任務

系統呼叫的處理過程

在使用者態中有一個c語言提供的APIxyz(),在使用者看來這就是系統呼叫,而xyz()中呼叫了SYSCALL來觸發系統呼叫。
即中斷向量0x80對應system_call中斷服務程式入口。

start_kernel函式執行核心啟動的初始化工作,其中會呼叫trap_init函式,在上圖所示目錄中可以看到以下程式碼。

當接受到int 0x80 中斷請求後,通過set_sysytem_trap_gate函式將中斷向量和入口函式繫結,將直接進入中斷,也就是跳轉到system_call的位置。

這裡將trap_init中繫結中斷向量和入口函式的程式碼中的巨集定義實現,可以看到系統呼叫對應的中斷向量就是0x80

system_call函式的理解


system_call是一段中斷服務程式入口的彙編程式碼,就是系統呼叫的處理過程,是系統呼叫使用者態和系統呼叫核心態想轉換的過程。

中斷過程都會有現場保護和恢復現場程式碼一開始的SAVE_ALL和restore_all就是實現了中斷上下文過程。

sys_call_table是一個系統呼叫表,EAX暫存器儲存了傳遞的系統呼叫號,來呼叫相應的系統呼叫,呼叫結束,EAX暫存器還要儲存系統呼叫的返回值。

syscall_exit中判斷當前的任務是否需要程序排程,如果需要程序排程進入syscall_exit_work,執行程序排程,結束後恢復現場返回使用者態。

系統呼叫函式

上圖所示是系統呼叫system_call的流程圖

  • SAVE ALL 是中斷髮生後儲存現場的巨集
  • cmpl $(nr_syscalls),%eax判斷檢查系統呼叫號的合法性如果系統呼叫號大於nr_syscalls 那麼出現異常,跳入異常處理syscall_badsys
    -call *sys_call_table(,%eax,4)通過系統呼叫號在系統呼叫表中找到相應的系統呼叫核心處理函式,就是將函式API和系統呼叫聯絡起來。
  • movl %eax,PT_EAX(%esp)作用是將系統呼叫返回值入棧
  • syscall exit檢查是否有任務要處理,如果發生程序排程需要進入syscall_exit_work
    • 程序間通訊會有訊號發生,所以進入程序排程後會有work_pendingwork_notifysig訊號處理、和work_resched等處理 work_resched中的schedule存著程序排程的程式碼,也就是程序排程的時機點
  • restore_alliret用於恢復現場和返回使用者態。

Linux核心編譯實踐中遇到的問題

  • 在為函式新增系統呼叫號時的路徑問題
    sudo gedit /usr/src/linux-3.14.40/arch/x86/syscall/syscall_32.tbl。
    根據文件我在這個路徑下並沒有找到syscall資料夾,也就無法修改 syscall_32.tbl

最後參考了一篇部落格,我想問題應該是核心版本更新,目錄有了一定的修改,最後找到了路徑

  • 使用 make bzImage時出現錯誤

根據錯誤提示,我考慮問題出在了核心呼叫時新增的系統呼叫格式出現了問題對比之後,我對程式碼進行更改,結果編譯成功

核心編譯時間非常久,編譯好了之後無法啟動,錯誤問題如下

後來發現是虛擬機器的記憶體不足的原因,重新設定了虛擬機器的記憶體之後成功進入虛擬機器,利用命令可以看到該核心版本已經是剛剛編譯的4.18.18

寫一個程式呼叫我們剛剛建立的系統呼叫,返回值得到的是我們當時設定的返回值

參考這篇部落格給我提供瞭解決問題的很多靈感:
Linux4.18.9新增系統呼叫傳遞引數示例