LINUX内核分析第四周——扒开系统调用的三层皮
生活随笔
收集整理的這篇文章主要介紹了
LINUX内核分析第四周——扒开系统调用的三层皮
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
LINUX內核分析第四周——扒開系統調用的三層皮
李雪琦 + 原創作品轉載請注明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
一、用戶態、內核態和中斷處理過程
1. 用戶態和內核態
CPU指令執行級別:
- 執行特權指令,訪問任意的物理地址——內核態。
低級別:代碼只能在級別允許的特定范圍內活動——用戶態。在日常操作下,執行系統調用的方式是通過庫函數,庫函數封裝系統調用,為用戶提供接口以便直接使用。
- Intel x86 CPU有四種不同的執行級別0~3,Linux只用其中的0和3來表示內核態和用戶態。
- 區分內核態和用戶態:CPU每條指令的讀取都是通過cs:eip,cs寄存器最低兩位表明了當前代碼的特權級。
- 內核態下可訪問所有地址空間。
- 0xc0000000(邏輯地址)以上的空間只能在內核態下訪問。
- 0x00000000 ~ 0xbfffffff 內核態和用戶態均可訪問。
用戶態轉換為內核態的主要方式:中斷。
2. 中斷處理
- 用戶態到內核態的切換:必須保存用戶態的寄存器上下文,包括用戶態棧頂地址、當時的狀態字、cs:eip的值,以及內核態的棧頂地址、當時的狀態字、中斷處理程序入口。
- 中斷發生后的第一件事:保存現場(SAVE_ALL:保存需要用到的寄存器數據)。
- 中斷處理結束前的最后一件事:恢復現場(RESTORE_ALL:退出中斷程序,恢復保存寄存器的數據)。
二、系統調用概述
1. 系統調用的意義:
操作系統為用戶態進程與硬件設備進行交互提供了一組接口,就是系統調用。
- 遠離底層硬件編程
- 安全性
- 可移植性
2. API - 應用編程接口
與系統調用區別:
- API只是一個函數定義。
- 系統調用是通過軟中斷向內核發出一個明確的請求。
- 一般每個系統調用對應一個封裝例程,庫再用這些封裝例程定義出用戶的API,方便用戶使用。也就是說,API與系統調用不是一一對應的。
API可以:
- 直接提供用戶態服務
- 一個單獨的API可能調用幾個系統調用
- 不同的API可能調用了同一個系統調用
返回值:
- 大部分封裝例程返回一個整數
- -1表示失敗,不能滿足請求
- errno 特定出錯碼
3.所謂“扒開系統調用的三層皮”
- API(xyz)
- 中斷向量(system_call)
- 中斷服務程序(sys_xyz)
1.系統調用的服務例程中,中斷向量0x80與system_call綁定起來。(Linux中可以通過執行int $128來執行系統調用。)
2.system_call是linux中所有系統調用的入口點,每個系統調用至少有一個參數,即系統調用號。
3.系統調用號將xyz與sys_xyz關聯起來。調用號在eax中。
系統調用的參數傳遞:
- 函數調用——壓棧
- 用戶態到內核態——寄存器傳遞。
每個參數長度不能超過32位,個數不能超過6個。
超過的話,使某個寄存器中存儲指針,指向內存,內存中存儲參數。
三、使用庫函數API和C代碼中嵌入匯編代碼觸發同一個系統調用
1.使用庫函數API獲取系統當前時間
使用time(),代碼如下:
#include<stdio.h> #include<time.h> int main() { time_t tt; struct tm *t;//構造一個結構體,方便讀取 tt = time(NULL);//time系統調用 t = localtime(&tt); printf("time:%d:%d:%d:%d:%d:%d\n", t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); return 0; }2.使用C代碼中嵌入匯編代碼觸發系統調用獲取系統當前時間
代碼如下:
#include<stdio.h> #include<time.h> int main() { time_t tt; struct tm *t; asm volatile( "mov $0,%%ebx\n\t" # 把ebx清零,相當于傳參數 "mov $0xd,%%eax\n\t"# 把0xd放入eax中,即系統調用號13,指time "int $0x80\n\t" "mov %%eax,%0\n\t" # 返回值是在eax中,%0指tt,把返回值放到tt中去。 : "=m" (tt) ); t = localtime(&tt); printf("time:%d:%d:%d:%d:%d:%d\n", t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); return 0; }四、使用庫函數API和C代碼中嵌入匯編代碼兩種方式使用同一個系統調用
在這里我選擇的是第7號系統調用,waitpid。
1.使用庫函數API:
2.嵌入匯編:
3.運行結果:
五、總結
- 即便是最簡單的程序,在進行輸入輸出等操作時也會需要調用操作系統所提供的服務,也就是系統調用。
- Linux下的系統調用是通過中斷(int 0x80)來實現的。
- 在執行int 80指令時,寄存器 eax 中存放的是系統調用的功能號,而傳給系統調用的參數則必須按順序放到寄存器 ebx,ecx,edx,esi,edi 中,當系統調用完成之后,返回值可以在寄存器 eax 中獲得。
- Linux 采用的是 C 語言的調用模式,這就意味著所有參數必須以相反的順序進棧,即最后一個參數先入棧,而第一個參數則最后入棧。
轉載于:https://www.cnblogs.com/lxq20135309/p/5296439.html
總結
以上是生活随笔為你收集整理的LINUX内核分析第四周——扒开系统调用的三层皮的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM学习历程—HDU2476 Stri
- 下一篇: Tesseract 3.02 OCR文字