系统调用
系统调用
操作系统为用户态进程与硬件及内核资源进行交互提供的一组接口。
系统调用可被看成是一个内核与用户空间程序交互的接口。
极大的提高了系统的安全性
使用户程序具有可移植性
系统调用与系统命令
系统命令相对API,更高一层,每个系统命令都是一个可执行程序。
系统命令的实现调用了系统调用。
通过strace命令可以查看系统命令所调用的系统调用:#strace ls
系统调用与内核函数
l 内核函数在形式上与普通函数一样,但它是在内核实现的,需要满足一些内核编程的要求。
l 系统调用是用户进程进入内核的接口层,由内核函数实现的。
l 进入内核后,不同的系统调用会找到各自对应的内核函数,这些内核函数被称为系统调用的“服务例程”。
初始化系统调用
内核初始化期间调用trap_init()函数建立IDT表中向量128对应的表项,语句如下:set_system_gate(0x80,$system_call)。
Linux只允许系统调用接口使用128这一个软中断向量。这也意味着所有的系统调用接口必须共享这一中断通道,并在同一个中断服务例程中调用不同的内核服务例程。
系统调用接口是通过调用软中断指令“int $0x80”使进程从用户态进入到内核态。
系统调用处理程序
当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。
在Linux中是通过执行int $0x80这条汇编语言来执行系统调用的,这条汇编指令产生向量为128的编程异常。
内核实现了很多不同的系统调用,进程必须传递一个名为系统调用号的参数来指明需要调用的系统调用,eax寄存器就用作这个目的。
系统调用编号
include/asm-i386/unistd.h?v=2.6.17.13
9 #define __NR_exit 1
10 #define __NR_fork 2
11 #define __NR_read 3
12 #define __NR_write 4
13 #define __NR_open 5
14 #define __NR_close 6
15 #define __NR_waitpid 7
……
320 #define __NR_get_robust_list 312
321 #define __NR_splice 313
322 #define __NR_sync_file_range 314
323 #define __NR_tee 315
324 #define __NR_vmsplice 316
325
326 #define NR_syscalls 317
系统调用表
为了把系统调用号与相应的服务例程关联起来,内核利用了一个系统调用表。
这个表存放在sys_call_table数组中有NR_syscalls个表项。
第n个表项对应了系统调用号为n的服务例程的入口地址的指针。
sys_call_table
arch/i386/kernel/syscall_table.S?v=2.6.17.13
1 ENTRY(sys_call_table)
2 .long sys_restart_syscall
3 .long sys_exit
4 .long sys_fork
5 .long sys_read
6 .long sys_write
7 .long sys_open /* 5 */
8 .long sys_close
9 .long sys_waitpid
10 .long sys_creat