前言
系统调用的基本原理
系统调用其实就是函数调用,只不过调用的是内核态的函数,但是我们知道,用户态是不能随意调用内核态的函数的,所以采用软中断的方式从用户态陷入到内核态。在内核中通过软中断0X80,系统会跳转到一个预设好的内核空间地址,它指向了系统调用处理程序(不要和系统调用服务例程混淆),这里指的是在entry.S文件中的system_call函数。就是说,所有的系统调用都会统一跳转到这个地址执行system_call函数,那么system_call函数如何派发它们到各自的服务例程呢?
我们知道每个系统调用都有一个系统调用号。同时,内核中一个有一个system_call_table数组,它是个函数指针数组,每个函数指针都指向了系统调用的服务例程。这个系统调用号是system_call_table的下标,用来指明到底要执行哪个系统调用。当int ox80的软中断执行时,系统调用号会被放进eax寄存器中,system_call函数可以读取eax寄存器获得系统调用号,将其乘以4得到偏移地址,以sys_call_table为基地址,基地址加上偏移地址就是应该执行的系统调用服务例程的地址。
系统调用的传参问题
当一个系统调用的参数个数大于5时(因为5个寄存器(eax, ebx, ecx, edx,esi)已经用完了),执行int 0x80指令时仍需将系统调用功能号保存在寄存器eax中,所不同的只是全部参数应该依次放在一块连续的内存区域里,同时在寄存器ebx中保存指向该内存区域的指针。系统调用完成之后,返回值扔将保存在寄存器eax中。由于只是需要一块连续的内存区域来保存系统调用的参数,因此完全可以像普通函数调用一样使用栈(stack)来传递系统调用所需要的参数。但是要注意一点,Linux采用的是c语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。如果采用栈来传递系统调用所需要的参数,在执行int 0x80指令时还应该将栈指针的当前值复制到寄存器ebx中。
1.添加系统调用的两种方法
方法一:编译内核法
拿到源码之后
- 修改内核的系统调