Linux系统调用

系统调用基本原理

系统调用其实就是函数调用,区别是调用内核态的函数。但是用户态到内核态不是随意切换的,所以通过系统调用接口实现用户态到内核态的切换,在保护机制的计算机系统中,用户必须通过软件中断或陷入的方式使进程从用户态切换为内核态。
在i386体系中,Linux系统调用接口是通过软中断指令int 0x80使进程从用户态进入内核态的,这个过程也叫“陷入”。系统调用接口调用软中断指令int 0x80的时候,这个指令会发生一个中断向量码为128的中断请求,并在响应过程中将进程从用户态切换为内核态。
通过软中断0x80,系统会跳转到一个预设好的内核空间地址,它指向了系统调用处理程序,即在entry.S文件中的system_call函数。也就是,所有的系统调用都会统一跳转到这个地址执行system_call()函数。
因为Linux只允许系统调用接口使用128这一个中断向量,并在中断号为128的中断服务例程中,调用不同调用不同的内核服务例程,所以,系统调用接口除了要引发int 0x80软中断外,为了进入内河后调用不同的内核服务例程,还需要提供识别内核服务例程的参数,称之为“系统调用号”。
每个系统调用都有对应的系统调用号,同时内核中有一个system_call_table数组,它是个函数指针数组,每个函数指针都指向了系统调用的服务例程,下标就是该内核服务例程的系统调用号,用以指明到底执行哪个系统调用。当int 0x80软中断执行时,系统调用号会放入eax寄存器中,system_call函数可以读取eax寄存器获得系统调用号,将其乘以4得到偏移地址,以sys_call_table为基地址,基地址加上偏移地址就是应该执行的系统调用服务例程(内核服务例程)的地址。

系统调用参数传递

参数依次存放在寄存器eaxebxecxedxesi中,当系统调用的参数大于5个时(因为上面5个寄存器用完了),执行int 0x80执行仍需将系统调用功能号保存在eax中,所不同的只是参数应该依次存放在一块连续的内存区域内,同时在寄存器eax中保存指向该内存区域的指针。
系统调用完成后,返回值仍将保存在寄存器eax中。由于只是需要一块连续的内存区域来保存系统调用的参数,因此可以完全像普通函数调用一样使用栈(Stack)来传递系统调用所需的参数。但是,注意参数以相反的顺序进栈,先进后出,即应该最后一个参数先进栈,第一个参数最后进栈。如果采用栈来传递系统调用所需要的参数,在执行int $0x80指令时还应该将栈指针的当前值复制到寄存器ebx中。

本文地址:http://www.yuhongwa.com/2018/05/12/系统调用/
转载请注明出处,谢谢!

坚持分享,您的支持将鼓励我继续学习哇~