实验二 内核编译法添加系统调用

声明系统调用

1
2
3
4
5
# 切换到解压后的目录
cd /usr/src/linux-6.9.6

# 添加系统调用ID,32位系统选择32.tbl,64位系统选择64.tbl
vim arch/x86/entry/syscalls/syscall_64.tbl

该文件有一个系统调用列表,最前面的属性是 id,在里面添加系统调用号,修改后保存 syscall_64.tbl 文件。

id 需要未被使用,每个字符串之间是 Tab 键,不是空格键,最后一列建议跟上文保持一致,直接 sys 开头就行。

1
335     common      helloworld              sys_helloworld

加入函数声明

1
2
3
4
5
# 切换到解压后的目录
cd /usr/src/linux-6.9.6

# 打开syscalls.h
vim arch/x86/include/asm/syscalls.h

使用 Shift + G 快速跳转到文件尾添加下面内容,需要在 end if 的前面

1
asmlinkage  long  __x64_sys_helloworld(void);

编写函数

1
2
3
4
5
# 切换到解压后的目录
cd /usr/src/linux-6.9.6

# 打开sys.c
vim kernel/sys.c

使用 Shift + G 快速跳转到文件尾添加下面内容,同样需要在 end if 的前面

1
2
3
4
5
asmlinkage long __x64_sys_helloworld(void){
printk( "helloworld!");//这里使用printk会打印到日志里,详细见后面结果
printf( "helloworld!\n");//这里使用printf会直接打印到屏幕上
return 1;
}

编译内核并使用

使用 实验一 Linux 内核编译 相关步骤编译内核并且使用。

使用下面的的代码使用系统调用:

测试程序需要将系统调用号修改成自己添加的

1
2
3
4
5
6
7
8
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <stdio.h>
#define SYS_HELLOWORD 335
int main(){
syscall(SYS_HELLOWORD);
}

使用 printf

直接打印到屏幕上,效果如下。

image-20240624214157269

使用 printk

在使用 printk 时,我们会将日志级别放到最开始的位置。

没有设置日志级别时,会为其设一个默认的日志级别: default_message_loglevel

printk() 中的消息日志级别小于当前控制台日志级别(console_printk[0])时,printk 的信息就会在控制台上显示。

但无论当前控制台日志级别是何值,即使没有在控制台打印出来,可以通过下面方法查看日志:

1
2
# 使用dmesg命令打印日志
dmesg

image-20240624214558191