系統調用的工作機制

所有的程序員在寫程序的時候都離不開通過庫函數的方式和系統調用打交道


什么是用戶態和內核態?(從CPU指令級別的角度)

一般現代CPU都有幾種不同的指令執行級別,什么樣的程序可以執行什么的指令
在高執行級別下,代碼可以執行特權指令,訪問任意的物理地址,這時CPU執行級別就對應著內核態
而在相應的低級別執行狀態下,代碼的掌控范圍會受到限制。只能在對應級別允許的范圍內活動
舉例:intel x86 CPU有四種不同的執行級別0-3,Linux只使用了其中的0級3級分別來表示內核態用戶態


如何區分用戶態和內核態?(從進程地址空間的角度)

cs寄存器的最低兩位表明了當前代碼的特權級
CPU每條指令的讀取都是通過cs:eip這兩個寄存器:
????? 其中? cs是代碼段選擇寄存器,eip是偏移量寄存器
上述判斷由硬件完成

在32位x86的機器上,有4G的進程地址空間(邏輯地址),在內核態的時候全都可以訪問,在用戶態的時候,只能訪問0x00000000-0xbfffffff的地址空間。也就是說0xc0000000以上的地址空間只能在內核態下訪問


中斷處理是從用戶態進入內核態主要的方式

當從用戶態切換到內核態的時候,必須用戶態的寄存器上下文保存起來,同時設置內核態的寄存器內容
中斷/int指令會在堆棧上保存一些寄存器的值
????? 如:用戶態棧頂地址、當時的狀態字、當時的 cs:eip 的值
同時設置內核態的棧頂地址、內核態的狀態字,中斷處理程序的入口地址 cs:eip 的值(對于系統調用來講,它是指向system_call函數)


中斷/int指令發生后第一件事就是保護現場

保護現場就是進入中斷程序保存需要用到的寄存器的數據

當進入到中斷處理程序后,一開始就執行SAVE_ALL,把其它的一些寄存器的值push到內核堆棧里面去

SAVE_ALL

中斷處理結束前最后一件事是恢復現場

恢復現場就是退出中斷程序恢復寄存器的數據

當中斷處理程序結束之后,它會RESTORE_ALL,把保存的用戶態的寄存器再pop出來到當前的CPU里面,最后iret,iret指令與中斷信號(包括int指令)發生時CPU做的動作剛好相反

RESTORE_ALL

中斷處理的完整過程

interrupt(ex:int 0x80)
save cs:eip/ss:esp/eflags(current) to kernel stack, then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack)
SAVE_ALL
....? // 內核代碼,完成中斷服務,發生進程調度
RESTORE_ALL
iret
pop cs:eip/ss:esp/eflags from kernel stack

SAVE_ALL....如果發生了進程調度,那么當前的狀態都會暫時保存在系統里面,當下一次發生進程調度切換回當前進程的時候,就會接著把它執行完,RESTORE_ALL....


以系統調用為例,看中斷具體是怎么執行的

系統調用通過軟中斷向內核發出一個明確的請求,是操作系統為用戶態進程與硬件設備進行交互提供的一組接口

封裝例程 (wrapper routine),唯一目的就是發布系統調用,讓程序員在寫代碼的時候不需要用匯編指令來觸發一個系統調用,而是直接調用一個函數就可以觸發一個系統調用

應用編程接口(application program interface, API) 只是一個函數定義。一般每個系統調用對應一個封裝例程,庫再用這些封裝例程定義出給用戶的API。但并不是每個API都對應一個特定的系統調用,API可能直接提供用戶態的服務,例如一些數學函數。一個單獨的API可能調用幾個系統調用,不同的API可能調用了同一個系統調用

應用程序、封裝例程、系統調用處理程序及系統調用服務例程之間的關系

User Mode 用戶態????? Kernel Mode 內核態

xyz()函數,是系統調用對應的API,這個應用程序編程接口里面封裝了一個系統調用,這個系統調用會觸發一個int 0x80的中斷,0x80這個中斷向量對應著system_call這個內核代碼的起點,這個內核代碼里面會有SAVE_ALL,然后執行到sys_xyz()中斷服務程序,進入程序里面處理,在中斷服務程序執行完之后會ret_from_sys_call,在return的過程中可能會發生進程調度(這是一個進程調度的時機),如果沒有進程調度,就會iret,回到用戶態接著執行

Summary

系統調用的三層皮:API、中斷向量對應的system_call、中斷服務程序sys_xyz

當用戶態進程調用一個系統調用時,CPU切換到內核態并開始執行一個內核函數,在Linux中是通過執行int $0x80來執行系統調用的,這條匯編指令產生向量為128的編程異常。(Intel Pentium II中引入了sysenter指令(快速系統調用),2.6已經支持)

內核實現了很多不同的系統調用,進程必須指明需要哪個系統調用,這需要傳遞一個名為系統調用號的參數,使用eax寄存器(系統調用號將xyz()和sys_xyz()關聯起來了)


系統調用的參數傳遞方法

普通函數調用的時候,可以采用把參數壓棧的方式傳遞參數。但是從用戶態到內核態,怎么傳遞參數呢?

system_call是linux中所有系統調用的入口點,每個系統調用至少有一個參數,即由eax傳遞的系統調用號

一個應用程序調用fork()封裝例程,那么在執行int $0x80之前就把eax寄存器的值置為2(即__NR_fork)
這個寄存器的設置是libc庫中的封裝例程進行的,因此用戶一般不關心系統調用號
進入sys_call之后,立即將eax的值壓入內核堆棧

寄存器傳遞參數具有如下限制:
1)每個參數的長度不能超過寄存器的長度,即32位
2)在系統調用號(eax)之外,參數的個數不能超過6個(ebx, ecx,edx,esi,edi,ebp)
超過6個怎么辦?

如果超過6個,就把某一個寄存器作為一個指針,指向一塊內存,進入到內核態之后可以訪問到所有的地址空間,通過內存來傳遞參數


通過庫函數API使用系統調用獲取系統當前時間

通過庫函數API使用系統調用獲取系統當前時間

用匯編方式觸發系統調用獲取系統當前時間

用匯編方式觸發系統調用獲取系統當前時間

系統調用傳遞第一個參數使用ebx,這里是NULL
使用eax傳遞系統調用號,這里time是13
系統調用的返回值使用eax存儲,和普通函數一樣


(完)


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 安大大 + 原創作品轉載請注明出處 + 《Linux操作系統分析》MOOC課程 用戶態、內核態和中斷處理過程 程序...
    夏天的籃球閱讀 1,697評論 0 0
  • 簡介 lab3 將主要實現能運行被保護的用戶模式環境(protected user-mode environmen...
    找不到工作閱讀 6,975評論 1 8
  • 一、溫故而知新 1. 內存不夠怎么辦 內存簡單分配策略的問題地址空間不隔離內存使用效率低程序運行的地址不確定 關于...
    SeanCST閱讀 7,856評論 0 27
  • 原文地址:C語言函數調用棧(一)C語言函數調用棧(二) 0 引言 程序的執行過程可看作連續的函數調用。當一個函數執...
    小豬啊嗚閱讀 4,650評論 1 19
  • 晨起,風雨大作。路遇一對母女。小姑娘被母親的懷抱與母親手中的傘隔絕在風雨之外。 公交車上,各種濕噠噠的雨傘,總會有...
    歲月嘉禮閱讀 221評論 0 0