首頁 > 系統教程 > Linux > 主體

Linux中系統呼叫不是核心的合法入口

王林
發布: 2024-03-19 10:34:02
轉載
887 人瀏覽過

在Linux中,系統呼叫是用戶空間存取核心的惟一手段,它們是核心惟一的合法入口。實際上,其他的像設備檔案和/proc之類的方法,最終還是要透過系統呼叫進行的。

通常情況下,應用程式透過應用程式插口(API)而不是直接透過系統呼叫來編程,而這些程式插口實際上並不須要和核心提供的系統呼叫對應。一個API定義了一組應用程式使用的程式插口。它們可以實現成一個系統調用,也可以透過調用多個系統調用來實現,就算不使用任何系統調用也不存在問題。實際上,API可以在各類不同的作業系統上實現,為應用程式提供完全相同的插口,而它們本身在這種系統上的實現卻可能迥異。

在Unix世界中,最受歡迎的應用程式插口是基於POSIX標準的,Linux是與POSIX相容的。

從程式設計師的角度看,她們只必須給API打交道就可以了,而核心只跟系統呼叫打交道;函式庫函數及應用程式是如何使用系統呼叫不是核心關心的。

系統呼叫(在linux中常叫做syscalls)一般透過函數進行呼叫。它們一般都須要定義一個或幾個參數(輸入)並且可能形成一些副作用。這種副作用透過一個long類型的回傳值來表示成功(0值)或則錯誤(負值)。當系統呼叫出現錯誤的時侯會把錯誤碼寫入errno全域變數。透過呼叫perror()函數,可以把該變數翻譯成使用者可以理解的錯誤字串。

系統呼叫的實作有兩個非常之處:1)函數申明中都有asmlinkage限定詞,用來通知編譯器僅從堆疊中提取該函數的參數。 2)系統呼叫getXXX()在核心中被定義為sys_getXXX()。這是Linux中所有系統呼叫都應遵循的命名規則。

系統呼叫號:在linux中,每位系統呼叫都賦於一個系統呼叫號,透過這個獨一無二的號就可以關聯繫統呼叫。當使用者空間的程序執行一個系統呼叫的時侯,這個系統呼叫號碼就被拿來指明究竟要執行那個系統呼叫;進程不會提到系統呼叫的名稱。系統呼叫號碼一旦分配就不能再有任何變更(否則編譯好的應用程式都會崩潰),假若一個系統呼叫被刪掉,它所佔用的系統呼叫號碼也不容許被回收。 Linux有一個"未使用"系統呼叫sys_ni_syscall(),它不但回傳-ENOSYS外不做任何其他工作,這個錯誤號碼就是專門針對無效的系統呼叫而設的。似乎很罕見,但假如有一個系統呼叫被刪掉,這個函數就要負責「填補空位」。

核心記錄了系統呼叫表中所有已註冊過的系統呼叫的列表,儲存在sys_call_table中。它與體系結構有關,通常在entry.s中定義。這個表中為每一個有效的系統呼叫指定了惟一的系統呼叫號。

使用者空間的程式難以直接執行核心程式碼。它們不能直接調用內核空間的函數,由於內核留在受保護的地址空間上,應用程式應以某種形式通知系統,告訴內核自己須要執行一個系統調用,系統系統切換到內核狀態linux 內核呼叫,這樣核心就可以代表應用程式來執行該系統呼叫了。這些通知內核的機制是透過軟中斷來實現的。 x86系統上的軟中斷由int$0x80指令形成。這條指令會觸發一個異常造成系統切換到內核態並執行第128號異常處理程序,而該程序正是系統調用處理程序,名子叫system_call().它與硬體體系結構緊密相關,一般在entry .s文件中透過彙編語言編撰。

所有的系統呼叫深陷核心的形式都是一樣的紅旗linux系統,所以光是深陷核心空間是不夠的。因而必須把系統呼叫號一並傳給核心。在x86上,這個傳遞動作是透過在觸發軟中斷前把呼叫號碼放入eax暫存器來實現的。這樣系統呼叫處理程序一旦運行,就可以從eax中得到資料。上述所說的system_call()透過將給定的系統呼叫號碼與NR_syscalls做比較來檢測其有效性。假如它小於或則等於NR_syscalls,函數就回傳-ENOSYS.否則,就執行對應的系統呼叫:call*sys_call_table(,�x,4);

因為系統呼叫表中的表項是以32位元(4位元組)類型儲存的,所以核心必須將給定的系統呼叫號碼除以4,之後用所得到的結果在該表中查詢器位置。如圖圖一所示:

