新手入门,绕不开HelloWord,本章写一个最简单的helloword模块,从编译到加载,再到验证,没有问题。
第一步
创建hello.c文件,代码如下:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h>
int __init hello_module_init(void)
{
printk(KERN_INFO "Hello world.\n");
return 0;//A non 0 return means init_module failed; module can't be loaded.
}
void __exit hello_module_exit(void)
{
printk(KERN_INFO "Bye world.\n");
}
module_init(hello_module_init);
module_exit(hello_module_exit);
内核模块提供module_init和module_exit两个接口,其实是宏定义, 这些宏在linux / init.h中定义。 需要注意的是,必须在调用宏之前定义init和exit函数,否则会出现编译错误。
printk函数其实是内核态的printf,是内核日志接口,有8个优先级,对应有宏,可以在linux / kernel.h中查看。 如果未指定优先级,默认使用DEFAULT_MESSAGE_LOGLEVEL优先级别。
第二步
编写makefile,内容如下:
obj-m += hello.o
hello-y :=
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
obj-m表示编译生成可加载模块。相对应的,obj-y表示直接将模块编译进内核。
这里并没有输入hello.c源文件,这得益于makefile的自动推导功能。
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
-C选项:此选项指定内核源码的位置,make在编译时会进入内核源码目录执行编译,编译完成时返回。
M=$(PWD):需要编译的模块源文件地址。
第三步
在终端执行make,无报错,在源码目录下会生成hello.ko文件,如下:
[root@localhost helloword]# ls
hello.c hello.ko hello.mod.c hello.mod.o hello.o Makefile modules.order Module.symvers
此时执行命令以验证:
[root@localhost helloword]# insmod hello.ko
[root@localhost helloword]# dmesg |tail -n 1
[25991.570137] Hello word.
[root@localhost helloword]# rmmod hello.ko
[root@localhost helloword]# dmesg |tail -n 2
[25991.570137] Hello word.
[26029.873588] Bye world.
[root@localhost helloword]#
可以看到,我的模块是正常加载,并能正常退出。
总结
这只是最简单的模块开发步骤,当然要构建一个复杂的模块代码,makefile也是很关键。自linux2.4开始,linux使用两个宏module_init和module_exit来完成模块的初始化和销毁。
内核开发,需要对应linux源码看,这样才能很清楚的找到接口的实现。内核说起来很难,其实,并没有想像的那么可怕,有问题在开源社区都能找到答案。
接下来,我会自己先玩一些复杂的模块,玩通了再来写博客,有意思又能成长的事情,欢迎一起交流。