前一段时间老师给我们布置了一个有关内核模块编写与加载的作业,有指导书,我看了一眼指导书,和往常一样,都是手把手教的那种。
- 编写内核模块代码
- 编写Makefile文件//注意是Makefile而不是makefile
- 执行make命令
- insmod装载模块
- rmmod移除模块
感觉好像和写一个C代码差不多
但是等我把上面的代码复制过来运行时却频频报错,最后折腾了好久,原来是书上的例子太久远了,对于一些现在的内核已经不适用了,最后在网上找了大佬博客,借用一下代码,最后成功了,记录一下,供以后回顾。
原文链接
首先贴代码
先新建一个文件夹,保证Makefile和hello.c在同一文件夹下
hello.c
#include<linux/module.h>
#include<linux/init.h>
#include<linux/moduleparam.h>
MODULE_AUTHOR("Kevin Taylor");
MODULE_LICENSE("GPL");
static int nbr = 10;
module_param(nbr, int, S_IRUGO);
static int __init hello_init(void)
{
int i;
printk(KERN_ALERT"Init hello mudule...\n");
for(i=0;i<nbr;i++)
{
printk(KERN_ALERT"Hello, how are you? %d\n", i);
}
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT"Exit hello mudule...\n");
printk(KERN_ALERT"I come from hello's module, I have been unload.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIPTION("A Simple Hello World");
MODULE_ALIAS("A simplest module");
Makefile
obj-m := hello.o #后面的hello是你要生成的模块的名字,可自行修改
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
all:
$(MAKE) -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
rm *.ko
rm *.o
注意!!!
由于Makefile文件中命令行前需要有一个Tab键才能被识别,不然会出现Makefile missing separator. Stop.的错误
还有就是不同系统的Tab键的空格数是不同的,并且你可以设置这个值,如果你是直接复制代码的话建议先把命令前的空格全删了,然后自己重新输入Tab
在文件编写好并且保存之后,我们就可以在命令行输入make来编译了,make是linux下一个程序,如果你的电脑显示没有make的话可以通过sudo apt-get install build-essential
命令来安装一些必须的程序
上面的命令适用于ubuntu,不同的系统命令会有所不同,例如cenOS就用yum 代替apt-get,根据自己的系统去网上找对应的下载命令。
然后会出现下面的情形,表示编译成功了
然后ls会发现多了很多文件,hello.ko (kernal object)内核目标文件
lsmod命令可以查看已经加载的模块
用sudo insmod hello.ko
命令将我们得到的模块加载进内核,然后用lsmod | grep hello
就可以看到我们的模块已经可以在已装载模块中查询到了,接下来用dmesg
命令,这个命令是查看日志,刚刚我们的模块实现的是在加载和卸载模块时往日志中写入,所以我们通过查看日志来检测模块功能是否实现。
毫无意外,我们确实往日志中写入了东西,那么我们接下来卸载模块,使用sudo rmmod hello
注意没有.ko了
然后lsmod | hello
,查询不到hello了,然后dmesg
这就实现了简单的模块加载与卸载。