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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

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

發(fā)布時(shí)間:2025/4/9 linux 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LINUX内核分析第四周——扒开系统调用的三层皮 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

LINUX內(nèi)核分析第四周——扒開系統(tǒng)調(diào)用的三層皮

李雪琦 + 原創(chuàng)作品轉(zhuǎn)載請(qǐng)注明出處 + 《Linux內(nèi)核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

一、用戶態(tài)、內(nèi)核態(tài)和中斷處理過程

1. 用戶態(tài)和內(nèi)核態(tài)

CPU指令執(zhí)行級(jí)別:

  • 執(zhí)行特權(quán)指令,訪問任意的物理地址——內(nèi)核態(tài)。
  • 低級(jí)別:代碼只能在級(jí)別允許的特定范圍內(nèi)活動(dòng)——用戶態(tài)。在日常操作下,執(zhí)行系統(tǒng)調(diào)用的方式是通過庫(kù)函數(shù),庫(kù)函數(shù)封裝系統(tǒng)調(diào)用,為用戶提供接口以便直接使用。

  • Intel x86 CPU有四種不同的執(zhí)行級(jí)別0~3,Linux只用其中的0和3來(lái)表示內(nèi)核態(tài)和用戶態(tài)。
  • 區(qū)分內(nèi)核態(tài)和用戶態(tài):CPU每條指令的讀取都是通過cs:eip,cs寄存器最低兩位表明了當(dāng)前代碼的特權(quán)級(jí)。
  • 內(nèi)核態(tài)下可訪問所有地址空間。
  • 0xc0000000(邏輯地址)以上的空間只能在內(nèi)核態(tài)下訪問。
  • 0x00000000 ~ 0xbfffffff 內(nèi)核態(tài)和用戶態(tài)均可訪問。
  • 用戶態(tài)轉(zhuǎn)換為內(nèi)核態(tài)的主要方式:中斷。

2. 中斷處理

  • 用戶態(tài)到內(nèi)核態(tài)的切換:必須保存用戶態(tài)的寄存器上下文,包括用戶態(tài)棧頂?shù)刂?、?dāng)時(shí)的狀態(tài)字、cs:eip的值,以及內(nèi)核態(tài)的棧頂?shù)刂贰?dāng)時(shí)的狀態(tài)字、中斷處理程序入口。
  • 中斷發(fā)生后的第一件事:保存現(xiàn)場(chǎng)(SAVE_ALL:保存需要用到的寄存器數(shù)據(jù))。
  • 中斷處理結(jié)束前的最后一件事:恢復(fù)現(xiàn)場(chǎng)(RESTORE_ALL:退出中斷程序,恢復(fù)保存寄存器的數(shù)據(jù))。

二、系統(tǒng)調(diào)用概述

1. 系統(tǒng)調(diào)用的意義:

操作系統(tǒng)為用戶態(tài)進(jìn)程與硬件設(shè)備進(jìn)行交互提供了一組接口,就是系統(tǒng)調(diào)用。

  • 遠(yuǎn)離底層硬件編程
  • 安全性
  • 可移植性

2. API - 應(yīng)用編程接口

與系統(tǒng)調(diào)用區(qū)別:

  • API只是一個(gè)函數(shù)定義。
  • 系統(tǒng)調(diào)用是通過軟中斷向內(nèi)核發(fā)出一個(gè)明確的請(qǐng)求。
  • 一般每個(gè)系統(tǒng)調(diào)用對(duì)應(yīng)一個(gè)封裝例程,庫(kù)再用這些封裝例程定義出用戶的API,方便用戶使用。也就是說(shuō),API與系統(tǒng)調(diào)用不是一一對(duì)應(yīng)的。

API可以:

  • 直接提供用戶態(tài)服務(wù)
  • 一個(gè)單獨(dú)的API可能調(diào)用幾個(gè)系統(tǒng)調(diào)用
  • 不同的API可能調(diào)用了同一個(gè)系統(tǒng)調(diào)用

返回值:

  • 大部分封裝例程返回一個(gè)整數(shù)
  • -1表示失敗,不能滿足請(qǐng)求
  • errno 特定出錯(cuò)碼

