内核模块相当于是内核的补丁,可以在内核运行时安装到内核之中。如下面一个简单的hello.c,它是一个内核模块的源码。
#include <linux/module.h>
#include <linux/init.h>
static int __init hello_init(void)
{
printk(KERN_EMERG "Hello world!\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_EMERG "hello exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
在这段代码中,定义了两个函数,分别是hello_init和hello_exit,这两个函数中都是打印了一些信息。与普通的c语言的打印函数不同的是这里用的是printk函数打印的。printk是专门用作内核打印的函数。代码的最后两行把这两个函数分别定义为内核模块初始化阶段执行的函数和内核模块退出的时候执行的函数。
为了编译这个源码,我们写了下面的Makefile文件
KDIR := /lib/modules/4.10.0-28-generic/build
obj-m := hello.o
build: kernel_modules
kernel_modules:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
在这个文件中,首先定义了变量KDIR,它定义了一个路径,就是用来编译内核模块的工具的目录。其中4.10.0-28-generic是内核的版本号。如果我们要在内核中安装内核模块,则必须用内核版本号相同的编译工具进行编译。可以用下面的命令来查看内核的版本号。
uname -r
obj-m := hello.o这一行的作用是指定编译后模块的名字。
build: kernel_modules这一行的作用是到kernel_modules这一段去执行编译的操作。
在kernel_modules这一段的代码是make -C $(KDIR) M=$(PWD) modules
其中-C $(KDIR)的作用是指定编译工具的所在的目录,
M=$(PWD)指定的是源码所在的目录,其中PWD就相当于在终端上执行命令pwd,返回的是当前目录,也就是hello.c和Makefiel存放的目录。最后的modules指明编译的目标是生成内核模块。
Makefile最后两行是clean的代码,含义是清除掉make过程生成的所有文件。
了解了这些,我们就可以开始编译内核模块了。执行make命令,完成内核模块的编译。我们可以看到在当前文件夹下生成了若干可文件,其中hello.ko就是我们生成的内核模块。
用下面的命令可以实现内核模块的安装。
insmod hello.ko
采用下面的命令可以查看已经安装的内核模块。
lsmod
采用下面的命令可以卸载已经安装的内核模块。
rmmod hello