《Linux內核分析》第四周學習總結編程
——扒開系統調用的三層皮數據結構
姓名:王瑋怡 學號:20135116app
理論總結部分:函數
第一節 用戶態、內核態和中斷學習
1、用戶態、內核態和中斷處理過程spa
通常現代CPU都有幾種不一樣的指令執行級別操作系統
一、用戶態指針
在相應的低級執行狀態下,代碼的掌控範圍會受到限制,此時爲用戶態。blog
二、內核態接口
在高執行級別下,代碼能夠執行特權指令,訪問任意的物理地址,這種CPU執行級別就對應着內核態。
三、舉例
Intel x86 CPU有四種不一樣的執行級別0-3,Linux只使用了0級和3級分別表示內核態和用戶態。
四、Linux代碼中如何區分用戶態和內核態
(1)cs寄存器的最低兩位代表當前代碼的特權級
(2)CPU每條指令的讀取都是經過cs:eip這兩個寄存器,其中cs是代碼段選擇寄存器,eip是偏移量寄存器
(3)上述判斷有硬件完成
(4)通常來講在Linux中,地址空間是一個顯著的標誌:
0xc0000000以上的地址空間只能在內核態下訪問
0x00000000-oxbfffffff的地址空間在兩種狀態下都能訪問
(注意:這裏說的地址空間爲邏輯地址而不是物理地址)
五、中斷處理是從用戶態進入內核態的主要方式
系統調用只是一種特殊的中斷
(1)從內核態切換到用戶態時必須保存用戶態的寄存器上下文,同時也要將內核態的寄存器相應值放入當前CPU中
(2)中斷/int指令會在堆棧上保存一些寄存器的值,如用戶態棧頂地址、當前的狀態字、當時的cs:eip的值,同時還保存內核態棧頂地址、當前的狀態字以及中斷處理程序的入口(cs:eip的值)
(3)中斷信號/int指令發生後進入中斷處理程序,執行的第一個動做是SAVE_ALL,將其餘寄存器的值push到內存堆棧中去,保存現場;中斷處理程序結束前最後一件事是恢復現場RESTORE_ALL,將用戶態的寄存器再popl出來到當前CPU中;iret指令與中斷信號(包括int指令)發生時的CPU的動做正好相反
(4)中斷處理的完整過程
第二節 系統調用概述
1、系統調用概述和系統調用的三層皮
一、系統調用的意義
二、操做系統提供的API(應用編程接口)和系統調用的關係
(1)API只是一個函數定義;系統調用經過軟中斷(rap)向內核發出一個明確的請求
(2)Libc庫定義的一些API引用了封裝例程(wrapper routine,惟一目的就是發佈系統調用)
通常每一個系統調用對應一個封裝例程
庫再調用這些封裝例程定義出給用戶的API
注意:
三、系統調用的三層皮:xyz、system_call和sys_xyz
(1)當用戶態進程調用一個系統調用時,CPU切換到內核態並開始執行一個內核函數
在Linux中經過int$0x80來執行系統調用——產生向量爲128的編程異常
(2)傳參:內核實現了不少不一樣的系統調用,進程須要經過傳遞一個名爲系統調用編號的參數來指明須要哪一個系統調用(經過eax寄存器來實現傳遞)——系統調用號將xyz和sys_xyz關聯起來
(3)系統調用的參數傳遞方法
a.系統調用也須要輸入輸出參數,如實際值、用戶態進程地址空間的變量的地址、包含指向用戶態函數的指針的數據結構的地址
b.system_call是Linux中全部系統調用的入口點,每一個系統調用至少有一個參數,即由eax傳遞的系統調用號
c.寄存器傳遞參數的限制:
每一個參數的長度不能超過寄存器的長度,即32位
在系統調用號(eax)以外,參數的個數不能超過6個(ebx、ecx、edx、esi、edi、ebp),若是超過6個,就把其中某一個寄存器做爲一個指針,指向一塊內存,進入內核態能夠訪問全部的地址空間,經過內存傳遞數據
實驗部分 :使用庫函數API和C代碼嵌入彙編代碼觸發同一個系統調用
1、使用庫函數API獲取當前進程的進程號(getpid())
運行結果以下:
使用getpid(),定義int型的數值變量tt(返回值)
2、使用C代碼嵌入彙編代碼觸發系統調用獲取當前進程的進程號(getpid())
mov $0,%%ebx\n\t 系統調用傳遞第一個參數使用容ebx,這裏是NULL(將ebx寄存器清零)
mov $0x14,%%eax\n\t 使用eax傳遞系統調用號,這裏getpid是20
mov %%eax,%0\n\t 系統調用的返回值使用eax存儲,tt變量
運行結果以下: