日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

LINUX内核分析第四周——扒开系统调用的三层皮

發布時間:2025/4/9 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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内核分析第四周——扒开系统调用的三层皮的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。