裡面早已提及,不只係統呼叫號碼以外,還須要一些外部的參數輸入。最簡單的方法就是像傳遞系統呼叫號碼一樣把這種參數也儲存在暫存器裡。在x86系統上ebx,ecx,edx,esi和edi依次序儲存前5個參數。須要六個或六個以上參數的情況不多見,此時,應當用一個單獨的寄存器儲存指向所有那些參數在用戶空間地址的表針。給用戶空間的回傳值也透過暫存器傳遞。在x86系統上,它儲存在eax暫存器中。

系統呼叫必須仔細偵測它們所有的參數是否合法有效。系統呼叫在核心空間執行。假如任由用戶將不合法的輸入傳遞給內核,這樣系統的安全與穩定將面臨極大的考驗。最重要的一種檢測就是檢測使用者提供的表針是否有效,核心在接收一個用戶空間的表針之前,核心必需要保證:

1)表針指向的顯存區域屬於使用者空間

2)表針指向的顯存區域在進程的位址空間裡

3)若果是讀,讀顯存應當標記為可讀。若果是寫,該顯存應標記為可寫。

核心提供了兩種方式來完成必須的偵測和核心空間與使用者空間之間資料的來回拷貝。這兩個方式必須有一個被呼叫。

内核调用用户态函数_内核调用call_linux 内核调用

#copy_to_user():向使用者空間寫入資料,須要3個參數。第一個參數是進程空間中的目的顯存位址。第二個是核心空間內的來源位址

.第三個是須要拷貝的資料寬度(位元組數)。

copy_from_user():向用戶空間讀取資料,須要3個參數。第一個參數是進程空間中的目的顯存位址。第二個是核心空間內的源地

址.第三個是須要拷貝的資料寬度(位元組數)。

注意:這兩個都有可能造成阻塞。當包含使用者資料的頁面被換出到硬盤上而不是在數學顯存上的時侯,這些情況才會發生。此時linux 核心呼叫,進程都會休眠,直到缺頁處理程序將該頁從硬盤重新換回化學記憶體。

核心在執行系統呼叫的時侯處於進程上下文,current表針指向當前任務,也就是引起系統呼叫的那種進程。在行程上下文中,核心可以休眠(例如在系統呼叫阻塞或明確呼叫schedule()的時侯)但是可以被佔領。當系統呼叫回傳的時侯,控制權一直在system_call()中,它最終會負責切換到用戶空間並讓使用者進程繼續執行。

為linux新增一個系統呼叫時間很簡單的事情,如何設計和實作一個系統呼叫是困局所在。實現系統呼叫的第一步是決定它的用途,這個用途是明晰且惟一的,不要嘗試編撰多用途的系統呼叫。 ioctl則是背面教材。新系統呼叫的參數,回傳值和錯誤碼該是哪些linux教學下載,這種都很關鍵。一旦一個系統呼叫編撰完成後,把它註冊成為一個即將的系統呼叫是件繁雜的工作,通常下邊幾步:

1)在系統呼叫表(通常坐落entry.s)的最後加入一個表項。從0開始算起,系統表項在該表中的位置就是它的系統呼叫號碼。如第

10個系統呼叫分配到系統呼叫號碼為9

2)任何體系結構,系統呼叫號碼必須定義於include/asm/unistd.h中

3)系統呼叫必須被編譯進核心映像(不能編譯成模組)。這只要把它放進kernel/下的一個相關文件就可以。

一般,系統呼叫靠C庫支持,使用者程式透過包含標準頭檔並和C函式庫鏈接,就可以使用系統呼叫(或則使用函式庫函數,再由函式庫函數實際呼叫)。幸好的是linux本身提供了一組巨集用於直接對系統呼叫進行存取。它會設定好暫存器並呼叫int$0x80指令。這種巨集是_syscalln(),其中n的範圍是從0到6.代表必須傳遞給系統呼叫的參數個數。這是因為該巨集必須了解究竟有多少參數會根據哪些順序壓入暫存器。以open系統呼叫為例:

open()系統呼叫定義如下是:

longopen(constchar*filename,intflags,intmode)

直接呼叫此系統呼叫的巨集的方式為:

#defineNR_open5

_syscall3(long,open,constchar*,filename,int,flags,int,mode)

這樣,應用程式就可以直接使用open().呼叫open()系統呼叫直接把裡面的巨集放置在應用程式中就可以了。對每位宏來說,都有2 2*n個參數。每位參數的意義簡單明了,這兒就不詳盡說明了。

以上是Linux中系統呼叫不是核心的合法入口的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:itcool.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板