「操作系统」 系统调用

Posted by Dawn-K's Blog on February 26, 2023

系统调用

应用程序执行系统调用

受限直接执行(LDE, limited direct execution)是操作系统的关键底层机制之一,让用户程序受限的运行在硬件上,只是在进行危险操作时向操作系统发出请求。

现代 CPU 存在两个状态 (intel 有 4 个,不过 linux 只使用其中的两个),一个是用户态,一个是内核态。

操作系统为了保护资源,自身是运行在内核模式的,能够执行所有指令。但是其他的进程必须运行在用户模式。然后内核通过 系统调用 来将部分功能开放给用户程序。

从用户态进入到内核态需要 陷入 (trap) 指令,这个指令是不能被用户态程序随便调用的,所以操作系统提供了库函数来对系统调用进行封装。

库函数隐藏了陷入中断等等的细节,实际上系统调用的处理函数都是运行在内核态下的。

库函数基本是首先搜集参数,然后调用软中断来实现系统调用。

软中断

硬件本身会产生中断,比如 IO 完成,时钟中断,网络信息到达等。还有一类软中断,是软件自身触发的,比如 INT 指令跟上一个中断指令号,就可以进行中断操作。

在中断时,硬件会去查询中断向量表,其中注册了中断时应执行的处理函数的地址。

系统调用就是通过软中断来实现,在linux中,是使用 INT 0x80 来触发所有的系统调用( system_call )。 可以理解为, 在使用 INT 0x80 之后,就进入了内核态。执行完对应的处理程序后,即 INT 0x80 返回后,就回到了用户态。

system_call 首先保存所有寄存器到内核栈中,然后通过查看 %eax 中的值, 来调用具体的系统调用。调用完成后执行 ret_from_sys_call() 从内核栈中恢复所有寄存器,然后回到用户态。

总结

LDE 协议分为两段。

  1. 在操作系统内核启动时,内核会将硬件陷阱表 (trap table) 注册到硬件中。
  2. 在用户程序可以通过库函数发起进行系统调用。发起后,库函数会进行参数的收集和中断(INT 0x80),然后进入内核态。中断处理程序会调用0x80号中断处理程序,即系统调用。结束后返回用户态,执行系统调用的下一条语句。

参考资料

介绍Linux系统调用