深入理解系统调用
为了安全,Linux 中分为用户态和内核态两种运行状态。对于普通进程,平时都是运行在用户态下,仅拥有基本的运行能力。当进行一些敏感操作,比如说要打开文件(open)然后进行写入(write)、分配内存(malloc)时,就会切换到内核态。内核态进行相应的检查,如果通过了,则按照进程的要求执行相应的操作,分配相应的资源。这种机制被称为系统调用,用户态进程发起调用,切换到内核态,内核态完成,返回用户态继续执行,是用户态唯一主动切换到内核态的合法手段(exception 和 interrupt 是被动切换)。
当⽤户态进程调⽤⼀个系统调⽤时,CPU切换到内核态并开始执⾏system_call(entry_INT80_32或entry_SYSCALL_64)汇编代码,其中根据系统调⽤号调⽤对应的内核处理函数。具体来说,在Linux中通过执⾏int $0x80或syscall指令来触发系统调⽤的执⾏,进⼊内核后,开始执⾏对应的中断服务程序entry_INT80_32或entry_SYSCALL_64。
Linux内核中⼤约定义了四五百个系统调⽤,这时内核如何知道⽤户态进程希望调⽤的是哪个系统调⽤呢?内核通过给每个系统调⽤⼀个编号来区分,即系统调⽤号。内核实现了很多不同的系统调⽤,⽤户态进程必须指明需要执⾏哪个系统调⽤,这需要使⽤EAX寄存器传递⼀个名为系统调⽤号的参数。除了系统调⽤号外,系统调⽤也可能需要传递参数,在32位x86体系结构下普通的函数调⽤是通过将参数压栈的⽅式传递的。系统调⽤从⽤户态切换到内核态,在⽤户态和内核态这两种执⾏模式下使⽤的是不同的堆栈,即进程的⽤户态堆栈和进程的内核态堆栈,传递参数⽅法⽆法通过参数压栈的⽅式,⽽是通过寄存器传递参数的⽅式。寄存器传递参数的个数是有限制的,⽽且每个参数的⻓度不能超过寄存器的⻓度,32位x86体系结构下寄存器的⻓度最⼤32位。除了EAX⽤于传递系统调⽤号外,参数按顺序赋值给EBX、ECX、EDX、ESI、EDI、EBP,参数的个数不能超过6个,即上述6个寄存器。如果超过6个就把某⼀个寄存器作为指针,指向内存,就可以通过内存来传递更多的参数。以上就是32位x86体系结构下系统调⽤的参数传递⽅式。
由于压栈的⽅式需要读写内存,函数调⽤速度较慢,64位x86体系结构下普通的函数调⽤和系统调⽤都是通过寄存器传递参数,RDI、RSI、RDX、RCX、R8、R9这6个寄存器⽤作函数/系统调⽤参数传递,依次对应第 1 参数到第 6 个参数。
下面用嵌入式汇编代码调用编号为8的系统调用creat,观察系统调用的过程。creat函数用来创建一个新的文件,函数原型为int creat(const char *pathname, mode_t mode);,成功返回为只写打开的文件描述符,若出错则返回-1。
编译一个Linux内核,使用busybox自制简易根文件系统,使用qemu运行虚拟机,用GDB进行调试。
触发系统调用的test.c程序如下:
#include <stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h> #include <fcntl.h> int main(int argc,char *argv[]) { int fd; //fd= creat(argv[1],0755); //if (fd<0) // printf("error!"); asm volatile( "movl %1,%%ebx\n\t" //系统调⽤传递第⼀个参数使⽤EBX寄存器,为argv[1] "movl $0755,%%ecx\n\t"//系统调⽤传递第二个参数使⽤ECX寄存器,为0755 "movl $0x8,%%eax\n\t"//使⽤%eax传递系统调⽤号8,⽤16进制为0x8 "int $0x80\n\t" //触发系统调⽤ "movl %%eax,%0\n\t" //通过EAX寄存器返回系统调⽤值 :"=m"(fd) :"b"(argv[1]) ); printf("%d\n",fd); fclose(fd); return 0; }
在gdb中加断点__ia32_sys_creat,运行test.c编译成的可执行程序test,在断点处停止,观察堆栈情况。

"int $0x80\n\t"指令触发系统调用后,先执行entry_INT80_compat函数,该函数对现场进行保存,之后调用do_int80_syscall_32函数,由用户态切换至内核态,再调用do_syscall_32_irqs_on函数,在其内调用__ia32_sys_creat函数完成creat系统调用的功能,之后切换回用户态,entry_INT80_compat函数恢复现场。

运行test 2.txt命令成功创建了2.txt文件。

浙公网安备 33010602011771号