標籤(空格分隔): 20135321餘佳源linux
操做系統中,內核提供了用戶進程與內核進行交互的一組接口。這些接口讓應用程序受限的訪問硬件設備,提供了新進程與已有進程進行通訊的機制,也提供了申請操做系統其餘資源的能力。提供接口主要是爲了保證系統穩定可靠,避免應用程序恣意妄行。編程
知識點回顧:
系統調用:須要int 0x80模擬中斷讓硬件觸發。同步、主動地進入系統空間。
硬中斷:異步、被動地進入系統空間。CPU運行時發生錯誤則中斷,中斷後沒有進程調度。
軟中斷:中斷後還執行其餘進程調度。
系統調用過程:切換執行路徑&切換運行級別
系統調用表:定義於arch/i386/kernel/syscall_table.S ,映射系統調用號和與系統調用。
系統調用的過程:int 0x80 -> 中斷向量表 ->系統調用表 JUMP(EAX*4+基地址)根據系統調用號找到對應的系統調用代碼並執行。api
系統調用在用戶控件進程和硬件設備之間添加了一箇中間層,做用以下:安全
·爲用戶空間提供了一種硬件的抽象接口 ·系統調用保證了系統的穩定和安全 ·每一個進程都運行在虛擬系統中,而在用戶控件和系統的其他部分提供這樣一層公共接口
在Linux中,系統調用是用戶控件訪問內核的惟一手段;除異常和陷入外,他們是內核惟一的合法入口。異步
系統調用與API的不一樣在於運行級別的切換。
函數
應用程序經過在用戶空間實現的應用編程接口(API)而非直接經過系統調用來編程。性能
POSIX是應用編程接口的一個國際標準,C庫提供了POSIX的絕大部分API。操作系統
在Unix世界中,最流行的應用編程接口是基於POSIX標準的。翻譯
關於Unix接口設計:提供機制而不是策略
POSIX、API、C庫和系統調用之間的關係以下圖:
設計
asmlinkage——這是一個編譯指令,通知編譯器僅從棧中提取該函數的參數。
全部的系統調用都須要這個限定詞
其次函數返回long
系統調用在用戶空間和內核空間有不一樣的返回值類型,在用戶空間爲int在內核空間爲long。
定義系統調用:要訪問系統調用,一般經過C庫定義的函數調用來進行
例:asmlinkage long sys_getpid(void)
緣由:
由於用戶控件不能直接執行內核代碼,須要切換內核態,它須要用某種方式告知內核,本身須要執行一個系統調用,請求切換到內核態,這個通知內核的機制是軟中斷。
經過引起一個異常來促使系統切換到內核態去執行異常處理程序,此時的異常處理程序實際上即系統調用處理程序system_call(),中斷號128,指令以下:
int 128
或者
int 0x80
退出是iret
它與硬件體系結構緊密相關
新指令sysenter,比int中斷指令更快更專業。
參數傳遞最簡單的辦法是像傳遞系統調用號同樣,把這些參數也放在寄存器裏。在X86-32系統上,ebx、ecx、edx、esi、edi按順序存放前五個參數。須要六個或六個以上參數時應用一個單獨的寄存器存放指向全部這些參數在用戶空間地址的指針。
system_call()函數經過將給定的系統調用號與NR_syscalls做比較來檢查其有效性。大於等於返回-ENOSYS,不然執行相應系統調用:
call *sys_call_table(,%rax,8)
過程:
int 0x80 → 中斷向量表中找到對應中斷向量 →系統調用表
JMP(EAX*4 + system_xxx),乘以4是由於系統調用表中的表象是以64位存放的。
最重要的一種檢查就是檢查用戶提供的指針是否有效。內核必須保證:
指針指向的內存區域屬於用戶空間
指針指向的內存區域在進程的地址空間裏,進程決不能繞過內存訪問限制
進程不能繞過內存訪問限制
最後一項檢查針對是否有合法權限
對於每一個宏來講,都有2+2*n個參數
第一個參數對應着系統調用的返回值類型
第二個參數是系統調用的名稱
在之後是按照系統調用參數的順序排列的每一個參數的類型和名稱
內核在執行系統調用時處於進程上下文。
在進程上下文中,內核能夠:
休眠
說明系統調用可使用內核提供的絕大部分功能
能夠被搶佔
要求保證該系統調用是可重入的
1.在系統調用表的最後加入一個表項。
2.對於所支持的各類體系結構,系統調用號都必須定義於<asm/unistd.h>中
3.系統調用必須被編譯進內核映像,不能被編譯成模塊。——放進kernel/下的一個相關文件中便可,例如sys.c。
Linux自己提供了一組宏,用於直接對系統調用進行訪問。
_syscalln() //n的範圍從0到6,表明須要傳遞給系統調用的參數個數。
例如:
long open(const char *filename, int flags, int mode)=#define NR_open 5_syscall3(long, open,const char*, filename, int, flags, int, mode) 應用程序能夠直接用open()了。
對於每一個宏來講,都有(2+2xn)個參數:
1.系統調用的返回值類型 2.系統調用的名稱 之後按照系統調用參數的順序排列每一個參數的類型和名稱。
_NR_open在<asm/unistd.h>中定義。
這個宏會被擴展成爲內嵌彙編的C函數。
創建一個新的系統調用的好處:
問題是:
替代方法:
實現一個設備節點,並對此實現read()和write()。使用特定的信息進行檢索。
Linux儘可能避免每出現一種新的抽象就簡單地加入一個新的系統調用。
系統調用究竟是什麼?
執行系統調用的連鎖反應有?