内核模块编写
Linux 内核模块
LKM(Loadable Kernel module) 尽管 linux 是单内核的,但是 linux 提供了一种机制,允许用户动态的加载模块到内核中。我也是刚开始学习些内核模块,这里从一个简单的 hello world 程序开始,看下 LKM(Loadable Kernel module) 即内核模块编写与普通程序的不同。
内核模块结构
用户态程序
以 hello.c 为示例,在用户态程序下,C 语言代码如下。
#include <stdio.h>
int main(int argc, char** argv){
print('hello world!\n');
return 0;
}
执行该程序只需要通过 gcc -o hello hello.c
生成可执行文件 hello
,然后通过./hello
就可以在 shell 中看见输出了,运行截图如下。
内核模块
内核模块 hello.c 代码如下, module.h
和 kernel.h
几乎是每个内核模块都要包含的。
module_init()
在内核模块插入时执行。module_exit
在内核模块卸载时执行。MODULE_LICENSE
为模块遵循的开源许可证书
1 // Filename: hello.c
2 // Author: lbt
3 // Create Date: 2020-08-01
4 // Description: kernel module example
5
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8
9 int init_hello_module(void){
10 printk("***************Start***************\n");
11 printk("Hello World! Start of hello world module!\n");
12 return 0;
13 }
14
15 void exit_hello_module(void){
16 printk("###############End#################\n");
17 printk("Hello World! End of hello world module!\n");
18 }
19
20
21 MODULE_LICENSE("Dual BSD/GPL");
22 module_init(init_hello_module);
23 module_exit(exit_hello_module);
24
编译并执行内核模块不同于用户态程序,需要编写 Makefile,上述程序的 Makefile 文件如下。执行 make
命令,不出现报错且在当前目录下生成了 hello.ko 即说明编译成功。
make 过程可能报错,我在 centos 最小化安装里,出现了错误。提示 Makefile 第 12 行的 make -C $(KERNEL_DIR) M=$(PWD) modules
执行错误,原因是 $(KERNEL_DIR) 指向的文件不存在,经查阅资料,该文件是一个软链接,链接指向 /usr/src/kernel/
下面的文件, 如下图所示。centos 最小化安装没有内核开发包,需要使用 yum 手动安装,命令为 yum install -y kernel-devel
,安装完成后重新 make 即可成功编译内核模块。
1 # Filename: Makefile
2 # Author: lbt
3 # Create Date: 2020-08-01
4 # Makefile of kernel module `hello`
5
6 obj-m := hello.o # hello.o 与 hello.c 对应
7
8 KERNEL_DIR := /lib/modules/$(shell uname -r)/build #指定内核源码
9 PWD := $(shell pwd) #指向当前目录
10
11 all:
12 make -C $(KERNEL_DIR) M=$(PWD) modules
13 clean:
14 make -C $(KERNEL_DIR) M=$(PWD) clean
shell 下运行以下命令可以对编译好的内核进行控制和查看。
modinfo hello.ko
内核模块信息查看insmod hello.ko
插入内核模块dmesg
查看内核模块输出信息rmmod hello.ko
卸载该内核模块
执行完 insmod hello.ko
后使用 dmesg
会看到以下信息:
执行完 rmmod hello.ko
后使用 dmesg
会看到以下信息:
至此,第一个 linux 内核模块编写完成。