在阅读本文之前,请阅读下linux kernel 模块化编程入门这篇文章。
模块的函数导出到符号表才可以供其他函数使用,需要用到宏:
该宏在include/linux/export.h里面。
既然模块间函数调用,我们要编写2个模块。
文件一:kernel_fun.h
1 2 3 4
| #ifndef KERNEL_FUN_H #define KERNEL_FUN_H void fun(void); #endif
|
文件二,要导出的模块文件:kernel_fun.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/export.h> #include "kernel_fun.h"
MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("yuuyuu"); MODULE_DESCRIPTION("kernel module hello"); MODULE_VERSION("1.0");
static int fun_init(void) { printk(KERN_ALERT "fun_init() start\n");
return 0; } void fun() { printk(KERN_ALERT "fun() is called\n"); }
static void fun_exit(void) { printk(KERN_ALERT "fun_exit() start\n"); }
module_init(fun_init); module_exit(fun_exit);
EXPORT_SYMBOL(fun);
|
最后一行就是导出到符号表。
文件三,要调用模块文件二的函数:kernel_mod.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/export.h> #include "kernel_fun.h"
MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("yuuyuu"); MODULE_DESCRIPTION("kernel module hello"); MODULE_VERSION("1.0");
static int mod_init(void) { printk(KERN_ALERT "mod_init() start\n");
fun(); return 0; }
static void mod_exit(void) { printk(KERN_ALERT "mod_exit() start\n"); }
module_init(mod_init); module_exit(mod_exit);
|
fun()即是调用其他模块的函数。
这里要编译2个模块,对应的Makefile文件:
1 2 3 4 5
| obj-m += kernel_mod.o kernel_fun.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
|
编译好这2个模块后,我们现在来验证。注意,因为kernel_mod依赖kernel_fun,所以我要先插入kernel_fun模块。
卸载模块的时候,我们要先卸载kernel_mod,原因同上。
依次插入kernel_fun,查看它的符号表,然后插入kernel_mod,查看dmesg:

可以看到kernel_fun的fun()被kernle_mod调用了。
延伸
How to export a struct between two kernel modules using EXPORT_SYMBOL or equivalent?
参考资料:
- 初探linux内核编程,参数传递以及模块间函数调用