呂鬆鴻 + 原創做品轉載請註明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000linux
中斷:中斷處理是從用戶態進入內核態主要的方式。編程
用戶態和內核態的轉換:安全
中斷處理的完整過程
進入中斷程序,保存寄存器數據 SAVE_ALL -..//內核代碼,完成中斷服務,發生進程調度
RESTORE_ALL//退出中斷程序,恢復寄存器數據
iret(pop cs:eip/ss:esp/eflags from kernel stack)//對應着中斷信號或int指令,與發生時CPU動做相反
1.系統調用:系統調用只是一種特殊的中斷。app
這是用戶態進程主動要求切換到內核態的一種方式,用戶態進程經過系統調用申請使用操做系統提供的服務程序完成工做。而系統調用的機制其核心仍是使用了操做系統爲用戶特別開放的一箇中斷來實現。函數
系統調用的意義:spa
把用戶從底層的硬件編程中解放出來
極大的提升了系統的安全性
使用戶程序具備可移植性
API和系統調用:操作系統
應用編程接口(application program interface,API)和系統調用是不一樣的指針
API只是一個函數定義
系統調用經過軟中斷向內核發出一個明確求
Libc庫定義的一些API引用了封裝例程:code
通常每一個系統調用對應一個封裝例程
庫再用這些封裝例程定義出給用戶的API
不是每一個API都對應一個特定的系統調用:blog
API可能直接提供用戶態的服務(如一些數學函數)
一個單獨的API可能調用幾個系統調用
不一樣的API可能調用了同一個系統調用
返回值
大部分封裝例程返回一個整數,其值的含義依賴於相應的系統調用 -1在多數狀況下表示內核不能知足進程的請求 Libc中定義的errno變量包含特定的出錯碼
應用程序、封裝例程、系統調用處理程序、系統調用服務例程之間的關係
2.系統調用的三層皮
•API(xyz)
•中斷向量(system_call)
•中斷服務程序(sys_xyz)
當用戶態進程調用一個系統調用時,CPU切換到內核態並開始執行一個內核函數。
Linux中是經過執行int $0x80來執行系統調用,這條彙編指令產生向量爲128的編程異常 —— 即中斷向量0x80與System_call綁定起來。
系統調用號將函數xyz()
和中斷服務程序sys_xyz
關聯起來。
3. 參數傳遞
內核實現了不少不一樣的系統調用,進程用系統調用號這個參數指明須要哪一個系統調用。
system_call是linux中全部系統調用的入口點,每一個系統調用至少有一個參數,使用eax寄存器傳遞系統調用號。
寄存器傳遞參數的限制
- 每一個參數的長度不能超過寄存器的長度,即32位 - 在系統調用號(eax)以外,參數的個數不能超過6個(ebx,ecx,edx,esi,edi,ebp) - 超過6個的狀況下,使用某一個寄存器做爲指針,進入內核態以後能夠訪問全部的地址空間,經過某一片區域傳遞參數。
1.使用庫函數API獲取系統當前進程pid值
在這裏我使用的是獲取進程pid的庫函數getpid()
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
int main(int argc, const char *argv[]) { pid_t tt; tt = getpid(); printf("%u\n", tt); return 0; }
2.使用c代碼中嵌入彙編代碼
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
int main(int argc, const char *argv[]) { pid_t tt; asm volatile( "mov $0x14, %%eax\n\t"//系統調用號14放在eax中
"int $0x80\n\t" //系統調用中斷
"mov %%eax, %0\n\t"//取出eax中返回的值
:"=m" (tt) ); printf("%u\n", tt); return 0; }
Linux下的系統調用是經過中斷(int 0x80)來實現的。
能夠經過庫函數API使用系統調用或者用匯編方式觸發系統調用。