编译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
2
3
4
cd /usr/src
sudo tar jxvf linux-2.6.23.12.tar.bz2
# 或者如果是 .tar.gz 格式
sudo tar zxvf linux-2.6.23.12.tar.gz

2. 添加自定义系统调用

2.1 修改 sys.c 文件

在内核源码中添加系统调用实现:

1
2
cd /usr/src/linux-2.6.23.12
sudo vim kernel/sys.c

在文件末尾添加以下代码:

1
2
3
4
5
/* 自定义系统调用:打印消息并返回参数 */
asmlinkage int sys_mysyscall(int num) {
printk(KERN_INFO "Hello from mysyscall! Received: %d\n", num);
return num;
}

注意asmlinkage 是必需的,表示参数通过栈传递。

2.2 修改系统调用表

编辑系统调用表文件:

1
2
3
cd /usr/src/linux-2.6.23.12/arch/i386/kernel
# 如果没有 i386 目录,尝试 x86 目录
sudo vim syscall_table.S

在文件末尾添加:

1
.long sys_mysyscall

2.3 添加系统调用号

修改系统头文件(用户空间):

1
sudo vim /usr/include/asm-i386/unistd.h

在文件末尾添加:

1
#define __NR_mysyscall 325

修改内核头文件

1
sudo vim /usr/src/linux-2.6.23.12/include/asm-i386/unistd.h

添加以下内容:

1
#define __NR_mysyscall 325

同时将原有的:

1
#define NR_syscalls 325

修改为:

1
#define NR_syscalls 326

提示:如果要添加多个系统调用,依次递增调用号(326, 327…)

3. 编译内核

3.1 配置内核

1
2
cd /usr/src/linux-2.6.23.12
sudo make menuconfig

在菜单中保持默认配置即可,直接保存退出。

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
2
3
4
5
# 复制内核镜像
sudo cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.23.12

# 生成 initramfs
sudo mkinitramfs -o /boot/initrd.img-2.6.23.12 2.6.23.12

4. 配置 GRUB 引导

4.1 编辑 GRUB 配置文件

1
2
3
sudo vim /boot/grub/menu.lst
# 或者
sudo vim /boot/grub/grub.conf

4.2 添加新内核启动项

在文件中找到类似以下的配置:

1
2
3
4
5
title Ubuntu 7.10, kernel 2.6.22-14-generic
root (hd0,0)
kernel /boot/vmlinuz-2.6.22-14-generic root=UUID=e2478f9d-7f5d-458f-b017-43458a8f62ea ro quiet splash
initrd /boot/initrd.img-2.6.22-14-generic
quiet

仿照格式添加新内核配置:

1
2
3
4
5
title Ubuntu 7.10, kernel 2.6.23.12 (Custom)
root (hd0,0)
kernel /boot/vmlinuz-2.6.23.12 root=UUID=e2478f9d-7f5d-458f-b017-43458a8f62ea ro quiet splash
initrd /boot/initrd.img-2.6.23.12
quiet

注意UUID 需要替换为你自己的分区 UUID,可通过 sudo blkid 查看。

4.3 显示 GRUB 菜单

注释掉隐藏菜单选项(如果有):

1
#hiddenmenu

保存并退出。

5. 重启系统

1
sudo reboot

在 GRUB 启动菜单中选择新编译的内核 kernel 2.6.23.12 (Custom) 启动。

🧪 测试自定义系统调用

编写测试程序

创建 test.c 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

#define __NR_mysyscall 325

int main() {
int result;

printf("调用自定义系统调用 mysyscall...\n");
result = syscall(__NR_mysyscall, 42);

printf("系统调用返回值: %d\n", result);

return 0;
}

编译并运行

1
2
gcc -o test test.c
./test

预期输出

1
2
调用自定义系统调用 mysyscall...
系统调用返回值: 42

查看内核日志

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
2
sudo apt-get update
sudo apt-get install build-essential libncurses5-dev

问题 4:系统调用返回 -1

解决方案

  • 检查系统调用号是否正确
  • 确认 NR_syscalls 已更新
  • 查看 dmesg 输出是否有错误信息

✅ 总结与建议

关键要点

  1. 耐心:内核编译耗时较长,尤其是 make modules
  2. 备份:修改前备份重要文件
  3. 版本匹配:确保内核版本与教程一致
  4. 日志查看:善用 dmesg 调试

学习收获

  • 理解 Linux 内核编译流程
  • 掌握系统调用添加方法
  • 熟悉内核模块机制
  • 提升 Linux 系统底层认知

📚 参考资料

祝各位实验顺利!如有问题欢迎交流讨论! 🎉