在阅读本文之前,请阅读下linux kernel 模块化编程入门这篇文章。

模块的函数导出到符号表才可以供其他函数使用,需要用到宏:

1
EXPORT_SYMBOL(sym)

该宏在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"
/* 以下4个宏分别是许可证,作者,模块描述,模块版本 */
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"
/* 以下4个宏分别是许可证,作者,模块描述,模块版本 */
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 */
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?


参考资料:

  1. 初探linux内核编程,参数传递以及模块间函数调用