在之前的创建简单的Kernel System Call内,如果每次想要修改system call的源代码,都要重新执行一次编译内核、make install、重新启动, 步骤麻烦而且还需要浪费很多时间。
一个简单的方法是,可以在system call的源代码中创建一个 函数指针,并将其暴露给外部的 kernel module;kernel module可以自己设置真正的函数逻辑,然后绑定这个函数指针。这样原来的system call就成了一个 wrapper/decorator。
1. 修改原本的system call代码
接着上次的代码,这次将原本的 kernel根目录下的kernel/hello.c
的代码修改为:
#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
long (*stub_hello_call)(long, long) = NULL; // 函数指针
EXPORT_SYMBOL(stub_hello_call); //
asmlinkage long sys_hello(long a, long b){
if(stub_hello_call == NULL){
return -ENOSYS;
}
else{
return stub_hello_call(a,b);
}
}
解释:
EXPORT_SYMBOL
是一个 macro, 它用来让 kernel symbols 可以被 loadable modules调用;只用被export了的symbol才能够被其他的modules访问到
https://lkw.readthedocs.io/en/latest/doc/04_exporting_symbols.html
2. 创建简单的module 代码
自己创建个hello文件夹,在里面写hello.c
:
#include <linux/module.h>
#include <linux/printk.h>
// 声明外部函数指针
extern long (*stub_hello_call)(long a, long b);
// 函数逻辑代码
long hello_call(long a, long b){
long sum = a + b;
printk("hello world\n");
printk("The sum is %ld\n", sum);
return 0;
}
int my_module_init(){
printk(KERN_INFO "Loading %s\n", MODULE_NAME);
stub_hello_call = &hello_call; // hook上 system call export出来的函数指针
return 0;
}
void my_module_exit(){
printk(KERN_INFO "Removing %s\n", MODULE_NAME);
stub_hello_call = NULL; // 将system call export的 函数指针取消挂钩
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("hello");
// MODULE_AUTHOR();
在同文件夹下,创建Makefile:
obj-m := hello_world.o
# obj-y := test_call.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
解释:
obj-m
代表指定的这个是 moduleobj-y
代表指定的这个是 kernel built-in
3. 加载模块和删除模块
先在同文件夹下执行make
命令。这会生成很多文件,其中的hello.ko
就是需要操作的模块文件。
加载模块前
先在加载module之前运行一下上一篇文章内写的测试代码:
./testhello
The result is -1
查看一下sudo dmesg
, 没有任何东西。
加载模块后
sudo insmod hello.ko # load 模块
查看并且确认模块已经正确加载:
lsmod | grep hello
运行 testhello:
./testhello
The result is 0
查看一下sudo dmesg
, 成功打印了代码的内容
卸载模块后
接下来,将模块remove掉:
sudo rmmod hello
lsmod | grep hello
再次运行测试代码:
The result is -1
大功告成!!