3.所謂“扒開系統(tǒng)調(diào)用的三層皮”

  • API(xyz)
  • 中斷向量(system_call)
  • 中斷服務(wù)程序(sys_xyz)

1.系統(tǒng)調(diào)用的服務(wù)例程中,中斷向量0x80與system_call綁定起來(lái)。(Linux中可以通過執(zhí)行int $128來(lái)執(zhí)行系統(tǒng)調(diào)用。)

2.system_call是linux中所有系統(tǒng)調(diào)用的入口點(diǎn),每個(gè)系統(tǒng)調(diào)用至少有一個(gè)參數(shù),即系統(tǒng)調(diào)用號(hào)。

3.系統(tǒng)調(diào)用號(hào)將xyz與sys_xyz關(guān)聯(lián)起來(lái)。調(diào)用號(hào)在eax中。
系統(tǒng)調(diào)用的參數(shù)傳遞:

  • 函數(shù)調(diào)用——壓棧
  • 用戶態(tài)到內(nèi)核態(tài)——寄存器傳遞。

每個(gè)參數(shù)長(zhǎng)度不能超過32位,個(gè)數(shù)不能超過6個(gè)。

超過的話,使某個(gè)寄存器中存儲(chǔ)指針,指向內(nèi)存,內(nèi)存中存儲(chǔ)參數(shù)。

三、使用庫(kù)函數(shù)API和C代碼中嵌入?yún)R編代碼觸發(fā)同一個(gè)系統(tǒng)調(diào)用

1.使用庫(kù)函數(shù)API獲取系統(tǒng)當(dāng)前時(shí)間

使用time(),代碼如下:

#include<stdio.h> #include<time.h> int main() { time_t tt; struct tm *t;//構(gòu)造一個(gè)結(jié)構(gòu)體,方便讀取 tt = time(NULL);//time系統(tǒng)調(diào)用 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代碼中嵌入?yún)R編代碼觸發(fā)系統(tǒng)調(diào)用獲取系統(tǒng)當(dāng)前時(shí)間

代碼如下:

#include<stdio.h> #include<time.h> int main() { time_t tt; struct tm *t; asm volatile( "mov $0,%%ebx\n\t" # 把ebx清零,相當(dāng)于傳參數(shù) "mov $0xd,%%eax\n\t"# 把0xd放入eax中,即系統(tǒng)調(diào)用號(hào)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; }

四、使用庫(kù)函數(shù)API和C代碼中嵌入?yún)R編代碼兩種方式使用同一個(gè)系統(tǒng)調(diào)用

在這里我選擇的是第7號(hào)系統(tǒng)調(diào)用,waitpid。

1.使用庫(kù)函數(shù)API:

2.嵌入?yún)R編:

3.運(yùn)行結(jié)果:

五、總結(jié)

  • 即便是最簡(jiǎn)單的程序,在進(jìn)行輸入輸出等操作時(shí)也會(huì)需要調(diào)用操作系統(tǒng)所提供的服務(wù),也就是系統(tǒng)調(diào)用。
  • Linux下的系統(tǒng)調(diào)用是通過中斷(int 0x80)來(lái)實(shí)現(xiàn)的。
  • 在執(zhí)行int 80指令時(shí),寄存器 eax 中存放的是系統(tǒng)調(diào)用的功能號(hào),而傳給系統(tǒng)調(diào)用的參數(shù)則必須按順序放到寄存器 ebx,ecx,edx,esi,edi 中,當(dāng)系統(tǒng)調(diào)用完成之后,返回值可以在寄存器 eax 中獲得。
  • Linux 采用的是 C 語(yǔ)言的調(diào)用模式,這就意味著所有參數(shù)必須以相反的順序進(jìn)棧,即最后一個(gè)參數(shù)先入棧,而第一個(gè)參數(shù)則最后入棧。

轉(zhuǎn)載于:https://www.cnblogs.com/lxq20135309/p/5296439.html

總結(jié)

以上是生活随笔為你收集整理的LINUX内核分析第四周——扒开系统调用的三层皮的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。