日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

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

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

李雪琦 + 原創(chuàng)作品轉(zhuǎn)載請注明出處 + 《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í)行級別:

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

  • Intel x86 CPU有四種不同的執(zhí)行級別0~3,Linux只用其中的0和3來表示內(nèi)核態(tài)和用戶態(tài)。
  • 區(qū)分內(nèi)核態(tài)和用戶態(tài):CPU每條指令的讀取都是通過cs:eip,cs寄存器最低兩位表明了當前代碼的特權級。
  • 內(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ù)刂?、當時的狀態(tài)字、cs:eip的值,以及內(nèi)核態(tài)的棧頂?shù)刂贰敃r的狀態(tài)字、中斷處理程序入口。
  • 中斷發(fā)生后的第一件事:保存現(xiàn)場(SAVE_ALL:保存需要用到的寄存器數(shù)據(jù))。
  • 中斷處理結束前的最后一件事:恢復現(xiàn)場(RESTORE_ALL:退出中斷程序,恢復保存寄存器的數(shù)據(jù))。

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

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

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

  • 遠離底層硬件編程
  • 安全性
  • 可移植性

2. API - 應用編程接口

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

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

API可以:

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

返回值:

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

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

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

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

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

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

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

每個參數(shù)長度不能超過32位,個數(shù)不能超過6個。

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

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

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

使用time(),代碼如下:

#include<stdio.h> #include<time.h> int main() { time_t tt; struct tm *t;//構造一個結構體,方便讀取 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)當前時間

代碼如下:

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

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

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

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

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

3.運行結果:

五、總結

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

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

總結

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

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