1. 寫在前面
系統調用是操作系統提供給用戶程序調用的一組“特殊”接口。通過這組“特殊”接口,用戶程序可以獲得操作系統內核提供的服務,如文件系統相關系統調用提供的打開文件、關閉文件或讀寫文件服務,時鍾相關的系統調用提供的獲取系統時間、設置系統時間服務等。
從邏輯上來說,系統調用可被看成是一個內核與用戶空間程序交互的接口——好比一個中間人,把用戶進程的請求傳達給內核,待內核把請求處理完畢后再將處理結果送回給用戶進程。
一個系統調用的典型調用過程如下圖所示。
系統調用的作用:
系統服務之所以需要通過系統調用提供給用戶空間,其根本原因是為了對系統進行“保護”。我們知道操作系統的運行空間分為內核空間與用戶空間,它們各自運行在不同的級別中,邏輯上相互隔離,故用戶進程在通常情況下不允許訪問內核數據、不允許使用內核函數,它們只能在用戶空間操作用戶數據,調用用戶空間的函數。但是很多情況下,用戶進程需要獲得系統服務(調用系統程序),這時就必須利用系統提供給用戶的“特殊”接口——系統調用,其特殊性在於規定了用戶進程進入內核的具體位置,即用戶訪問內核的路徑是事先規定好的,只能從規定位置進入內核,而不准許肆意跳入內核。有了上述陷入內核的統一訪問路徑限制,才能有效保證系統內核的安全。我們可以形象地描述上述機制:作為一個游客,你可以買票要求進入野生動物園,但你必須老老實實的坐在觀光車上,按照規定的路線觀光游覽。當然,不准下車,因為那樣太危險,不是讓你丟掉小命,就是讓你嚇壞了野生動物。
在前述文章“Linux-3.10.1內核的編譯和安裝”(詳見http://www.lingyuecloud.com/Index/details/id/58.html)中,我們知道利用Linux內核的開源特性,可以對Linux系統進行定制化開發、編譯和安裝。例如,通過修改Linux內核源碼,我們定制化開發了一個新功能,那么如何在應用程序中使用這個新功能呢?為此,我們還需要為“應用程序”與“內核中新增的新功能”建立橋梁——即一個能夠連接兩者的系統調用。
假設我們已經獲得了Linux-3.10.1的源碼包linux-3.10.1.tar.bz2,解壓該源碼包后得到linux-3.10.1文件夾,並切換到該文件夾下(如何獲取包linux-3.10.1.tar.bz2?如何解壓?請詳見http://www.lingyuecloud.com/Index/details/id/58.html——“Linux-3.10.1內核的編譯和安裝”)。接下來,靈躍桌面雲將以Linux-3.10.1內核為例,詳細描述為內核添加一個新的系統調用的過程,下述所有操作都在linux-3.10.1目錄下進行。
2. 環境說明
注:在下述描述中,涉及在服務器Ubuntu 12.04操作系統環境上的所有操作,均以root身份登錄並執行。
3. 為Linux-3.10.1內核添加一個系統調用
3.1 系統調用號
Linux系統調用號的作用是在系統調用過程中,將其數值作為下標的在系統調用表中進行索引,從而得到處理該系統調用的函數的地址。
每個系統調用都有一個唯一的系統調用號,應用程序可以通過系統調用號調用指定的系統調用。
3.2 系統調用表
與Windows系統中的SSDT(System Services Descriptor Table)的作用一樣,Linux系統調用表保留着處理各個系統調用的函數的入口地址;其實際上是一個二維的指針數組[X][Y],X代表系統調用號,Y代表系統調用函數的入口地址。
3.3 添加系統調用lingyuecloudsyscall
1) 添加自定義的系統調用源代碼
在“linux-3.10.1/kernel”目錄下的sys.c文件中添加自定義的系統調用lingyuecloudsyscall的實現函數。
打開sys.c文件,添加以下示例代碼:
#vim kernel/sys.c
asmlinkage long sys_lingyuecloudsyscall (int number){ } |
2) 修改系統調用表
系統調用表文件在“linux-3.10.1/arch/x86/syscalls”目錄下的syscall_64.tbl文件中。
打開syscall_64.tbl,添加新的系統調用指針,如下所示:
#vim arch/x86/syscalls/syscall_64.tbl
314 64 lingyuecloudsyscall sys_ lingyuecloudsyscall; |
如下圖所示:
其中,314為lingyuecloudsyscall的系統調用號,應用程序可通過此調用號調用lingyuecloudsyscall系統調用,也可以使用其它的系統調用號,但注意不能與已有的系統調用號重復。64表示適配於64位系統內核環境,相關描述詳情可查閱https://en.wikipedia.org/wiki/X32_ABI。
3) 添加系統調用lingyuecloudsyscall的函數聲明
在“linux-3.10.1/include/linux/”目錄下的syscalls.h文件中添加函數聲明。
打開syscalls.h,在倒數第二行添加下面內容:
#vim include/linux/syscalls.h
asmlinkage long sys_lingyuecloudsyscall(int num); |
如下圖所示:
4) 重新編譯
5) 內核
編譯過程詳見http://www.lingyuecloud.com/Index/details/id/58.html——“Linux-3.10.1內核的編譯和安裝”。
6) 測試系統調用
編寫測試程序lingyuecloud_test.c:
#include<stdio.h> #include<linux/unistd.h> #include<sys/syscall.h> int main() { long a; a = syscall(314,100); //調用第314號系統調用,即sys_lingyuecloudcall(); printf("The number is%d\n",a); return 0; } |
編譯測試程序:
#gcc -o lingyuecloud lingyuecloud_test.c
測試結果如下圖所示:
如果能夠看到上述結果,表示你的第一個自定義系統調用已經添加成功。