编译内核模块
内核模块在用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中设置的东西。
阅读(3003) | 评论(0) | 转发(0) |