Linux 内核新增系统调用
zstu 浙江理工大学 操作系统 课程设计 任务A 新增系统调用
1、编写一个新系统调用的响应函数,函数的名称和功能由实验者自行定义。把新的系统调用函数嵌入到Linux内核中
2、编写应用程序以测试新的系统调用并输出测试结果
以 Debian 12 为例
1 下载并解压 Linux Kernel 源码
在 https://www.kernel.org/ 处下载,以 6.6.2 为例。
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.2.tar.xz |
2 添加系统调用函数
新增 kernel/hello.c
文件如下:
// kernel/hello.c |
SYSCALL_DEFINE0
是一个宏,用于定义一个不接受任何参数的系统调用。这个宏处理系统调用的名称和参数数量。在这个例子中,hello
是系统调用的名称。数字0
表示这个系统调用不接受任何参数。
printk
是内核中的一个函数,用于输出日志信息。KERN_INFO
是日志级别,表示这条信息是一条普通的信息性消息。"Hello, Linux 6.6.2\n"
则是要输出到内核日志的实际消息。当这个系统调用被执行时,这条消息会被记录在内核日志中,可以用dmesg
命令查看。
3 系统调用表中注册系统调用
对于 x86 架构,修改 arch/x86/entry/syscalls/syscall_64.tbl
文件
添加以下内容,注意代码序号,按序存放
# For x86_64 |
4 在系统调用头文件中声明
修改include/linux/syscalls.h
,在最后一行#endif
之前添加以下代码
// include/linux/syscalls.h |
asmlinkage
是一个宏,它用于告诉编译器该函数的参数不是通过寄存器传递的(这是C调用惯例的常见方式),而是通过系统调用的堆栈传递的。
这是因为用户空间程序通常通过syscall
指令来进行系统调用,该指令将参数放在寄存器中,而系统调用服务例程(即系统调用的实际实现)需要从堆栈中获取这些参数。
5 在 kernel 目录下的 Makefile 中添加引用
修改 kernel/Makefile
,更新代码如下
在 obj-y
的最后添加 hello.c
6 重新编译并安装内核
安装依赖
apt install dwarves build-essential libncurses-dev bison flex libssl-dev libelf-dev bc |
构建之前确保你在 linux-6.6.2 目录下
编译内核需要很长的时间
make defconfig # 使用默认配置 |
在编译内核后出现Kernel: arch/x86/boot/bzImage is ready (#1)
表示成功
对于使用 grub 的机器,使用以下命令安装内核,然后重启系统
update-grub |
重启后使用 uname -a
检查内核版本,如下表示成功
7 测试系统调用
编写 hello.c
程序
|
编译运行
gcc -o hello hello.c |
出现 returned 0 表示成功,-1表示失败
在 dmesg 中查看消息
dmesg | tail |
可以看到输出了 Hello, Linux 6.6.2