内核模块程序结构以及编译内核模块(单个文件以及多个文件)
单个文件编译的内核模块例子
#include <linux/module.h> #include <linux/init.h> static int __init hello_init() { printk("Hello world!\n"); } static int __exit hello_exit() { printk("<7>Hello <0>exit!\n"); } module_init( hello_init); module_exit( hello_exit);
1.模块加载函数,通过module_init宏来指定
2.模块卸载函数,通过module_exit宏来指定
3.编译模块需要使用makefile文件,单一依赖文件的makefile
ifneq ($(KERNELRELEASE),) obj-m := hello.o else KDIR := /lib/modules/2.6.18-53.el5/build all: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers endif
注释
ifneq ($(KERNELRELEASE),)
如果KERNELRELEASE这个变量不为空就执行
obj-m := hello.o
第一次执行makefile文件 KERNELRELEASE是为空的,所以就会执行
KDIR := /lib/modules/2.6.18-53.el5/build all: make -C $(KDIR) M=$(PWD) modules
make -C $(KDIR) M=$(PWD) modules的讲解
make -C的含义是进出后面$(KDIR)指定的目录,使用此目录下的makefile来编译内核模块,此例中就是进入 /lib/modules/2.6.18-53.el5/build 下使用它的makefile来编译
M=$(PWD) M是build目录的makefile要求的,表示需要被编译的内核模块代码所在路径(.c文件路径),
$(PWD)代表当前目录下面。
modules是makefile处理当中的目标。
使用/lib/modules/2.6.18-53.el5/build路径下的makefile文件,编译当前目录下的模块,生成modules。
在编译过程中会第二次使用本makefile,第二次使用makefile时KERNELRELEASE就有内核版本号了,
然后就会运行obj-m := hello.o
hello.o是编译完成后内核模块的名字。
编译后会生成.ko文件,就是内核模块
单一.c文件必须和生成的.o文件名对应才行。之后会讲解多文件makefile的写法。
多个文件编译的内核模块例子
main.c
#include <linux/module.h> #include <linux/init.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Fzh"); MODULE_DESCRIPTION("HELLO"); extern int add(int a, int b); static int __init hello_init() { printk("Hello world!\n"); add(1,2); return 0; } static int __exit hello_exit() { printk("<7>Hello <0>exit!\n"); } module_init( hello_init); module_exit( hello_exit);
add.c
int add(int a, int b) { return a+b; }
ifneq ($(KERNELRELEASE),) obj-m := hello.o hello-objs := main.o add.o else KDIR := /lib/modules/2.6.18-53.el5/build all: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers endif
需要注意的是
obj-m := hello.o //最终生成hello.ko hello-objs := main.o add.o //为了最终生成hello.ko需要main.o 和 add.o