大家好,欢迎来到IT知识分享网。
定义
模块依赖是指A模块引用了B模块的函数或者全局变量,A模块就依赖于B模块,B模块就是被依赖的模块,加载模块时,需要先加载B模块,再加载A模块。另外A模块使用B模块的函数或者全局变量,需要在B模块中导出,否则A模块会编译出错,导出使用宏EXPORT_SYMBOL。
EXPORT_SYMBOL(函数名或者变量名) EXPORT_SYMBOL_GPL(函数名或者变量名) //只有license是GPL的能使用
示例代码:
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