内核模块高级2-模块依赖

内核模块高级2-模块依赖定义 模块依赖是指 A 模块引用了 B 模块的函数或者全局变量 A 模块就依赖于 B 模块 B 模块就是被依赖的模块 加载模块时 需要先加载 B 模块 再加载 A 模块 另外 A 模块使用 B 模块的函数或者全局变量 需要在 B 模块中导出 否则 A 模块会编译出错 导出使用宏 E

大家好,欢迎来到IT知识分享网。

定义

模块依赖是指A模块引用了B模块的函数或者全局变量,A模块就依赖于B模块,B模块就是被依赖的模块,加载模块时,需要先加载B模块,再加载A模块。另外A模块使用B模块的函数或者全局变量,需要在B模块中导出,否则A模块会编译出错,导出使用宏EXPORT_SYMBOL。

EXPORT_SYMBOL(函数名或者变量名)  EXPORT_SYMBOL_GPL(函数名或者变量名)  //只有license是GPL的能使用

内核模块高级2-模块依赖

示例代码:

modA.c

#include <linux/init.h> #include <linux/module.h> extern void modB_fun(void); static int hello_init(void) {     printk("Hello A World.\n");         modB_fun();//调用模块B中的函数,实现在modB.c     return 0; } static void hello_exit(void) {      printk("Goodbye A World.\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ono Zhang"); MODULE_DESCRIPTION("A simple Hello World Module");

modB.c

#include <linux/init.h> #include <linux/module.h> void modB_fun(void)  {     printk("In modB World.\n"); } EXPORT_SYMBOL(modB_fun);//导出函数符号 static int hello_init(void) {     printk("Hello B World.\n");         modB_fun();         return 0; } static void hello_exit(void) {      printk("Goodbye B World.\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ono Zhang"); MODULE_DESCRIPTION("A simple Hello World Module");

Makefile

obj-m = modA.o modB.o KER_DIR=/home/linux-kernel modules:     make -C $(KER_DIR) M=$(shell pwd) modules clean:     make -C $(KER_DIR) M=$(shell pwd) clean

KDIR是内核源码路径

也可以写成

obj-m = modA.o  obj-m += modB.o KER_DIR=/home/linux-kernel modules:     make -C $(KER_DIR) M=$(shell pwd) modules clean:     make -C $(KER_DIR) M=$(shell pwd) clean

加载

编译后加载,若先加载模块A,会出现如下的错误:

$sudo insmod modA.ko insmod: ERROR: could not insert module modA.ko: Unknown symbol in module

正确的加载方法有两种:

方式1:先加载模块B,再加载模块A,如下:

nbsp;sudo insmod modB.ko  nbsp;sudo insmod modA.ko  nbsp;dmesg ... [ 1369.] Hello B World. [ 1369.] In modB World. [ 1372.] Hello A World. [ 1372.] In modB World.

备注:dmesg是查看日志的命令

方式2:使用modprobe命令,但使用前注意:

1)需要把模块文件modA.ko、modB.ko拷贝到/lib/modules/内核版本号/目录中

比如使用/lib/modules/5.15.0-116-generic

2)拷贝文件后,使用depmod命令在/lib/modules/版本号/modules.dep文件中生成对应模块的依赖函数

$sudo cp modA.ko modB.ko /lib/modules/5.15.0-116-generic/$sudo depmod$cat /lib/modules/5.15.0-116-generic/modules.dep | grep modB.ko modA.ko: modB.ko modB.ko:$sudo modprobe modA$dmesg... [ 1859.] Hello B World. [ 1859.] In modB World. [ 1859.] Hello A World. [ 1859.] In modB World.

depmod会把模块A依赖的模块B和模块A一起加载起来。

另外卸载时,也需要注意顺序,先卸载模块A,后卸载模块B,否则会出现以下错误:

nbsp;rmmod modB.ko rmmod: ERROR: Module modB is in use by: modA nbsp;modprobe -r modB modprobe: FATAL: Module modB is in use.

若使用modprobe -r modA,会把模块B一起卸载掉。

$sudo modprobe -r modA$dmesg... [ 2421.] Goodbye A World. [ 2421.] Goodbye B World.

编译注意

模块A和模块B若不在同一个目录,不一起编译,编译模块A时会报编译错误

nbsp;make make -C /lib/modules/5.15.0-116-generic/build M=/home/hqyj/1101 modules make[1]: 进入目录“/usr/src/linux-headers-5.15.0-116-generic”   CC [M]  /home/hqyj/1101/modA.o   MODPOST /home/hqyj/1101/Module.symvers ERROR: modpost: "modB_fun" [/home/hqyj/1101/modA.ko] undefined! make[2]: * [scripts/Makefile.modpost:133:/home/hqyj/1101/Module.symvers] 错误 1 make[2]: * 正在删除文件“/home/hqyj/1101/Module.symvers” make[1]: * [Makefile:1830:modules] 错误 2 make[1]: 离开目录“/usr/src/linux-headers-5.15.0-116-generic” make: * [Makefile:5:modules] 错误 2

解决办法有2种:

1、模块B编译出来的Modules.symvers文件拷贝到模块A所在的目录编译

2、在模块A的Makefile里面添加 KBUILD_EXTRA_SYMBOLS=/模块B目录/Module.symvers

obj-m = modA.o   KER_DIR=/home/linux-kernel#modB的目录里面有Module.symvers,需要先编译模块BKBUILD_EXTRA_SYMBOLS=modB/Module.symvers modules:     make -C $(KER_DIR) M=$(shell pwd) modules clean:     make -C $(KER_DIR) M=$(shell pwd) clean

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/177309.html

(0)
上一篇 2025-04-27 07:00
下一篇 2025-04-27 07:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信