歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux系統調用

操作系統管理軟硬件資源,用戶進程只能直接或間接的通過系統調用訪問系統資源,而用戶進程與內核運行於不同的權限空間,需要進行用戶態到內核態的轉變,這一轉變是通過系統中斷實現。現以getpid為例:

在用戶態通過API接口編程如下:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    return printf("pid is %d\n", getpid()) > 0;
}


getpid 為應用編程接口(API)函數,提供統一標准接口,實現是通過系統調用獲得進程ID。
系統調用函數由唯一的調用號標識,x86構架下在文件 arch/x86/include/asm/unistd.h 指定,實現文件根據32位系統與64為系統的不同分別實現在相同目錄的unistd_32.h和unistd_64.h文件,現通過64位系統分析,32位系統原理相同。

#define __NR_getpid                             39
__SYSCALL(__NR_getpid, sys_getpid)

可以看到getpid系統調用號為 39, 當然這在不同的系統上並不一定相同,getpid API函數的封裝正是封裝了種種不同。

系統初始化時創建名為 sys_call_table 的表項,其中存儲了系統調用函數,而__NR_*調用號正是表項索引,sys_call_table的定義 32構架位於 arch/x86/kernel/syscall_table_32.S,sys_call_table 為起始地址依次存儲一系列函數地址。

ENTRY(sys_call_table)
	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
	.long sys_exit
	.long ptregs_fork
	.long sys_read
	.long sys_write
	.long sys_open		/* 5 */
	.long sys_close
	.long sys_waitpid
	.long sys_creat
	.long sys_link
	...

64位構架位於arch/x86/kernel/syscall_64.c,這裡干脆定義成了一個sys_call_ptr_t類型數組,其初始化由宏__SYSCALL完成。

const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
	/*
	*Smells like a like a compiler bug -- it doesn't work
	*when the & below is removed.
	*/
	[0 ... __NR_syscall_max] = &sys_ni_syscall,
#include <asm/unistd_64.h>
};

系統調用時,根據 sys_call_table[__NR_getpid] 獲得 sys_getpid 地址調用之。如此,我們便可通過修改 sys_call_table 的初始化和__NR_*的定義來增加自己的系統調用和修改原來系統調用的執行方式。

倘若增加我們自己的系統調用,那接下來一問題是我們如何調用?getpid函數由glibc庫封裝,接下來需要看如何直接調用該內核函數。當然,通過源碼可以看到getpid的實現即為 sys_getpid 函數,但因為調用需要進行特權級的轉變,所以直接調用sys_getpid函數是行不通的。

Copyright © Linux教程網 All Rights Reserved