用户可以通过两种方式使用系统调用:
第一种方式是通过C库函数,包括系统调用在C库中的封装函数和其他普通函数。(如write,read,kill,mkdir等函数)
第二种方式是使用_syscall宏。2.6.18版本之前的内核,在include/asm-i386/unistd.h文件中定义有7个_syscall宏,分别是:
_syscall0(type,name)
_syscall1(type,name,type1,arg1)
_syscall2(type,name,type1,arg1,type2,arg2)
_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)
_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)
_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6)
这里介绍第二种方式(其实第一种方式本质上就是第二种方式,只不过C库函数对其进行了封装)
先举个例子
如下图,testsyscall调用后,根据宏定义_syscall0会将返回值int和函数名传入。后面会讲到syscall
以下就是如何产生int80中断
根据汇编中传入的宏定义找到对应的系统调用号,这个时候已经由汇编产生int80软中断,切换到内核态了。然后再通过调用号在system_call_table中根据偏移量找到对应的内核态中该系统调用函数,如open就找到了sys_open
参数传递:
函数需要传入几个参数,就调用对应个数的syscalln(),其中n的范围从0到6。代表需要传递给系统调用的参数个数,这是由于该宏必须了解到底有多少参数按照什么次序压入寄存器
对于每个宏来说,都有2+ n个参数。
第一个参数对应着系统调用的返回值类型。
第二个参数是系统调用的名称。再以后是按照系统调用参数的顺序排列的每个参数的类型和名称。
(我的理解:第0个,第1个参数是固定的,后面2-6的值就是参数。)
如上图所示,type是返回类型,name就是系统调用名称。(就是说open函数调用后在汇编里会组合为_NR_open)