1. 概述
Linux 的进程有自己的用户空间,使用自己的虚拟内存空间,因此进程之间无法调用彼此的函数
而 Linux 的模块都加载在内核空间,共享内存,因此可以从一个模块访问另一个模块的资源,而这需要符号表的导出与导入
2. API
EXPORT_SYMBOL(变量名|函数名) 或者 EXPORT_SYMBOL_GPL(变量名|函数名)
3. 导出实例
. ├── 1 │ ├── demo1.c │ └── Makefile └── 2 ├── demo2.c └── Makefil
Makefile 使用 Linux 内核模块编程 第 4.2 节的架构通用 Makefile
// demo1.c #include <linux/init.h> #include <linux/module.h> // 定义函数 int add(int i, int j) { return i + j; } static int __init mycdev_init(void) { return 0; } // 声明导出当前函数的符号表 EXPORT_SYMBOL(add); static void __exit mycdev_exit(void) {} module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL")
// demo2.c #include <linux/init.h> #include <linux/module.h> extern int add(int i, int j); static int __init mycdev_init(void) { printk("add(3, 4) = %d\n", add(3, 4)); return 0; } static void __exit mycdev_exit(void) {} module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL")
在 1 目录下编译
make arch=x86 modname=demo1
,生成 Module.symvers
,将其拷贝到 2 目录下,make arch=x86 modname=demo2
进行编译。版本较新的 Linux 内核不再支持这种编译方式,需要修改 Makefile,在 2 目录下的 Makefile 中添加变量
KBUILD_EXTRA_SYMBOLS+=$(shell pwd)/../1/Module.symvers
,且不再需要拷贝符号表文件。编译完成的
demo2.ko
可以通过 modinfo
查看到它的依赖模块:filename: /sys_import/2/demo2.ko license: GPL srcversion: 160996D8382541A4A59A2DE depends: demo1 retpoline: Y name: demo2 vermagic: 6.2.0-24-generic SMP preempt mod_unload modversions
通过按顺序加载
insmod demo1.ko
和 insmod demo2.ko
,可以在 dmesg
中查看到输出结果:[38917.418050] add(3, 4) = 7
卸载模块时,需要先卸载
demo2
再卸载 demo1