操作系统实验做到“系统调用”这一章,很多同学第一次意识到:原来操作系统不是一门纯理论课,而是真的可以“动手改内核”的课。实验指导书里那句“新增一个系统调用并验证”看起来轻飘飘,真做起来要面对内核源码、编译环境、系统调用表、grub引导一长串东西,不少人就在这一步卡住了。这篇我把实验三从原理到实操完整拆开,按我自己做实验时的路径来讲:系统调用为什么是这么设计的、代码怎么加进去、内核怎么编、验证怎么做,以及我在编译内核时踩过的各种坑。适合正在做这个实验的本科生,也适合想搞懂系统调用机制的自学者。
1. 系统调用实验的底层逻辑:用户程序是在怎么“找内核办事”的
1.1 用户态和内核态之间有一道墙
操作系统实验做到系统调用,第一个绕不开的概念就是特权级。CPU分了几个特权级,Linux只用了两个:内核态(ring 0)拥有全部权限,可以直接操作内存、设备、中断;用户态(ring 3)什么硬件都碰不了,连往显存里写一个字节都要内核代劳。
这个设计不是故意给程序员添堵,而是系统稳定性的根基。你想一下,如果任意一个用户程序都能随便改内存页表、直接往磁盘的某个扇区写数据,那一个崩溃的程序就能把整个系统带崩,或者一个恶意程序可以直接读到别人的进程内存。所以操作系统必须给用户程序开一个“合法的窗口”,这个窗口就是系统调用。
我在带实验时喜欢打一个比方:内核就像学校食堂的后厨,用户程序是来打饭的学生,你不能自己冲进后厨翻锅,但你可以走到窗口前点菜。窗口就是系统调用,窗口上贴的菜单就是系统调用表,你报的菜名就是系统调用号,递进去的校园卡和饭盒就是参数和缓冲区。
1.2 从printf到write,中间到底发生了什么
很多同学在上一门《C语言程序设计》时天天用printf,但从来没有想过printf背后发生了什么。printf是C标准库函数,它做了一些格式化的工作之后,最终要调用write这个系统调用把字符串交给内核,由内核驱动终端或文件系统把数据真正写出去。
在这个调用链里,库函数和系统调用是两回事。库函数跑在用户态,它自己完成格式化、缓存之类的逻辑;系统调用则要跨越用户态和内核态的边界,CPU要切到内核态去执行内核代码。这个跨越需要一个特殊的指令,在x86_64架构上就是syscall指令。执行这条指令之前,用户程序把系统调用号放进rax寄存器,把参数依次放进rdi、rsi、rdx等寄存器,然后执行syscall,CPU就会按内核提前设置好的入口地址跳进内核态,开始执行对应的系统调用处理函数。
也就是说,系统调用本质上是“按照约定好的号码,让CPU陷入内核并执行指定函数”的过程。理解了这条主线,实验三做什么就很清楚了:往这张菜单上添加一道新菜,再让后厨把这道菜真的做出来。
1.3 系统调用表:操作系统内置的“菜单”
系统调用表是内核里一张很关键的表,每一行对应一个系统调用,记录了三样东西:系统调用号、调用名称、对应的内核函数入口。用户程序传进来的系统调用号通过这张表映射到具体的函数,然后内核才执行真正的工作。
这张表不是运行时动态配置的,而是编译内核时静态生成的,每一行写死在代码里。这就是为什么实验三要求“新增系统调用”时,需要重新编译内核:不重编,系统调用表里就不会有你新加的那一行,内核也根本不认识你的新调用号。
所以实验三的任务拆开就是四步:改系统调用表、实现内核函数、重新编译并安装内核、写用户态程序验证。下面每一节都在解决这四件事中的一件。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 实验环境准备:版本匹配、依赖安装与快照兜底
2.1 内核源码版本怎么选
新增系统调用要先拿到内核源码。实验机上如果用的是Ubuntu,我建议优先选一个和当前系统版本匹配的官方稳定内核源码,而不是拿最新的Linus主分支来折腾。
为什么?内核编译不是什么玄学,但工具链和源码之间确实有兼容性。比如老内核配新GCC,或者新内核配老版本的libelf,都可能出现莫名其妙的编译错误。我做过一次实验,拿6.x的内核源码放到Ubuntu 18.04上编译,光是openssl相关的头文件就报了一堆错,后来换回5.4.x版本一次就过了。选错版本属于是给自己增加工作量。
下载源码有两个常用方式,任选其一就行。第一种是去kernel.org下载对应版本的tar.xz压缩包解压到/usr/src目录,例如:
bash复制cd /usr/src
sudo wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.x.tar.xz
sudo tar -xvf linux-5.15.x.tar.xz
第二种是直接用apt拉当前系统对应版本的源码:
bash复制sudo apt-get source linux-image-$(uname -r)
我推荐第一种,因为apt源码
