系统调用
系统调用
概念
操作系统作为用户和计算机硬件之间的接口,需要向上提供一些简单易用的服务。主要命令接口和程序接口。其中程序接口由一组系统调用组成。
系统调用是操作系统提供给应用程序(程序员/编程人员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以通过系统调用来请求获得操作系统内核的服务
系统调用和库函数的区别
以C语言编写的应用程序为例,该应用程序调用了C语言的库函数,C语言的库函数则是对操作系统提供的系统调用做了一步封装。本质上还是通过系统调用控制计算机的硬件(显示屏等)
当然,并不是所有的C库函数都设计系统调用:
- 取绝对值函数不涉及系统调用。
- 创建一个新文件涉及系统调用

为什么系统调用时必须的?
如果两个进程可以随意的,并发的共享打印机资源,会出现什么情况?
比如有两个进程并发的执行,打印机设备交替的接受到了WPS和Word两个进程发来的打印请求。结果就会导致两篇论文就混在一起了。
解决方法:由操作系统的系统调用对共享资源进行统一管理,并向上提供系统调用,用户进程如果想要使用打印机这种共享资源,就只能通过系统调用向操作系统内核发出打印请求。内核回答各个请求协调处理。
什么功能会用到系统调用?
应用程序通过系统调用请求操作系统的服务。而系统中的各种共享资源都由操作系统内核统一掌管,因此凡是与共享资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统内核提出服务请求,由操作系统内核代为完成。
系统调用过程
例子:用户在C语言程序中调用了C语言库write()
和read()
函数。
- 用户程序发起系统调用
- 用户先将该程序编译,生成
.exe
可执行文件。并运行此文件。 CPU
读取文件中的二进制指令开始一行一行的执行。参数通过寄存器(如ebx、ecx、edx等)传递给内核。并将系统调用号存入eax
寄存器。
- 用户先将该程序编译,生成
- 触发中断
- 传统方式使用
int 0x80
指令触发中断(x86架构)。 - 现代
CPU
通过syscall/sysenter
指令直接进入内核态,减少性能损耗。
- 传统方式使用
- 中断处理
- CPU检测到中断后,从用户态切换到内核态,并跳转到预定义的中断向量表中的
system_call
函数入口。 - 保存中断现场。
- CPU检测到中断后,从用户态切换到内核态,并跳转到预定义的中断向量表中的
- 内核执行系统调用
- 根据eax中的系统调用号,在系统调用表中索引对应的内核函数地址(如sys_read)。
- 将存在寄存器的参数拿出来,执行系统调用程序。
- 返回用户态
- 保存返回值:内核将结果(如读取的字节数)存入eax寄存器。
- 恢复中断上下文。
- CPU执行指令将内核态切换为用户态,继续执行应用程序。
大致过程:
- 传递系统调用参数
- 执行陷入指令触发中断(用户态)
- 通过终端将用户态变为内核态。
- 执行相应的内核程序处理系统调用(内核态)
- 返回应用程序。
注意:
- 陷入指令是在用户态执行的,执行陷入指令之后立即引发一个内中断,使CPU进入核心态。
- 发出系统调用请求是在用户态,而对系统调用的相应处理在核心态下进行。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 MyAKDreamのBlog!