Linux下常见系统调用
fork open read write close等
标准I/O库
fopen fread fwrite fclose ffflush等
标准IO库中预定义了三个流
stdin 标准输入
stdout 标准输出
stderr 标准错误
它们引用的文件和STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO指向的文件相同
标准IO库通过调用read/write系统调用来实现真正的IO。
Linux下系统调用的实现
Linux下的系统调用是通过0x80实现的,但是我们知道操作系统会有多个系统调用(Linux下有319个系统调用),而对于同一个中断号是如何处理多个不同的系统调用的?最简单的方式是对于不同的系统调用采用不同的中断号,但是中断号明显是一种稀缺资源,Linux显然不会这么做;还有一个问题就是系统调用是需要提供参数,并且具有返回值的,这些参数又是怎么传递的?也就是说,对于系统调用我们要搞清楚两点:
1. 系统调用的函数名称转换。
2. 系统调用的参数传递。
首先看第一个问题。实际上,Linux中处理系统调用的方式与中断类似。每个系统调用都有相应的系统调用号作为唯一的标识,内核维护一张系统调用表,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量。在进行系统调用是只要指定对应的系统调用号,就可以明确的要调用哪个系统调用,这就完成了系统调用的函数名称的转换。1
假如Linux中open的调用号是5
Linux中是通过寄存器%eax传递系统调用号,所以具体调用open的过程是:将5存入%eax中,然后进行系统调用sys_open
完成操作。
对于参数传递,Linux是通过寄存器完成的。
Linux最多允许向系统调用传递6个参数,分别依次由%ebx,%ecx,%edx,%esi,%edi和%ebp这个6个寄存器完成。
如上图2所示,Linux中,在用户态和内核态运行的进程使用的栈(空间)是不同的,分别叫做用户空间和内核空间,两者各自负责相应特权级别状态下 的函数调用。当进行系统调用时,进程不仅要从用户态切换到内核态,同时也要完成空间切换,这样处于内核态的系统调用才能在内核空间上完成调用。系统调用返回时,还要切换回用户空间,继续完成用户态下的函数调用。
系统调用很耗时耗资源原因在于俩点:
第一,系统调用通过中断实现,需要完成栈切换。
第二,使用寄存器传参,这需要额外的保存和恢复的过程。