偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

讓我們一起捋一捋系統(tǒng)調(diào)用

系統(tǒng)
系統(tǒng)調(diào)用就是調(diào)用操作系統(tǒng)提供的一系列內(nèi)核功能函數(shù),因?yàn)閮?nèi)核總是對(duì)用戶程序持不信任的態(tài)度,一些核心功能不能交由用戶程序來(lái)實(shí)現(xiàn)執(zhí)行。用戶程序只能發(fā)出請(qǐng)求,然后內(nèi)核調(diào)用相應(yīng)的內(nèi)核函數(shù)來(lái)幫著處理,將結(jié)果返回給應(yīng)用程序。

[[399828]]

本文轉(zhuǎn)載自微信公眾號(hào)「Rand」,作者Rand。轉(zhuǎn)載本文請(qǐng)聯(lián)系Rand公眾號(hào)。

系統(tǒng)調(diào)用就是調(diào)用操作系統(tǒng)提供的一系列內(nèi)核功能函數(shù),因?yàn)閮?nèi)核總是對(duì)用戶程序持不信任的態(tài)度,一些核心功能不能交由用戶程序來(lái)實(shí)現(xiàn)執(zhí)行。用戶程序只能發(fā)出請(qǐng)求,然后內(nèi)核調(diào)用相應(yīng)的內(nèi)核函數(shù)來(lái)幫著處理,將結(jié)果返回給應(yīng)用程序。如此才能保證系統(tǒng)的穩(wěn)定和安全,關(guān)于系統(tǒng)調(diào)用的這些理論知識(shí)不多說(shuō),書本上有一大堆,本文旨在捋清楚系統(tǒng)調(diào)用這條線。

總述

Linux 里系統(tǒng)調(diào)用是由中斷來(lái)實(shí)現(xiàn)的,既然利用中斷實(shí)現(xiàn),那么總體來(lái)說(shuō)系統(tǒng)調(diào)用的過(guò)程應(yīng)該與中斷的過(guò)程相似。也的確如此,總體流程是差不多,但也有所區(qū)別。

每一種中斷都會(huì)有一個(gè)中斷向量號(hào)或中斷類型號(hào),有相應(yīng)的中斷服務(wù)程序也就是處理中斷的函數(shù)。但是我們應(yīng)該知道,系統(tǒng)調(diào)用是有很多的,比如 fork,read,write 等等。雖然中斷向量號(hào)有空缺多余的,但系統(tǒng)調(diào)用數(shù)目更多,到2.6.23版的 Linux,就已經(jīng)有325個(gè),而中斷向量號(hào)只有 256 個(gè),明顯為每一個(gè)系統(tǒng)調(diào)用單獨(dú)分配一個(gè)中斷向量號(hào)不現(xiàn)實(shí)。

那怎么解決呢,采用的辦法是直接為所有的系統(tǒng)調(diào)用分配一個(gè)中斷類型號(hào),一般是 0x80,再用系統(tǒng)調(diào)用號(hào)來(lái)區(qū)分各個(gè)不同的系統(tǒng)調(diào)用。

所以我們的系統(tǒng)調(diào)用大致流程變?yōu)楦鶕?jù)中斷向量號(hào)去IDT中索引相應(yīng)的中斷門描述符,得到選擇子和偏移量,根據(jù)選擇子去GDT中索引相應(yīng)的段描述符得到段基址,與上面得到的偏移量相加得到中斷服務(wù)程序的地址。中斷處理程序根據(jù)系統(tǒng)調(diào)用號(hào)再調(diào)用相應(yīng)的系統(tǒng)調(diào)用函數(shù)做具體的處理,最后返回。

上述為系統(tǒng)調(diào)用的大致過(guò)程,下面我們一步步地來(lái)具體看看系統(tǒng)調(diào)用的過(guò)程,或者說(shuō)系統(tǒng)調(diào)用是如何實(shí)現(xiàn)的。

1. 用戶接口

我們平常編寫程序調(diào)用的是操作系統(tǒng)或者說(shuō) C 庫(kù)提供的用戶接口,也就是常說(shuō)的 API,而并不是直接使用系統(tǒng)調(diào)用來(lái)編程,用戶接口可以看作實(shí)際的系統(tǒng)調(diào)用函數(shù)的封裝。

