中断与系统调用

系统调用的概念

  程序员或系统管理员通常并非直接和系统调用打交道,在实际应用中,程序员调用的的函数,或称为应用程序接口(API),管理员使用的则是更高层次的系统命令。操作系统为每个系统调用在标准C函数库中构造一个具有相同名字的封装函数,由它来屏蔽下层的复杂性,负责把操作系统提供的服务接口----系统调用-----封装成应用程序能够直接调用的函数(库函数)

  系统调用通过中断机制向内核提交请求,它的功能由内核函数实现,进入内核后不同系统调用找到各自对应的内核函数,这些内核函数就是系统调用的“服务例程”。API实质上是一个函数定义,说明如何获得一个给定服务,如read(),malloc(),free()等。它有可能和系统调用形式上一致,如read()函数就和read()系统调用对应,但未必总是一一对应,往往会出现不同函数的内部用到同一个内核函数,如malloc(),free()内部均利用sys_brk()内核函数来扩大或缩小进程堆;一个函数也可利用几个内核函数组合完成任务,有些函数不需要任何内核函数,它的实现与内核无关。系统命令相对与编程接口有更高的层次,它们是内部引用函数的可执行程序,如常用的系统命令ls,hostname等,而这些命令的实现大多数依靠系统调用。

  下面以read()为例来了解系统调用的执行流程,当应用程序调用read(fd,buffer,nbytes)函数时,该函数在Linux/GNU提供的标准C库,即libc中,对应的封装函数由下面汇编指令实现:

      movel  $3,%eax

      movel  fd,%ebx

      movel  buffer,%ecx

      movel  nbutes,%edx      

      int  $0x80

  在Linux中规定int  $0x80指令是系统调用的总入口,若干个寄存器中存放应用程序传递个内核的参数。内核为了区分不同的系统调用,需要给每个都分配唯一的系统调用号,而相对应的内核函数的入口地址都放在系统调用表中。内核在获得系统调用号后根据寄存器EAX中调用号的值跳转到系统调用表相应的内核函数,以完成应用程序请求的服务。

系统调用的执行流程

  系统调用与普通C语言函数调用最大的区别在于系统调用需要陷入内核态,发生特权级的转换。

  1.保存现场  2.跳到内核函数  3.参数传递  

  4.系统调用封装

  应用程序发出的系统调用是同步事件,虽然它在内核态执行,但却在调用进程的上下文中,所以既可以访问进程地址空间,也可以访问内核空间。system_call()在内核栈上保存硬件上下文,然后使用系统调用号作为系统调用表system_call_table的索引,以确定system_call()应该执行哪个系统调用对应的内核函数。当系统调用执行结束后,system_call()在对应的寄存器EAX中放入返回的int值或错误码,并从内核栈恢复硬件上下文,回到用户态并把控制权交给库函数,库函数再返回给应用程序。

  5.系统调用上下文

  内核在执行系统调用时处于进程上下文中,current指针指向当前进程,即引发系统调用的进程。

https://www.cnblogs.com/qiaoshanzi/archive/2013/05/16/3082550.html

猜你喜欢

转载自www.cnblogs.com/feng9exe/p/12521100.html
今日推荐