系统调用的过程
source link: https://jiajunhuang.com/articles/2020_02_27-syscall.md.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
系统调用的过程
来自APUE和TLPI读书笔记
一个系统调用是怎么发生的呢?典型步骤如下:
- 调用标准库中的函数,例如C语言中,申请内存时,会使用如下代码:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main() {
char *s = malloc(sizeof("hello"));
printf("s -> %s\n", s);
memcpy(s, "world", 5);
printf("s -> %s\n", s);
free(s);
}
其中 malloc
就是一个标准库中的函数,它其实是一个系统调用的wrapper。
malloc
所包裹的系统调用函数(Linux中一般是sbrk
)不一定每一次都会被调用,因为通常来说,为了提高内存分配的性能, 标准库里的wrapper函数会对所申请的内存进行缓存。此外,内核所提供的系统调用,也会规定好以一种什么样的方式进行调用, 哪个参数该放哪个寄存器上等等。标准库里的函数负责把这些准备好。由于所有的系统调用都是以同一种方式进入内核,而每个系统调用都有一个编号,这个编号是内核用来分辨是哪个系统调用用的, wrapper函数把系统调用的编号copy到寄存器
%eax
。wrapper函数执行一个
trap(一般翻译为中断)
进入内核模式,比如以前的Linux中,一般是执行int 0x80
,当然现在的CPU 有一个更高效的方式。当进入内核态之后,操作系统完成这么几件事情:
- 保存当前的寄存器里的值
- 检查系统调用编号是否正确
- 执行系统调用的代码
- 执行完成之后恢复寄存器的值
- 返回到用户态的wrapper函数中,所执行系统调用的地方的代码指令处
wrapper函数对系统调用返回的结果进行检查,如果出错了,就设置好
errno
这个值。
这就是一个典型的C程序进行系统调用的过程,其他语言也是类似,只不过所使用的标准库函数不一定同名,系统调用返回之后的
处理方式也未必相同(比如未必是使用 errno
而是抛异常等)。
关注公众号,获得及时更新
为什么我要用Linux作为桌面?
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK