Linux 内核导出符号表

Last edited
Last updated July 5, 2023
Pages
Tags

1. 概述

Linux 的进程有自己的用户空间,使用自己的虚拟内存空间,因此进程之间无法调用彼此的函数
 
notion image
而 Linux 的模块都加载在内核空间,共享内存,因此可以从一个模块访问另一个模块的资源,而这需要符号表的导出与导入
 
notion image

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.koinsmod demo2.ko ,可以在 dmesg 中查看到输出结果:
[38917.418050] add(3, 4) = 7
卸载模块时,需要先卸载 demo2 再卸载 demo1