基於int的Linux的經典系統調用實現


 

   先說明兩個概念:中斷和系統調用

一 系統調用: 是應用程序(運行庫也是應用程序的一部分)與操作系統內核之間的接口,它決定了應用程序是如何和內核打交道的。

1  Linux系統調用:2.6.19版內核提供了319個系統調用。比如 exit fork read open close ……

2  對Windows來說,操作系統提供給應用程序的接口不是系統調用,而是API。比如:ReadFile。我們暫時把API和系統調用等同起來

3  Linux中,每個系統調用對應一個系統調用號,內核維護了一個系統調用表,通過這張表可以找到對應的系統調用函數。

 

二 中斷

1  現代的CPU常常可以在多種截然不同的特權級別下執行指令,所以有兩種特權級別,分別為用戶模式(User Mode)和內核模式(Kernel Mode)

2  系統調用運行在內核態,應用程序基本都是運行在用戶態。用戶態要切換到內核態,操作系統一般是通過中斷來完成

3  Linux使用0x80中斷作為系統調用的入口,Windows采用0x2E號中斷作為系統調用入口

4  中斷是一個硬件或軟件發出的請求,要求CPU暫停當前工作轉手去處理更加重要的事。

5  中斷一般有兩個屬性,中斷號和中斷處理程序。不同的中斷有不同的中斷號,也對應不同的中斷處理程序。

6  在內核中有一個數組稱為中斷向量表,這個數組的第n項包含了指向第n號中斷的中斷處理程序的指針

 

三 基於int的Linux的經典系統調用實現(進入正題)

1  以fork為例 

void main(void)
{
    fork();  
}

 

2  大概流程就是這樣:用戶調用fork  ->  eax=2(保存系統調用號到寄存器中) -> int 0x80 (觸發中斷,切換到內核態)

            ->  在中斷向量表中查找(0x80號) -> 執行0x80對應的中斷服務程序(system_call)

            ->  在系統調用表中找到系統調用號為2的那一項(通過之前保存的eax=2) -> 執行系統調用(sys_fork)

 

3  執行流程圖如下

 

4  用戶調用某個系統調用,執行到int $0x80時,會保存現場以便恢復,接着將特權狀態切換到內核態,然后CPU便會查找中斷向量表中的第0x80號元素。

 

5  切換堆棧:

1       在執行中斷處理函數之前,CPU首先還要進行棧的切換。

2       在Linux中,用戶態和內核態使用的是不同的棧,兩者各自負責各自的函數調用。

3       調用0x80中斷時,程序執行流程從用戶態切換到內核態,當前棧也必須相應的從用戶棧切換到內核棧。從中斷處理程序中返回時,再切換回用戶棧

4       “當前棧”指的是ESP的值所在的棧空間,若ESP的值位於用戶棧的范圍內,那個當前棧就是用戶棧,反之就是內核棧。此外,寄存器SS的值還要指向當前棧所在的頁

5       用戶棧 -> 內核棧的實際行為就是:

        保存當前的ESP,SS的值   ->   將ESP SS的值設置為內核棧的相應值

      內核棧 -> 用戶棧的實際行為就是:

        恢復原來的ESP SS的值

6       用戶態的ESP 和 SS保存在內核棧中,這一行為由i386的中斷指令自動地由硬件完成。

7       中斷發生時,CPU切入內核態,還會接着做下面幾件事

        找到當前進程的內核棧(每個進程都有獨立的內核棧) ->   在內核棧中一次壓入用戶態的寄存器SS、ESP、EFLAGS、CS、EIP。

8       系統從系統調用中返回時,需要用iret指令回到用戶態,iret會從內核態中彈出寄存器SS、ESP、EFLAGS、CS、EIP的值,使得棧恢復到用戶態的狀態

 

6,中斷處理程序:切換棧了以后,程序的流程就切換到了中斷向量表中記錄0x80號中斷處理程序,Linux內部的i386中斷服務流程如圖

        

執行完sys_fork后再沿原路返回

 

參考: 《程序員的自我修養》

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM