编译Linux内核增加系统调用
实验环境:Ubuntu 7.10 + Linux Kernel 2.6.23.12
耗时:约 2-3 小时(主要是编译时间)
难度:⭐⭐⭐
经过一两天的摸索,终于在 Ubuntu 虚拟机中成功完成了内核编译和系统调用添加实验。期间踩了不少坑,换了几个内核版本,重新编译了多次。现将完整步骤整理如下,希望能有所帮助!
📋 准备工作
系统要求
- Ubuntu 7.10 或更高版本
- 至少 20GB 磁盘空间
- 4GB 以上内存(虚拟机建议分配 2GB+)
下载内核源码
访问 https://www.kernel.org 下载 Linux 内核源码包(本文使用 linux-2.6.23.12.tar.gz)
🔧 详细步骤
1. 解压内核源码
将内核包解压到 /usr/src 目录:
1 | cd /usr/src |
2. 添加自定义系统调用
2.1 修改 sys.c 文件
在内核源码中添加系统调用实现:
1 | cd /usr/src/linux-2.6.23.12 |
在文件末尾添加以下代码:
1 | /* 自定义系统调用:打印消息并返回参数 */ |
注意:
asmlinkage是必需的,表示参数通过栈传递。
2.2 修改系统调用表
编辑系统调用表文件:
1 | cd /usr/src/linux-2.6.23.12/arch/i386/kernel |
在文件末尾添加:
1 | .long sys_mysyscall |
2.3 添加系统调用号
修改系统头文件(用户空间):
1 | sudo vim /usr/include/asm-i386/unistd.h |
在文件末尾添加:
1 |
修改内核头文件:
1 | sudo vim /usr/src/linux-2.6.23.12/include/asm-i386/unistd.h |
添加以下内容:
1 |
同时将原有的:
1 |
修改为:
1 |
提示:如果要添加多个系统调用,依次递增调用号(326, 327…)
3. 编译内核
3.1 配置内核
1 | cd /usr/src/linux-2.6.23.12 |
在菜单中保持默认配置即可,直接保存退出。
3.2 编译内核镜像
1 | sudo make bzImage |
耗时:约 30-60 分钟
3.3 编译内核模块
1 | sudo make modules |
耗时:约 1-2 小时(虚拟机会更慢)
建议:此时可以休息一下,喝杯咖啡或打打球 😊
3.4 安装模块
1 | sudo make modules_install |
执行后会在 /lib/modules/ 下生成 2.6.23.12 目录。
3.5 安装内核
1 | # 复制内核镜像 |
4. 配置 GRUB 引导
4.1 编辑 GRUB 配置文件
1 | sudo vim /boot/grub/menu.lst |
4.2 添加新内核启动项
在文件中找到类似以下的配置:
1 | title Ubuntu 7.10, kernel 2.6.22-14-generic |
仿照格式添加新内核配置:
1 | title Ubuntu 7.10, kernel 2.6.23.12 (Custom) |
注意:
UUID需要替换为你自己的分区 UUID,可通过sudo blkid查看。
4.3 显示 GRUB 菜单
注释掉隐藏菜单选项(如果有):
1 | #hiddenmenu |
保存并退出。
5. 重启系统
1 | sudo reboot |
在 GRUB 启动菜单中选择新编译的内核 kernel 2.6.23.12 (Custom) 启动。
🧪 测试自定义系统调用
编写测试程序
创建 test.c 文件:
1 |
|
编译并运行
1 | gcc -o test test.c |
预期输出:
1 | 调用自定义系统调用 mysyscall... |
查看内核日志
1 | dmesg | tail |
应该能看到类似输出:
1 | [12345.678901] Hello from mysyscall! Received: 42 |
常见问题及解决方案
问题 1:找不到 i386 目录
解决方案:新版本内核可能使用 x86 目录,修改路径为:
1 | cd /usr/src/linux-2.6.23.12/arch/x86/kernel |
问题 2:make modules 非常慢
解决方案:
- 使用多核编译:
sudo make -j4 modules(4 为 CPU 核心数) - 虚拟机分配更多 CPU 和内存
问题 3:编译报错缺少依赖
解决方案:安装必要的编译工具:
1 | sudo apt-get update |
问题 4:系统调用返回 -1
解决方案:
- 检查系统调用号是否正确
- 确认
NR_syscalls已更新 - 查看
dmesg输出是否有错误信息
✅ 总结与建议
关键要点
- 耐心:内核编译耗时较长,尤其是
make modules - 备份:修改前备份重要文件
- 版本匹配:确保内核版本与教程一致
- 日志查看:善用
dmesg调试
学习收获
- 理解 Linux 内核编译流程
- 掌握系统调用添加方法
- 熟悉内核模块机制
- 提升 Linux 系统底层认知
📚 参考资料
祝各位实验顺利!如有问题欢迎交流讨论! 🎉