1、UNIX 内核系统调用的机制系统调用的机制1.中断和异常大多数的微处理器的处理都可以被当前执行的程序具有更高优先级的事件中断。这些特殊事件有各自的特点,但总的说来,它们可以分为中断和异常(Interrupts and excepton)。中断可以说是硬件设备对处理器产生的“刺激”,它们是由外部事件引起的。这些事件包括硬盘和软盘的活动,键盘的输入,调制解调器的控制活动等等.另一方面,异常则是响应某些系统错误引起的,也可以是响应某些可以在程序中执行的特殊机器指令引起的。不管产生的是中断还是异常,处理器响应的方式是类似的。执行一段被称为中断处理或异常处理的特殊程序。一般来说,在特定的系统中,对每一种
2、中断和异常类型都有单独的处理程序。对每一种中断和异常,都在 0255 范围内给以一个唯一的数加以标记,当发生中断或者异常时,这个数(称为向量号)用作进入指针数组(中断或异常向量表)的索引,表中每个指针指向用来处理特定中断或异常类型的子程序的地址。大多数中断和异常象函数一样进行处理。所以当中断或异常处理程序结束时,被中断的程序将重发生中断时的断点继续向下执行。2.系统调用的机制在 UNIX 系统中,系统调用是作为一种异常类型实现的。它将执行相应的机器代码指令来产生异常信号。产生中断或异常的重要效果是系统自动将用户模式切换为内核模式来对它进行处理。这就是说,执行系统调用的异常指令时,将自动地将系统
3、切换为内核模式,并安排异常处理程序的执行。它知道如何处理这一调用。以 LINUX 为例,在 LINUX 中实现系统调用异常的实际指令是:int $0x80这一指令使用中断/异常向量号 128(即 16 进制的 80)将控制权转移给内核。为达到在系统调用时不必用机器指令编程,在标准的 C 语言库中为每一个系统调用提供了一段短的子程序,完成机器代码的编程工作。事实上,机器代码非常短。它要做的工作只是将送给系统调用的参数值加载到 CPU寄存器中,接着执行 int $0x80 指令。然后运行系统调用,系统调用的返回值将送入 CPU 的一个寄存器中,标准的库子程序取得这一返回值,并将它送回给你的程序。为
4、了使系统调用执行成为一项简单的任务,LINUX 中提供了一组预处理宏指令。它们可以用在程序中。这些宏指令取一定的参数,然后扩展为调用指定的系统调用的函数:这些宏指令具有类似下面的名称格式:syscallN(parameters)其中 N 用系统调用所需的参数数目代替,而 parameters 则用一组参数代替。这些参数使宏指令完成适合于特定的系统调用的扩展。例如,为了建立调用 seuid()系统调用的函数,应该使用;syscall1(int,setuid,uid_t,uid)syscallN()宏指令的第一个参数说明产生的函数的返回值的类型(这里是int),第二个参数说明产生的函数的名称(这里
5、是 setuid)。后面是系统调用所需要的每个参数。这一宏指令后面还有两个参数分别用来指定参数的类型和名称(这里是 uid_t 和 uid)。用作系统调用的参数的数据类型有一个限制,它们的容量不能超过 4 个字节。这是因为执行 int $0x80 指令进行系统调用时,所有的参数值都存在32 位的 CPU 寄存器中。使用 CPU 寄存器传递参数带来的另外一个限制是可以传递给系统调用的参数的数目。这个限制是最多可以传送 5 个参数。所以一共定义了 6 个不同的 syscall N()宏指令(从 syscall 0()到syscall5() )。一旦 syscall N()宏指令用特定的系统调用的相应参数进行了扩展,得到的结果是一个与系统调用同名的函数,它可以在用户程序中执行这一系统调用。