什么是系统调用?我的理解是系统调用是操作系统提供的一组函数,比如I/O读写磁盘等。由于是操作系统提供的,故只能在内核态中执行。用户编写的程序平时运行在用户态,需要用系统调用时只能通过特定的方式(int 0x80中断进入内核,eax寄存器指定具体的系统调用,用edi、esi等寄存器向系统调用传递参数)来使用系统调用。
大致的执行逻辑如下所示:
应用程序在用户态执行时可能会请求系统调用,比如读写磁盘的I/O操作,这时就需要int 0x80指令。int 0x80指令是一条硬件中断指令,该指令的执行意味着程序将从用户态进入内核态,同时由硬件负责保存用户态的执行现场,并把程序的用户态堆栈转换为内核态堆栈。
Int0x80之后就进入到内核代码了,在内核中首先执行到system_call的位置,pushl %eax的意思是把eax寄存器的值压入程序内核态堆栈,eax中存放着系统调用号,系统调用号标识了不同的系统调用。用户态程序传递给系统调用的参数存放在ebx、ecx、edx等等寄存器中,而ebx、ecx、edx等寄存器的值通过SAVE_ALL宏压入内核堆栈。
系统调用处理完之后由RESTORE_ALL宏把SAVE_ALL压入的寄存器反向弹出。
Iret指令与int 0x80相反,iret从内核态返回到用户态,一次系统调用完成。
下图更具体的说明了这一过程:
sys_call_table意为系统调用表,维护了每个系统调用函数的内存入口地址。eax寄存器保存着系统调用号,4 * (eax),在32位系统中一个指针大小为4字节,4 * (eax)就指向了某一个具体的系统调用程序所在的内存位置。