Linux 有许多功能是通过模块的方式, 在需要时才载入 kernel。 如此可使 kernel 较为精简,进而提高效率,以及保有较大的弹性。这些可动态加载的模块,通常是系统的设备驱动程序。加载模块采用 insmod 指令,其常用语法如下。
insmod [-fkmpsvxX] [-o<模块名称>] [模块文件]
其中的参数解释如下。
-f:不检查目前 kernel 版本与模块编译时的 kernel 版本是否一致,强制将模块载入。
-k:将模块设置为自动卸载。
-m:输出模块的载入信息。
-p:测试模块是否能正确地载入 kernel。
-s:将所有信息记录在系统记录文件中。
-v:执行时显示详细的信息。
-x:要汇出模块的外部符号。
-X:汇出模块所有的外部符号,此为预设置。
• rmmod(卸载模块)指令
Linux 把系统的许多功能编译成一个个单独的模块,待有需要时再分别加载它们,如果不再需要这些模块的时候,就可以使用 rmmod 命令来卸载这些模块。其语法如下。
rmmod [-as] [模块名称...]
其使用参数说明如下。
-a:删除所有目前不需要的模块。
-s:把信息输出至 syslog 常驻服务,而非终端机界面
/* hello.c */这个模块什么也不干,只是在模块加载时打印一条信息,卸载时也打印一条信息。麻雀虽小,但五脏具全,MODULE_LICENSE()指明认证方式,现在支 持的有:“GPL” “GPL v2" "GPL and additional rights" "Dual BSD/GPL" "Dual MIT/GPL" "Dual MPL/GPL" "Proprietary",这是内核2.6里新添加的,实验发现它不是必需的。module_init()指明模块的入口,这是必需 的;module_exit()指明模块的出口,这也是必需的。
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE ( "Dual BSD/GPL" );
static int hello_init ( void )
{
printk ( KERN_ALERT "Hello, World/n" );
return 0 ;
}
static int hello_exit ( void )
{
printk ( KERN_ALERT "Goodbye, cruel world/n" );
}
module_init ( hello_init );
module_exit ( hello_exit );
编译使用make的扩展功能,在与hello.c同一目录下创建一个 Makefile文件,内容如下:
/* Makefile */其中TARGET指明了目标文件的名字,KDIR指明了引用头文件的位置,请根据具体情况修改该文件。不过有几点要说明,模块的编译需要有一个内核源码的目 录结构,如果有内核源码当然更好,直接把KDIR改为源码的路径就OK了。当然只有一个内核目录结构也就可以了,毕竟需要的只是头文件,及一些编译脚本, 在Linux各发行版的/usr/src/下是有这样一个目录结构的,比如我的系统为Ubuntu9.10,内核为2.6.31-19的通用版,在 /usr/src/下就有linux-headers-2.6.31-19-generic这样一个目录。所以我使用KDIR=/usr/src /linux-headers-2.6.31-19-generic。其实还有一个目录名为linux-headers-2.6.31-19,而且你会发 现linux-headers-2.6.31-19-generic里的大部分文件只是指向linux-headers-2.6.31-19的一些链接, 不过linux-headers-2.6.31-19里面默认缺少一些编译模块所需要的文件,不要使用它。
TARGET = hello
KDIR =/ usr / src / linux - headers - 2.6 . 31 - 19 - generic
PWD = $ ( shell pwd )
obj - m := $ ( TARGET ). o
default :
make - C $ ( KDIR ) M = $ ( PWD ) modules
接下来,你只要使用make命 令,就可以进行编译了,make会为你处理好一切,它会根据KDIR找到编译所需要的文件。如果你运气好的话,你的当前目录下就会成生hello.o hello.mod.o hello.mod.c modules.order Module.markers Module.symvers hello.ko,当然可爱的hello.ko就是我们想要的。到此你的模块已经成功生成了,接下来便可以加载这个模块看看效果了。
使用 insmod ./hello.ko来加载模块,如果你遇到insmod: error inserting 'hello.o' :-l invalid module format这样的错误,不用惊慌,并不是你的模块有问题,而是你当前运行的内核版本与你编译链接的头文件版本不一致,所以会出现格式不对的问题。此时, 你可以更换系统内核,也可以下载一个与系统版本一致的内核源码重新编译该模块。如果你没有遇到任何问题,也没有打印出任何信息,那么恭喜你,你的内核加载 成功了,你可以使用lsmod命令来罗列出当前你系统加载的所有模块,相信你在列表中会找到hello的。你可能会疑惑,为什么没有如我们想像中的那样, 打印出"Hello, World"?呵呵,这是因为printk并不会把打印内容打印到你当面的终端,要知道模块是运行在内核态的,而你所能面对的是用户态,内核态的打印信息 需要通过log或者dmesg命令来查看,想看到打印結果,最简单的方法是敲入dmesg命令,你就可以看到你所希望看到的信息了,同时,你也可以打开 /var/log/message这个文件进行查看。
最后,使用rmmod hello来卸载模块,同样,使用dmesg可以看到打印出的"Goodbye, cruel world"。