這里要注意我們平常所說(shuō)的 API 和系統(tǒng)調(diào)用之間并沒有一定的對(duì)應(yīng)關(guān)系。一個(gè) API 可以對(duì)應(yīng)一個(gè)系統(tǒng)調(diào)用,也可以對(duì)應(yīng)多個(gè)系統(tǒng)調(diào)用,甚至不依賴任何系統(tǒng)調(diào)用,更甚多個(gè)API對(duì)應(yīng)一個(gè)系統(tǒng)調(diào)用。所以 API 就只是一個(gè)接口,具體使用哪些系統(tǒng)調(diào)用實(shí)現(xiàn)什么功能,從理論上來(lái)講只要邏輯沒問題隨便怎么定義怎么實(shí)現(xiàn)都可以,但是為了可移植兼容的考慮,還是必須得遵循一定的規(guī)則,大多操作系統(tǒng) API 都是遵循POSIX標(biāo)準(zhǔn)的。

上述說(shuō)過(guò)系統(tǒng)調(diào)用的用戶接口可以看作是系統(tǒng)調(diào)用的封裝,咱們以 getpid 來(lái)舉例具體看看:

  1. int getpid(){ 
  2.     return _syscall0(SYS_getpid); 

2. 系統(tǒng)調(diào)用接口

系統(tǒng)調(diào)用接口指的就是上面那個(gè) _syscall 函數(shù),早期的 Linux 里面的 _syscall是用宏來(lái)實(shí)現(xiàn)的,一共有 7 個(gè),后面跟不同的數(shù)字來(lái)區(qū)分,如_syscall0,_syscall1,分別支持0—6個(gè)參數(shù)。咱們?cè)谶@兒也不搬出具體代碼解釋說(shuō)明,有興趣的朋友可以自己去看看,這7個(gè)宏的實(shí)現(xiàn)原理都一樣,主要做了以下三件事:

  1. 系統(tǒng)調(diào)用號(hào)傳給 eax 寄存器
  2. 傳入?yún)?shù)
  3. int 80h

傳參,如果參數(shù)少,直接存到寄存器里即可,采用寄存器傳參方便而且速度快。在下x86的系統(tǒng)上,前5個(gè)參數(shù)按順序存放在ebx, ecx,edx, esi,edi 5 個(gè)寄存中。而如果參數(shù)過(guò)多,會(huì)使用一個(gè)單獨(dú)的寄存器存放所有參數(shù)在用戶空間的地址,陷入內(nèi)核后再將參數(shù)從用戶空間拷貝到內(nèi)核。

系統(tǒng)調(diào)用號(hào)和最后的返回值都存在 eax 寄存器中,約定俗成的東西。

接著就是 int n 指令,int n 就相當(dāng)于發(fā)生了一個(gè)n號(hào)中斷,屬于軟中斷,雖然引發(fā)中斷的方式不同,但對(duì)中斷的處理基本是一樣的,中斷這一塊前文講述的應(yīng)該很清楚了,這里不再贅述只是簡(jiǎn)單說(shuō)明一下:

  1. 有特權(quán)級(jí)變化的話壓入 ss 和 esp,因?yàn)槭窍到y(tǒng)調(diào)用,特權(quán)級(jí)是肯定發(fā)生了變化的
  2. 壓入 eflags,cs,eip 寄存器
  3. 根據(jù)中斷類型號(hào)索引 IDT 中的中斷門描述符,取出里面的內(nèi)容修改 cs,eip 寄存器的值;根據(jù) cs 里面的選擇子又去 GDT 中索引段描述符,獲取段基址。再根據(jù) eip 中的偏移量找到系統(tǒng)調(diào)用服務(wù)程序。

這里對(duì)于用戶態(tài)的 ss和 esp 寄存器值保存作為題外話補(bǔ)充說(shuō)明一下。不知大家有沒有想過(guò)這個(gè)問題,用戶態(tài)下的 ss 和 esp 怎么保存到內(nèi)核棧里面去的,切換到內(nèi)核棧需要改變 ss 和 esp,那原 ss 和esp不就丟掉了嗎?所以處理器會(huì)臨時(shí)保存 ss 和 esp 的值,切換到內(nèi)核態(tài)時(shí)再重新拷貝一份用戶態(tài)的 ss 和 esp 的值。之后再壓入 eflags,cs,eip 寄存器,當(dāng)然如果特權(quán)級(jí)沒有發(fā)生變化,也就不會(huì)有上述過(guò)程。

這一塊兒在我寫的中斷文章里面忘記說(shuō)了,在此補(bǔ)上,這些所有有關(guān)處理器的規(guī)則約定功能都由指令集體系結(jié)構(gòu)ISA所管,它規(guī)定了我們需要做什么,提供什么,然后它就自動(dòng)完成一些事情。就像調(diào)用 API 編程一樣,我們提供合理的參數(shù),然后相應(yīng)的函數(shù)自動(dòng)完成一些工作。對(duì)于CPU而言同樣的道理,只是更偏向于底層具體的物理實(shí)現(xiàn),但從邏輯上來(lái)講是相通的。

