编译内核模块
内核模块在用gcc编译时需要使用特定的参数。另外,一些宏同样需要定义。 这是因为在编译成可执行文件和内核模块时, 内核头文件起的作用是不同的。 以往的内核版本需要我们去在makefile中手动设置这些设定。尽管这些makefile是按目录分层次 安排的,但是这其中有许多多余的重复并导致代码树大而难以维护。 幸运的是,一种称为kbuild的新方法被引入,现在外部的可加载内核模块的编译的方法已经同内核编译统一起来。想了解更多的编译非内核代码树中的模块(就像我们将要编写的)请参考帮助文件linux/documentation/kbuild/modules.txt。
现在让我们看一个编译名字叫做hello-1.c的模块的简单的makefile文件:
example 2-2. 一个基本的makefile
obj-m = hello-1.o
现在你可以通过执行命令 make -c /usr/src/linux-`uname -r` subdirs=$pwd modules 编译模块。 你应该得到同下面类似的屏幕输出:
[root@pcsenonsrv test_module]# make -c /usr/src/linux-`uname -r` subdirs=$pwd modules
make: entering directory `/usr/src/linux-2.6.x
cc [m] /root/test_module/hello-1.o
building modules, stage 2.
modpost
cc /root/test_module/hello-1.mod.o
ld [m] /root/test_module/hello-1.ko
make: leaving directory `/usr/src/linux-2.6.x
请注意2.6的内核现在引入一种新的内核模块命名规范:内核模块现在使用.ko的文件后缀(代替 以往的.o后缀),这样内核模块就可以同普通的目标文件区别开。更详细的文档请参考 linux/documentation/kbuild/makefiles.txt。在研究makefile之前请确认你已经参考了这些文档。
现在是使用insmod ./hello-1.ko命令加载该模块的时候了(忽略任何你看到的关于内核污染的输出 显示,我们将在以后介绍相关内容)。
所有已经被加载的内核模块都罗列在文件/proc/modules中。cat一下这个文件看一下你的模块是否真的 成为内核的一部分了。如果是,祝贺你!你现在已经是内核模块的作者了。当你的新鲜劲过去后,使用命令 rmmod hello-1.卸载模块。再看一下/var/log/messages文件的内容是否有相关的日志内容。
这儿是另一个练习。看到了在声明 init_module()上的注释吗? 改变返回值非零,重新编译再加载,发生了什么?
在内核linux 2.4中,你可以为你的模块的“开始”和“结束”函数起任意的名字。它们不再必须使用 init_module()和cleanup_module()的名字。这可以通过宏 module_init()和module_exit()实现。这些宏在头文件linux/init.h定义。唯一需要注意的地方是函数必须在宏的使用前定义,否则会有编译 错误。下面就是一个例子。
example 2-3. hello-2.c
/*
* hello-2.c - demonstrating the module_init() and module_exit() macros.
* this is preferred over using init_module() and cleanup_module().
*/
#include /* needed by all modules */
#include /* needed for kern_alert */
#include /* needed for the macros */
static int __init hello_2_init(void)
{
printk(kern_alert "hello, world 2\n");
return 0;
}
static void __exit hello_2_exit(void)
{
printk(kern_alert "goodbye, world 2\n");
}
module_init(hello_2_init);
module_exit(hello_2_exit);
现在我们已经写过两个真正的模块了。添加编译另一个模块的选项十分简单,如下:
example 2-4. 两个内核模块使用的makefile
obj-m = hello-1.o
obj-m = hello-2.o
现在让我们来研究一下linux/drivers/char/makefile这个实际中的例子。就如同你看到的, 一些被编译进内核 (obj-y),但是这些obj-m哪里去了呢?对于熟悉shell脚本的人这不难理解。这些在makefile中随处可见 的obj-$(config_foo)的指令将会在config_foo被设置后扩展为你熟悉的obj-y或obj-m。这其实就是你在使用 make menuconfig编译内核时生成的linux/.config中设置的东西。
阅读(2990) | 评论(0) | 转发(0) |