系统调用

系统调用(system call)是内核提供给应用程序的一系列函数接口。系统调用将应用程序的请求通知内核,调用相应的内核函数处理请求,处理完成后,将处理结果返回给应用程序,user space 只能通过系统调用来访问kernel提供的函数。

中断有两个重要的属性,中断号和中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表(Interrupt Vector Table),这个数组存储了所有中断处理程序的地址,而中断号就是相应中断在中断向量表中的偏移量。一般地,系统调用都是通过软件中断实现的。linux系统下,调用系统调用时产生0x80号中断。

当进程调用系统调用或者发生中断时,CPU从用户态切换成内核态,用户进程摇身一变成为内核进程,用户进程和内核进程用的是同一个PCB,但是有自己的栈空间,称为用户栈和内核栈。

当进行系统调用时,进程不仅要从用户态切换到内核态,同时也要完成栈切换,这样处于内核态的系统调用才能在内核栈上完成调用。系统调用返回时,还要切换回用户栈,继续完成用户态下的函数调用。

在调用int指令进行系统调用后会把用户栈的esp的值及相关寄存器压入内核栈中,系统调用通过iret指令返回,在返回之前会从内核栈弹出用户栈的esp和寄存器的状态,然后进行恢复。

因此,发生系统调用陷入内核态时,寄存器上下文保存在内核栈中,返回用户态时,弹出内核栈中寄存器的值,进行恢复

linux系统下系统调用的实现:(以open系统调用为例)

<1>use space存储着open系统调用的系统调用号,当调用系统调用时,查表,将open系统调用号5传给内核。在执行 int 0x80时,eax寄存器中放的是系统调用号5。

mov   eax,5
int   0x80

<2>系统调用的函数名称转换

#define __syscall_return(type, res) \
do { \
    if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \
        errno = -(res); \
        res = -1; \
    } \
    return (type) (res); \
} while (0)


#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, type5,arg5) \
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
    : "=a" (__res) \
    : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
      "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
__syscall_return(type,__res); \
}

<3>内核查系统调用表sys_call_table,知道5号是_NR_open系统调用。

#define __NR_restart_syscall      0
#define __NR_exit         1
#define __NR_fork         2
#define __NR_read         3
#define __NR_write        4
#define __NR_open         5
#define __NR_close        6
#define __NR_waitpid      7
#define __NR_creat        8
#define __NR_link         9
#define __NR_unlink      10

<4>执行相应处理函数,将文件的描述符通过eax寄存器返回给用户空间,以后用户空间通过这个描述符对文件进行读写操作。

<5>恢复用户态寄存器的值,继续执行用户空间代码。

Linux最多允许向系统调用传递6个参数,分别依次由eax,ebx,ecx,edx,esi,edi这6个寄存器完成,eax存的是系统调用号,需要6个及以上参数情况不多见,这时应该有一个单独的寄存器存放指向所有这些参数在用户空间的地址的指针。给用户空间的值通过eax寄存器返回。

linux系统上,系统调用表sys_call_table保存在/include/Asm-i386/unistd.h文件中。
这里写图片描述
linux2.6.11.12版本中,共定义了288个系统调用,现在最高的版本已经支持319个系统调用了。

系统调用通过中断实现,需要完成栈切换
使用寄存器传参,这需要额外的保存和恢复的过程。
系统调用很耗时,要尽量少用

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值