3. 系統(tǒng)調(diào)用號(hào)

每個(gè)系統(tǒng)調(diào)用都有自己的專屬號(hào)碼,其實(shí)就是個(gè)索引號(hào),如下面所示:

  1. #define __NR_eixt   1 
  2. #define __NR_fork   2 
  3. #define __NR_read   3 
  4. /*...................*/ 

4. 系統(tǒng)調(diào)用服務(wù)例程

系統(tǒng)調(diào)用服務(wù)例程才是具體干事的內(nèi)核功能函數(shù),前面的那些用戶接口,系統(tǒng)調(diào)用接口,中斷服務(wù)程序都不是具體干事的,全都相當(dāng)于接口一類,而這個(gè)系統(tǒng)調(diào)用服務(wù)例程才是具體做事的一個(gè)函數(shù),舉個(gè)簡(jiǎn)單例子,用 getpid 這個(gè)系統(tǒng)調(diào)用來(lái)說(shuō)明:

  1. int sys_getpid(void){ 
  2.  return current->pid   //current指向當(dāng)前進(jìn)程 

5. 系統(tǒng)調(diào)用表

每個(gè)系統(tǒng)調(diào)用都對(duì)應(yīng)著一個(gè)服務(wù)例程,將它們的首地址集中起來(lái)放在一個(gè)數(shù)組里方便使用系統(tǒng)調(diào)用號(hào)來(lái)索引,這個(gè)表(數(shù)組一個(gè)意思)在Linux里面是 sys_call_table,就像這樣:

  1. ENTRY(sys_call_table) 
  2.     .long sys_restart_syscall 
  3.     .long sys_exit 
  4.     .long sys_fork 

6. 系統(tǒng)調(diào)用服務(wù)程序

這個(gè)系統(tǒng)調(diào)用服務(wù)程序就是中斷服務(wù)程序,以前的哪些外設(shè)引發(fā)的中斷相應(yīng)的服務(wù)程序會(huì)處理實(shí)際的事務(wù),而系統(tǒng)調(diào)用前面說(shuō)過(guò)不太一樣,它交給系統(tǒng)調(diào)用服務(wù)例程來(lái)處理的,下面來(lái)仔細(xì)看看:

  1. system_call: 
  2.     SAVE_ALL      #保存上下文 
  3.     push arg      #壓入?yún)?shù) 
  4.      
  5.     call *sys_call_table(,%eax,4)   #根據(jù)eax里面的系統(tǒng)調(diào)用號(hào)調(diào)用相應(yīng)服務(wù)例程 
  6.      
  7.     mov %eax, 24(%esp)  #將服務(wù)例程的返回值保存到上下文中的eax處 
  8.    
  9. syscall_exit: 
  10.     #返回退出 

系統(tǒng)調(diào)用利用中斷實(shí)現(xiàn),所以處理中斷要先保存上下文,因?yàn)橄到y(tǒng)調(diào)用不具體處理事務(wù)而是調(diào)用其他函數(shù)來(lái)處理,所以壓入?yún)?shù)然后調(diào)用函數(shù)。這是調(diào)用函數(shù)前的一慣做法:先壓入?yún)?shù)再調(diào)用。參數(shù)從何而來(lái)?還記得前面把參數(shù)放在寄存器里面吧,所以這兒push arg就是壓入寄存器,就不具體寫了,知道就好。

系統(tǒng)調(diào)用服務(wù)例程的運(yùn)行結(jié)果是要傳回到用戶態(tài)的,eax 里面存放的返回值,所以當(dāng)服務(wù)例程運(yùn)行完后,只要將當(dāng)前寄存器 eax 里面的值保存到上下文里面的 eax 處即可。在Linux2.6 里面棧頂向上 24 個(gè)字節(jié)處就是用戶態(tài)下的 eax,這個(gè)用戶態(tài)下eax的位置與具體保存上下文時(shí)如何壓棧有關(guān),前后能夠?qū)?yīng)上就行。

注:上述是根據(jù) Linux2.6 簡(jiǎn)化來(lái)的偽碼,Linux2.6里面是確有 SAVE_ALL 這個(gè)宏的,其中壓入?yún)?shù)就是 SAVE_ALL 的一部分,在這兒只是為了過(guò)程更清晰所以單獨(dú)寫了出來(lái)。

