日期:2014-05-16 浏览次数:20780 次
一. 概述
系统调用是应用程序与内核交互的一种方式。系统调用作为一种接口,通过系统调用,应用程序能够进入操作系统内核,从而使用内核提供的各种资源,比如操作硬件,开关中断,改变特权模式等等。首先,系统调用是一个软中断,既然是中断那么一般就具有中断号和中断处理程序两个属性,Linux使用0x80号中断作为系统调用的入口,而中断处理程序的地址放在中断向量表里。
二. 过程
基于linux-2.6.38,以read()系统调用函数为例进行说明。
在用户空间,read()函数的声明位于#include<unistd.h>,原型为:ssize_t read(int fd, void *buf, size_t count)。下面是read()函数在用户空间的定义的伪代码:
1 ssize_t read(int fd, void *buf, size_t count) 2 { 3 long res; 4 %eax = __NR_read 5 %ebx = fd 6 %ecx = (long)buf 7 %edx= count 8 int $0x80 9 res = %eax 10 return res; 11 }
第4行,用eax寄存器保存read()的系统调用号,在/arch/x86/include/asm/unistd_32.h里定义(#define __NR_read 3);第5~7行,分别将三个参数放入三个寄存器(通过寄存器来传递参数);第8行,执行系统调用,进入内核;第9行,获取eax寄存器所保存的函数返回值。
执行第8行后已经进入了系统内核,由于这是一个中断,因此程序进入到中断向量表中记录0x80号的中断处理程序,中断向量表的初始化在/arch/x86/kernel/traps.c中定义:
1 void __init trap_init(void) 2 { 3 ................... 4 5 #ifdef CONFIG_X86_32 6 set_system_trap_gate(SYSCALL_VECTOR, &system_call); 7 set_bit(SYSCALL_VECTOR, used_vectors); 8 #endif 9 ................... 10 }