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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux下简单的系统调用

發布時間:2025/3/15 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下简单的系统调用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原創 2017年03月17日 21:31:20

楊金龍 + 原創作品轉載請注明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000

??本周是Linux系統分析課程的第四周課程,本周主要講Linux系統調用的過程,具體知識點和實驗結果總結如下。

系統調用的相關知識

  系統調用:系統調用只是一個特殊的中斷。我們通過庫函數和系統調用打交道,庫函數把系統調用封裝起來。
1、儲備知識——內核態和用戶態
  內核態:在高執行級別下,代碼可以執行特權指令,訪問任意的物理內存,這種CPU執行級別就對應著內核態。
  用戶態:在用戶態級別下,代碼的掌控范圍會受到限制,只能在對應級別允許的范圍內活動。
注:Intel x86CPU有四種不同的執行級別0-3,Linux只使用了其中的0級和3級分別來表示內核態和用戶態。
2、為什么有權限級別的劃分?
  若沒有用戶態和內核態的劃分,用戶寫的不健壯的程序就可以執行特權指令時,就很容易是系統崩潰。操作系統發展過程中劃分了用戶態和內核態,是系統更穩定的機制。
3、寄存器在系統調用中的作用
  Cs寄存器的最低兩位表明了當前代碼的特權級。CPU每條指令的讀取都是通過CS:EIP這兩個寄存器:其中CS是代碼段選擇寄存器,EIP是偏移量寄存器。
4、內存地址空間
  一般在Linux中,地址空間是一個顯著的標志:0xc0000000以上的地址空間只能在內核態下訪問,0x0000000–0xbfffffff的地址空間在兩種狀態下都可以訪問。
注:產生中斷是從用戶態進入內核態的主要方式。
5、寄存器上下文:
 5.1從用戶態切換到內核態時:
  必須保存用戶態的寄存器上下文;
  同時把內核態的寄存器的值放到寄存器中。
 5.2中斷/int指令會在堆棧上保存一些寄存器的值:
  如用戶態棧頂地址;
  當前的狀態字;
  當時的CS:EIP的值。
 5.3中斷發生后的第一件事就是保存現場:
  保存現場:就是進入中斷程序,保存需要用到的寄存器的數據。
 5.4中斷處理結束前最后一件事就是恢復現場:
  恢復現場:就是退出中斷程序恢復保存寄存器的數據。
  注:Iret指令和中斷信號(包括int指令)發生時的CPU做的動作整好相反。

中斷處理的完整過程

如下圖所示

  中斷指令interrupt(ex:int 0x80)開始進行系統調用;
  保存當前CS:EIP,SS:ESP,eflags的值到內核堆棧,同時加載了中斷服務程序的地址到CS:EIP以及內核堆棧棧頂指針到SS:ESP中。Int指令完成上述操作過程。
  內核代碼,完成中斷服務:
  發生進程調度,則保存調度時的現場,進行調度,完成調度后再恢復現場;
  不發生進程調度,則恢復之前的保存現場:iret - pop cs:EIP/SS:ESP/eflags from kernel stack.

系統調用的意義

1、操作系統為用戶態進程與硬件設備進行交互提供了一組接口——系統調用。
  把用戶從底層的硬件編程中解放出來;
  極大的提高了系統的安全性;
  使用戶程序具有可移植性。
2、操作系統提供的API和系統調用的關系。
  應用編程接口(Application program interface,API)和系統調用時不同的;
  API只是一個函數定義;
  系統調用通過軟中斷向內核發出一個明確的請求。
  Libc庫定義的一些API引用了封裝例程(wrapper routine,唯一的目的就是發布系統調用):一般每個系統調用對應一個封裝例程。庫再用這些封裝例程定義給出用戶的API。
3、不是每個API都對應一個特定的系統調用:
  API可能直接提供用戶態的服務;
  一個單獨的API可能調用幾個系統調用;
  不同的API可能調用了同一個系統調用。
4、返回值
  大部分封裝例程返回一個整數,其值的含義依賴于相應的系統調用;
  -1在多數情況下表示內核不能滿足進程的請求;
  Libc中定義的errno變量包含特定的出錯碼。
  

注:系統調用的三層皮:API,中斷向量,中斷服務程序

5、系統調用的服務例程:
  5.1 當用戶態進程調用一個系統調用時,CPU切換內核態并開始執行一個內核函數。
  在Linux中是通過執行int $0x80來執行系統調用的,這條匯編指令產生向量為128的編程異常;
  Inter Pentium II中引入了sysenter指令(快速系統調用),2,6已經支持。
5.2 傳參:
  內核實現了很多不同的系統調用;
  進程必須指明需要哪個系統調用,這需要使用EAX寄存器傳遞一個名為系統調用號的參數
5.3 系統調用也需要輸入輸出參數,例如:
  實際的值;
  用戶態進程地址空間的變量的地址;
  甚至包含指向用戶態函數的指針的數據結構的地址。
  System call是Linux中所有系統調用的入口點,每個系統調用至少有一個參數,即由eax
5.3 傳遞的系統調用號;
  系統調用號將xyz和sys_xyz關聯起來;用eax寄存器來傳遞參數;
  一個應用程序調用fork()封裝例程,那么在執行int $0x80之前就把EAX寄存器的值置為2(即 NR fork);
  這個寄存器的設置是libc庫中的封裝例程進行的,因此用戶一般不關心系統調用號;
  進入sys,call之后,立即將EAX的值壓入內核堆棧;
5.4 寄存器參數具有如下限制:
  每個參數的長度不能超過寄存器的長度,即32位;
  在系統調用號(EAX)之外,參數的個數不能超過6個(ebx,ecx,edx,esi,edi,ebp)。

實驗代碼

  實驗過程中調用mkdir系統函數,mkdir調用號為39,函數原型如下:
  

int mkdir(const char *path, mode_t mode);
參數:
 path是目錄名
 mode是目錄權限
返回值:
 返回0 表示成功, 返回 -1表示錯誤,并且會設置errno值。

通過C代碼調用

mkdir.c

#include <stdio.h> #include <sys/stat.h> #include <sys/types.h>int main() {int ret = 0;ret = mkdir("./test", 0777);if(ret == 0){printf("Mkdir success!\n") ; }else printf("Mkdir failed!\n");return 0; }

通過嵌入式匯編調用

mkdir_asm.c

#include <stdio.h>int main() {int ret = 0;char *dir = "./test_asm";int mode = 0777;asm volatile("movl $39, %%eax\n\t""int $0x80\n\t""movl %%eax, %0\n\t": "=m"(ret): "b"(dir), "c"(mode) );if(ret == 0)printf("Mkdir through asm success!\n");else printf("Mkdir through asm failed!\n");return 0; }

實驗總結

  通過對系統調用的兩種代碼實現方法的分析,我們可以知道C語言的API只不過是對Linux底層系統調用的一次封裝而已,本質上是通過系統中斷實現的。


總結

以上是生活随笔為你收集整理的Linux下简单的系统调用的全部內容,希望文章能夠幫你解決所遇到的問題。

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