Introduction
对于习惯了平时在Linux上进行C应用程序开发的你,是否想窥探一下底层的世界?
对于对Linux Kernel源码无从下手的你,是否希望有一个简易的方法?
是的,这里有一个地方,可以让你轻松的编写和调试Linux Kernel Code。
这个就是我将要介绍的Linux Kernel Module,即Linux内核模块。
Linux Kernel Module究竟是什么?
Linux Kernel Module是一段可以在运行时被加载到Linux Kernel中的代码,可以使用Kernel Functions。Linux Kernel Module的用途很广,最常见的例子就是Device Driver,也就是设备驱动程序。
如果没有Linux Kernel Module,每一行修改Kernel代码,每一个新增的Kernel功能特性,都需要重新编译Kernel,大大浪费了时间和效率。
如何查看已经加载的Linux Kernel Module
在bash下输入:
$ lsmod
Module Size Used by
nls_utf8 16384 1
isofs 30960 1
...
或者直接在bash下查看:
$ cat /proc/modules
Hello World!
闲话少说,开始编写我们的第一个Kernel Module,直接上代码,hello-world.c:
#include <linux/kernel.h>
#include <linux/module.h>
int init_module(void) {
printk(KERN_INFO "Hello World!\n");
return 0;
}
void cleanup_module(void) {
printk(KERN_INFO "Bye World!\n");
}
内核中打印函数和应用打印函数略微不同,printf()是glibc的函数,内核中使用printk()。实际上printk()的设计并不是为了打印,而是为了记录,根据配置不同,内容可能由syslogd或者klogd打印到/var/log/messages中,或者打印到你的console中。
编译的话,和应用层代码使用的gcc或者g++不同,Kernel Module使用Makefile,或者kbuild。下面是Makefile文件:
obj-m += hello-world.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
在命令行输入:
$ Make
如果成功,你将在当前目录看到hello-world.ko,以及其他的临时文件。
通过modinfo来查看module信息,在命令行输入:
$ modinfo hello-world.ko
filename: hello-world.ko
...
现在没有什么信息,别着急,后面会介绍如何将信息(author, license等)写到Kernel Module中。
运行我们的Kernel Module,在命令行输入:
$ insmod hello-world.ko
如果提示权限不够,输入:
$ sudo insmod hello-world.ko
执行完毕后,可能在console上不会显示任何结果。还记得前面提到的吗?我们需要查看/var/log/messages,最简单的方法是在命令行输入:
$ dmesg
...
[26484.975093] Hello World!
好了,我们卸载模块,同样在命令行输入:
$ rmmod hello-world.ko
如果提示权限不够,输入:
$ sudo rmmod hello-world.ko
执行完毕后,可能在console上不会显示任何结果。同样查看/var/log/messages:
$ dmesg
...
[26484.975093] Hello World!
[26739.017345] Bye World!
一个像样的Kernel Module
我们先简单包装一下Hello World的Code,让他看上去稍微丰富一点:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
static int __init init_my_module(void) {
printk(KERN_INFO "Hello, my module!\n");
return 0;
}
static void __exit exit_my_module(void) {
printk(KERN_INFO "Bye, my module!\n");
}
module_init(init_my_module);
module_exit(exit_my_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("csprojectedu");
这里我们使用了linux/init.h中提供的宏__init和__exit,解放我们的函数名,不再沿用蹩脚的init_module()和cleanup_module()了。
Makefile还是沿用之前的:
obj-m += my_module.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
在命令行输入:
$ Make
通过modinfo来查看module信息,在命令行输入:
$ modinfo my_module.ko
filename: my_module.ko
author: csprojectedu
license: GPL
...
是不是多了author和license?insmod的时候也不再报缺少license的警告了吧。
Summary
通过最简单的hello-world.c和Makefile(真的没有比这个更简单的代码了),介绍了如何编写我们的第一个Kernel Module。动手做一做吧,你已经迈向了内核世界的第一步。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。