系統調用(一)
(一):與內核通信
系統調用在用戶空間和硬件設備之間加入了一個中間層。該層主要有三個作用:
?1:他為用戶空間提供了一種硬件的抽象接口
?2:系統調用保證了系統的穩定和安全。
?3:每個進程都運行在虛擬系統中,而在用戶空間和系統的其余部分提供這樣一層公共接口,也是出於這種考慮。
在Linux中,系統調用是用戶空間訪問內核的唯一手段。
(二):API,POSIX,C庫
普通情況下。應用程序通過在用戶空間實現的應用編程接口(API)而不是直接通過系統調用來編程。一個API定義了一組應用程序使用的編程接口。
以下我們看一下POSIX,API。和C庫以及系統調用之間的聯系。
(三):系統調用
首先我們先看一下一個比較簡單的系統調用的實現:
SYSCALL_DEFINE0(getpid)
{
?return task_tgrid_vnr(current);
}
註意,定義中並沒有規定他要怎樣實現。
當中SYSCALL_DFINE0不過一個宏。他定義一個無參數的系統調用。尾展開後的代碼為:
asmlinkage long sys_getpid(void)
那麽我們來看一下怎樣定義系統調用:
首先,註意函數聲明中的asmlinkage限定詞。這是一個編譯指令,通知編譯器只從棧中提取該函數的參數。
全部的系統調用都須要這個限定詞。
其次。函數返回long。為了保證32位和64位系統的兼容,系統調用在用戶空間和內核空間有不同的返回值類型,在用戶空間為int,在內核空間為long。
最後,註意系統調用get_pid()在內核中被定義成sys_getpid()。
這是一個命名規則。
1:系統調用號
在Linux中,每個系統調用被賦予一個系統調用號。這種話,每個系統調用都會關聯一個系統調用。
系統調用號很重要,一旦分配就不能再有不論什麽改變。否則編譯好的應用程序就會崩潰。
此外。假設一個系統調用被刪除,他所占用的系統調用號也不同意被回收利用,否則,曾經編譯過的代碼會調用這個系統調用,但其實卻調用的是另外一個系統調用。
在Linux中有一個”未實現“的系統調用sys_ni_syscall()。他除了返回-ENOSYS之外不做不論什麽事情,這個系統調用就是專門針對無效的系統調用而設的。
假設一個系統調用被刪除或者是變為不可用,這個系統調用就負責”填空補缺“。
在sys_call_table中,是內核記錄的全部的已註冊過的系統調用的列表。
在x84-64中,定義在文件arch/i386/kernel/syscall_64.c中。
這個表為沒一個有效的系統調用指定了唯一的系統調用號。
如今我們來看一下:
const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
/*
*Smells like a like a compiler bug -- it doesn‘t work
*when the & below is removed.
*
* 看上去像是一個編譯器bug -- 當以下的&移除之後,他就不能工作了
*/
[0 ... __NR_syscall_max] = &sys_ni_syscall,
#include <asm/unistd_64.h>
};
2:系統調用的性能
Linux系統調用比其它操作系統運行的要快。
Linux很短的上下文切換時間是一個重要的原因,進出內核都被優化的簡單介紹高效。同一時候。系統調用處理函數和每個系統調用本身也都很簡潔。
(四):系統調用處理函數
因為用戶空間的程序是無法運行內核程序的。全部須要一個機制來通知內核運行某個系統調用。
通知內核的機制是通過軟中斷來實現的:通過引發一個異常來促使系統切換到內核態去運行異常處理程序。
此時的一場處理程序就是系統調用處理程序。有關於中斷,會在後面具體學習。
1:指定恰當的系統調用
因為全部的系統調用陷入內核的方式都是一樣的。所以,須要將系統調用號一並傳給內核。在x86上,系統調用號是通過eax寄存器來傳遞給內核的。在陷入內核之前,用戶空間就把對應的系統調用所對應的號傳入eax中。
system_call()函數通過將給定的系統調用號與NR_syscalls做比較來檢查其有效性。
假設大於或等於NR_syscalls。該函數就返回-ENOSYS。
否則,就運行對應的系統調用:
call *sys_call_table(,%rax,8)
因為系統調用表中的表項是以63位類型存放的,所以內核須要將給定的系統調用號乘以4,然後用所得的結果在該表中查詢位置。
2:參數傳遞
同系統調用號一樣,進行參數傳遞的時候。也能夠通過寄存器將參數傳遞到內核中。在x86-32系統上。ebx,ecx,edx,esi,edi依照順序存放前5個參數,此外,應該用一個單獨的寄存器存放指向全部這些參數在用戶空間地址的指針。
以下我們看一下系統調用的過程:
給用戶空間的返回值也是通過寄存器傳遞的。
在x86系統上。他存放在eax寄存器上。
系統調用(一)