使用者程式是如何呼叫核心程式的呢?考慮實現下面的乙個whoami的系統呼叫:
在核心中100位址處有乙個使用者「lizhijun」,whoami函式的功能是要列印出這個使用者名稱,那可以直接列印出100位址處的內容嗎?答案當然是否定的,因為使用者程式不能隨意的訪問核心程式,核心態可以訪問任何資料,使用者態卻不能訪問核心資料,這是一種處理器的硬體設計所決定的,如下圖:
判斷一段程式能不能訪問另一段是根據程式的特權級來判斷的,dpl是指目標程式的特權級(核心態**dpl存在於gdt表中,在head.s已經初始化好),cpl指當前程式的特權級,當前程式執行在什麼態,使用cs的最低兩位來表示的,0表示核心態,3表示使用者態,當dpl大於cpl時,當前程式可訪問目標程式。
首先硬體提供了主動進入核心的方法,對於intel x86而言,就是中斷指令,通過中斷指令將cs的cpl改為0,從而進入核心,這是使用者程式呼叫核心**的唯一方法。
以c語言中printf函式為例,printf函式實際上是呼叫了核心的write函式,庫函式write最終通過巨集展開成包含指令int 0x80的**,從而進入核心執行核心的write函式:
那麼具體流程是怎樣的呢?當呼叫庫函式write時,執行下面的**:
展開後的**如下:
int write(int fd, const char *buf, off_t count)
**是內嵌彙編**,一共3條語句,分別用:隔開,第一條是中斷指令,第二條是輸出,是指把_res的內容付給eax暫存器,第三條是輸入,是指把三個引數和_nr_write的值分別付給ebx 、ecx、edx和eax暫存器,首先執行第三條語句,然後執行中斷指令,最後執行輸出指令,然後再執行c語言的return語句。總的來說就是將系統呼叫號(nr_write)置給eax,然後呼叫中斷指令進入核心。
那麼呼叫中斷又是怎麼進入核心呢?首先呼叫中斷時需要查詢idt表,早在系統初始化時就已經初始化好了idt表,初始化函式(set_system_gate(0x80,&system_call);)做了如下操作:
將0x80號中斷表的表項賦值:dpl賦值為3,&system_call賦給處理函式入口偏移,段選擇符賦為0x0008,即cs=8,ip = &system_call,(通過cs=8找到gdt表中的核心**段,同jmpi 0,8的那個用法,而且8的最後一位為0,所以cpl被置為0),然後跳轉到核心區域執行。
接下來就呼叫system_call函式:
該函式首先做了一些鋪設操作,然後將資料段暫存器賦值為0x10,現在資料指標和**指標都指向了核心區域,因此接下來就真正進入核心操作,執行call _sys_call_table(,%eax,4)指令,_sys_call_table是乙個系統呼叫表的起始位址,通過位址和eax的值找到要呼叫的系統呼叫的真正位址,即_sys_call_table+4*%eax,eax中是之前存入的nr_write(4),找到表中的第4個元素:
確實為sys_write,因此接下來就呼叫sys_write,此函式就是真正要做寫操作的函式了。
總結一下,就是如下圖:
當從第乙個框圖到第二框圖時,此時cpl=3,在初始化時,又將int 0x80指令的dpl做成了3,因此可以調到執行int 0x80指令。
作業系統 系統呼叫
由作業系統提供的功能,通常應用程式本身是無法實現的。例如對檔案進行操作,應用程式必需通過系統呼叫才能做到,因為只有作業系統才具有直接管理外圍裝置的許可權。又如程序或執行緒間的同步互斥操作,也必需經由作業系統對核心變數進行維護才能完成。從下到上看乙個完整的計算機系統 物理硬體 os核心 os服務 應用...
作業系統(六)系統呼叫
在前幾篇文章中曾經提到過系統呼叫程式介面,並提到系統呼叫使應用程式請求作業系統服務的唯一方式。下面再來更進一步地學習一下。目錄 1.6 系統呼叫 1.6.1 系統呼叫 1.6.2 系統呼叫的具體使用場景 1.6.3 系統呼叫的過程 系統呼叫 是作業系統提供給應用程式 程式設計師 程式設計人員 使用的...
作業系統(3)系統呼叫
作業系統作為使用者和計算機硬體之間的介面,需要向上提供一些簡單的服務。主要包括命令介面和程式介面。其中程式介面由一組系統呼叫組成。1 命令介面 允許使用者直接使用 聯機命令介面 使用者說一句,系統做一句。離線命令介面 使用者說一堆,系統做一堆。2 程式介面 允許使用者通過程式間接使用 由一組系統呼叫...