標籤:
本周的實驗淺析了系統調用的工作過程,下面通過使用庫函數API和C代碼中嵌入彙編代碼兩種方式使用同一個系統調用加深對其過程的理解。
系統調用列表:http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
本次實驗使用了20號系統調用getpid來擷取當前核心名稱和其它資訊。
getpid 簡單案例
// C語言使用庫函數API#include <stdio.h>#include <unistd.h>int main() { pid_t tt; tt = getpid(); printf("%u\n", tt); return 0;}
// C代碼中嵌入彙編代碼#include <stdio.h>#include <unistd.h>int main() { pid_t tt; asm volatile ( "movl $0x20, %%eax\n\t" "int $0x80\n\t" "movl %%eax, %0\n\t" :"=m"(tt) ); printf("%u\n", tt); return 0;}
上述兩種方法都已實現,如下:
C語言內嵌彙編代碼要求先聲明輸出參數,然後聲明輸出參數值。因為上述代碼中不需要傳入參數,所以只有一個輸出值。
對於內嵌彙編調用 system_call():
1. 系統調用號放入 eax 中。
2. 系統調用的參數,按順序存入相應寄存器中。
3. 傳回值使用 eax 傳遞值。
因為中斷( 包括異常 )是從使用者態進入核心態的唯一方式,所以在上述代碼中使用了中斷( "int $0x80\n\t" 這句 ),然後中斷處理常式SAVE_ALL儲存現場,隨後就進入了核心態進行下一步的操作。
通過本周的作業,更加熟悉了系統調用的本質,以及系統調用和中斷的關聯。系統調用是使用者態和核心態的橋樑,而具體的措施就是中斷。上面我們採用內嵌彙編編寫的代碼,在運行時,通過eax準備系統調用號,使用ebx、ecx等傳遞具體參數,當我們觸發0x80中斷時,經過中斷處理常式,我們就進入了核心態。
總結:
通過這一周的學習,更加熟悉了系統調用的本質,和系統調用與中斷的關聯。
一、中斷處理是從使用者態進入核心態主要的方式,系統調用是一種特殊的中斷。
中斷處理的完整過程( 由中斷訊號或者 int 指令完成 ):
- 從當前進程的描述符中提取其核心棧的 ss0 及 esp0 資訊。
- 使用 ss0 和 esp0 指向的核心棧將當前進程的 cs, eip, eflags, ss, esp 資訊儲存起來,這個過程也完成了由使用者棧到核心棧的切換過程,同時儲存了被暫停執行的程式的下一條指令。
- 將先前由中斷向量檢索得到的中斷處理常式的 cs, eip 資訊裝入相應的寄存器,開始執行中斷處理常式,這時就轉到了核心態的程式執行了。
- 若完成中斷服務之後不發生進程調度,則繼續執行指令( RESTORE_ALL 和 iret ),然後返回到原來的狀態;若發生進程調度,那麼當前發生的狀態都會暫時的儲存在系統中,當下一次發生調度再次回到當前進程時就繼續執行指令 RESTORE_ALL 和 iret。
二、系統調用的工作機制:
- 使用者態中的 xyz() 函數就是系統調用所對應的系統 API;
- 在這個 API 中將系統調用封裝好,並在執行時觸發 int 0x80 這個中斷。這個中斷在對應了核心態中的 System_call();
- System_call() 中可能會執行中斷服務程式 sys_xyz()。
- 中斷服務完成後有可能會發生進程調度。如果沒有發生進程調度,那麼執行 iret 返回使用者態繼續執行下面的其他指令。
總結:
系統調用的三層皮:xyz( API )、system_call( 中斷向量 )和 sys_xyz( 服務程式 )。
李若森
原創作品轉載請註明出處
《Linux核心分析》MOOC課程 http://mooc.study.163.com/course/USTC-1000029000
使用庫函數API和C代碼中嵌入彙編代碼兩種方式使用同一個系統調用