日期:2014-05-16 浏览次数:20761 次
UNIX系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口。
从编程者的观点看,API和系统调用之间的差别是没有关系的:唯一相关的事情就是函数名、 参数类型以及返回代码的含义。然而,从内核设计者的观点看,这种差别确实有关系,因为系统调用属于内核,而用户态的库函数不属于内核。
当用户态的进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。调用系统调用的最终结果都是跳转到所谓系统调用处理程序的汇编语言函数。因为内核实现了很多不同的系统调用,进程必须传递一个名为系统调用号的参数来识别所需的系统调用,eax寄存器就用此目的。
系统调用处理程序与其他异常处理程序的结构类似,执行如下操作:
下图展示了调用系统调用的应用程序、相应的封装例程、系统调用处理程序以及系统调用服务例程之间的关系,箭头表示函数之间的执行流。把CPU从用户态切换到内核态和从内核态切换到用户态。
为了把系统调用与相应的服务例程关联起来,内核利用了一个系统调用分派表,这个表存放在sys_call_table数组中,有NR_syscalls个表项:第n个表项包含系统调用号为nd的服务例程的地址。
可以通过两种不同的方式嗲用系统调用:
同样内核可以通过两种方式从系统调用退出,从而使CPU切换回到用户态:
但是进入内核的两种范式并不像看起来那么简单,因为:
1)通过int $0x80指令发出系统调用
调用系统调用的传统方法是使用汇编语言指令int。向量128(0x80)对应于内核入口点,在内核初始化期间调用的函数trap_init(),用下面的方式建立对应于向量128的中断描述符表表项:
set_system_gate(0x80,&system_call);