模块是Linux内核特有的一种机制,是一些可以作为独立程序来编译的函数和数据类型的集合。它可以用来动态地增加内核的功能。我们可以编写一个模块,将它作为Linux内核空间扩展来执行。
在装载模块时将它的代码链接到内核中。Linux模块装载分为两种,静态装载:模块在内核启动时装载;动态装载:模块在内核运行的过程中装载。如果一个模块装载完毕后,该模块的某一个函数被调用了,那么内核就可以使用系统调用,并将其传递到模块中的相应函数。
如果在Linux机器上有模块运行(不管是静态的还是动态的),那么可以通过读取/proc/modules文件看出哪些模块正在运行。模块通常用来实现设备驱动程序。模块一旦被装载进系统,就在内核地址空间管态下执行。如果模块知道内核数据结构的地址,模块就可以读写内核的数据结构。因为模块的设计和实现与内核无关,所以模块不能依靠静态链接通过变量名引用内核数据结构。Linux内核提供了一种机制:实现数据结构的文件可以导出结构的符号名,这样在运行时就可以使用这个结构了。调试程序为了允许用户通过符号名来引用数据结构就需要依赖于这种运行期的变量绑定。
在构建内核时,使用文件的头文件导出内核公共符号。如果要找出究竟导出了哪些符号供模块直接使用,需要阅读kernal/ksyms.c文件。在编写模块的过程中,编写(修改)导出变量需要格外注意,因为通过修改变量会修改内核的状态,造成不希望的后果,所以在未了解修改内核变量的后果之前应该对这些变量只进行读操作。
模块是一种抽象的数据类型,具有一个可以通过静态内核中断的接口。最小的模块结构必须包括两个函数,这两个函数在系统装载和卸载模块时使用,分别是init_module()和cleanup_module()。因此模块文件的格式如下:
#include <linux/kernel.h>
#include <linux/module.h>
...
int init_module(){
/*安装时,初始化模块的编码*/
}
int cleanup_module(){
/*卸载时,清除模块的编码*/
}