7. 總結(jié)捋線

上述就是系統(tǒng)調(diào)用的大概過(guò)程,這兒再總結(jié)總結(jié)捋一捋:

  1. 調(diào)用用戶接口函數(shù)
  2. 用戶接口封裝的是系統(tǒng)調(diào)用接口,早期的 Linux 里就是那7個(gè)宏
  3. _syscall 傳系統(tǒng)調(diào)用號(hào),傳參,int 80h
  4. int 80h 陷入內(nèi)核,保存ss,esp,eflags,cs,eip寄存器
  5. 根據(jù)中斷向量號(hào) 80h 去IDT中索引中斷門描述符,根據(jù)其內(nèi)容修改 cs,eip 的值
  6. 根據(jù) cs 里的選擇子去 GDT 中索引段描述符,獲得中斷(系統(tǒng)調(diào)用)服務(wù)程序的段基址,結(jié)合 eip 里面的偏移量就得到系統(tǒng)調(diào)用服務(wù)程序的地址
  7. 系統(tǒng)調(diào)用服務(wù)程序中 system_call 保存上下文,壓入系統(tǒng)調(diào)用服務(wù)例程需要的參數(shù)
  8. 根據(jù) eax 里面的系統(tǒng)調(diào)用號(hào)索引 sys_call_table,然后調(diào)用執(zhí)行
  9. 修改上下文中 eax 處的值,將其修改為服務(wù)例程返回值
  10. 返回,相當(dāng)于第4步的逆過(guò)程

大致的過(guò)程圖如下所示:

并不是所有的系統(tǒng)調(diào)用都有上述的過(guò)程,在這兒只是從頭至尾的捋一捋,知曉有這么一個(gè)過(guò)程就好,畢竟本文的目的就是捋一捋系統(tǒng)調(diào)用這條線嘛

8. syscall說(shuō)明

_syscall 宏這種形式的系統(tǒng)調(diào)用在 Linux 里面已經(jīng)廢棄不再提供庫(kù)實(shí)現(xiàn)支持,因?yàn)檫@種方式最多支持6個(gè)參數(shù),而且每個(gè)參數(shù)還要提供相應(yīng)的類型,總共就是2n個(gè)參數(shù)。但是這種實(shí)現(xiàn)方式思路清晰簡(jiǎn)單,所以上述我也是以這種實(shí)現(xiàn)為基來(lái)說(shuō)明的。

現(xiàn)在 Linux 的系統(tǒng)調(diào)用都是用庫(kù)函數(shù)syscall來(lái)實(shí)現(xiàn)的,原型為:

  1. int syscall(int number, ...); 

number指的是系統(tǒng)調(diào)用號(hào)。從這原型就能看出,庫(kù)函數(shù)這種實(shí)現(xiàn)方式支持變參(...),所以能夠?qū)⑺械南到y(tǒng)調(diào)用統(tǒng)一起來(lái),不像宏實(shí)現(xiàn)方式不同參數(shù)的系統(tǒng)調(diào)用還需要使用不同的宏。

 

責(zé)任編輯:武曉燕 來(lái)源: Rand
相關(guān)推薦

2021-11-04 18:15:55

下載上傳瀏覽器

2021-07-07 22:27:54

磁盤分區(qū)硬盤

2023-11-28 12:42:56

數(shù)據(jù)分析管理

2024-05-06 12:23:00

GenAI人工智能

2020-12-18 06:09:07

Java淺拷貝深拷貝

2020-05-18 14:12:41

PostgreSQLDB架構(gòu)數(shù)據(jù)庫(kù)

2023-03-15 10:38:55

2022-03-31 18:59:43

數(shù)據(jù)庫(kù)InnoDBMySQL

2021-08-27 07:06:10

IOJava抽象

2021-12-29 08:27:05

ByteBuffer磁盤服務(wù)器

2022-03-08 17:52:58

TCP格式IP

2021-03-10 10:00:31

Go語(yǔ)言strconv包類型轉(zhuǎn)換工具

2023-08-14 08:38:26

反射reflect結(jié)構(gòu)體

2021-11-26 07:00:05

反轉(zhuǎn)整數(shù)數(shù)字

2021-07-15 07:23:28

Singlefligh設(shè)計(jì)

2022-02-14 10:16:22

Axios接口HTTP

2016-09-06 10:39:30

Dell Techno

2022-06-26 09:40:55

Django框架服務(wù)

2022-02-14 07:03:31

網(wǎng)站安全MFA

2022-07-10 23:15:46

Go語(yǔ)言內(nèi)存
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)