2、Linux驱动开发:模块_引用符号

目录

🍅点击这里查看所有博文

随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有一点用处的技巧,用的不多的技巧可能一个星期就忘了。

想了很久想通过一些手段把这些事情记录下来。也尝试过在书上记笔记,这也只是一时的,书不在手边的时候那些笔记就和没记一样,不是很方便。

很多时候我们遇到了问题,一般情况下都是选择在搜索引擎检索相关内容,这样来的也更快一点,除非真的找不到才会去选择翻书。后来就想到了写博客,博客作为自己的一个笔记平台倒是挺合适的。随时可以查阅,不用随身携带。

同时由于写博客是对外的,既然是对外的就不能随便写,任何人都可以看到。经验对于我来说那就只是经验而已,公布出来说不一定我的一些经验可以帮助到其他的人。遇到和我相同问题时可以少走一些弯路。

既然决定了要写博客,那就只能认真去写。不管写的好不好,尽力就行。千里之行始于足下,一步一个脚印,慢慢来 ,写的多了慢慢也会变好的。权当是记录自己的成长的一个过程,等到以后再往回看时,就会发现自己以前原来这么菜😂。

本系列博客所述资料均来自互联网资料,并不是本人原创(只有博客是自己写的)。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。

什么是符号?

这里的符号主要指的是全局变量和函数

Linux内核采用的是以模块化形式管理内核代码。内核中的每个模块相互之间是相互独立的,也就是说A模块的全局变量和函数,B模块是无法访问的。

不同模块间可通过导出宏,将符号导出,被导出的符号可被其他模块使用。

c 复制代码
static int num = 100;
static void show(void)
{
	printk("aaaa:  num =%d \n",num);
}
EXPORT_SYMBOL(num);
EXPORT_SYMBOL(show);

Ubuntu中的符号表

Linux内核的全局符号表在/usr/src/linux-headers-xxxxx-generic/Module.symvers。

shell 复制代码
root@ubuntu:# ls /usr/src/linux-headers-4.15.0-142-generic/
arch   crypto         firmware  init    Kconfig  Makefile        net      security  ubuntu
block  Documentation  fs        ipc     kernel   mm              samples  sound     usr
certs  drivers        include   Kbuild  lib      Module.symvers  scripts  tools     virt

某个单独编译的内核符号表在代码根目录下。在模块编译好后,在它的当前目录会看到一个Module.symvers文件,这里存放的就是我们模块A导出的符号。

shell 复制代码
root@ubuntu:# ls
helloa.c   helloa.mod.c  helloa.o  modules.order
helloa.ko  helloa.mod.o  Makefile  Module.symvers

示例源码

模块A的示例源码,在模块A中使用EXPORT_SYMBOL导出整型变量num和void型函数show。

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PD");
static int num = 100;
static void show(void)
{
	printk("helloa_show num =%d \n",num);
}
static int hello_init(void)
{
	printk("helloa_init \n");
	return 0;
}
static void hello_exit(void)
{
	printk("helloa_exit \n");
	return;
}
EXPORT_SYMBOL(num);
EXPORT_SYMBOL(show);
module_init(hello_init);
module_exit(hello_exit);

在模块B中直接使用extern引入外部的定义即可。

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PD");
extern int num;
extern  void show(void);
static int hello_init(void)
{
	printk("hellob_init %d\n",num);
	show();
	return 0;
}
static void hello_exit(void)
{
	printk("hellob_exit \n");
	return;
}
module_init(hello_init);
module_exit(hello_exit);

引用步骤

编译模块A,将模块A编译生成的Module.symvers文件拷贝到模块 B目录下(可选),不拷贝的话,在编译B时也只是会报一个警告,不影响使用。建议拷贝,程序员不能忽视任何一个警告才是对的。

WARNING: "show" [/home/peng/Desktop/driver/example/2_export/b/hellob.ko] undefined!
WARNING: "num" [/home/peng/Desktop/driver/example/2_export/b/hellob.ko] undefined!

编译模块B,操作正确的情况下,正常是不会有任何的错误和警告的。

shell 复制代码
root@ubuntu:# make
make -C /lib/modules/4.15.0-142-generic/build M=/home/peng/Desktop/driver/example/2_export/b modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
  CC [M]  /home/peng/Desktop/driver/example/2_export/b/hellob.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "show" [/home/peng/Desktop/driver/example/2_export/b/hellob.ko] undefined!
WARNING: "num" [/home/peng/Desktop/driver/example/2_export/b/hellob.ko] undefined!
  CC      /home/peng/Desktop/driver/example/2_export/b/hellob.mod.o
  LD [M]  /home/peng/Desktop/driver/example/2_export/b/hellob.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'

先加载模块A,然后加载模块B。从日志中分析可知在加载模块A时,先执行了helloa的加载函数。加载模块B的过程中执行模块B加载函数时,首先引用了模块a的变量num,紧接着又调用了模块A中show函数。

shell 复制代码
root@ubuntu:# insmod ./helloa.ko
root@ubuntu:# insmod ./hellob.ko
root@ubuntu:# dmesg
[ 8167.354563] helloa_init 
[ 8170.907883] hellob_init 100
[ 8170.907884] helloa_show num =100

注意事项

加载的时候,必须先加载A模块,再加载B模块。否则会报错Unknown symbol in module

shell 复制代码
root@ubuntu:# insmod ./hellob.ko
insmod: ERROR: could not insert module ./hellob.ko: Unknown symbol in module
root@ubuntu:# insmod ./helloa.ko
root@ubuntu:# insmod ./hellob.ko

卸载的时候,必须先卸载B模块,再卸载A模块。否则会报错Module helloa is in use by

shell 复制代码
root@ubuntu:# rmmod ./helloa.ko
rmmod: ERROR: Module helloa is in use by: hellob
root@ubuntu:# rmmod ./hellob.ko
root@ubuntu:# rmmod ./helloa.ko

那么本篇博客就到此结束了,这里只是记录了一些我个人的学习笔记,其中存在大量我自己的理解。文中所述不一定是完全正确的,可能有的地方我自己也理解错了。如果有些错的地方,欢迎大家批评指正。如有问题直接在对应的博客评论区指出即可,不需要私聊我。我们交流的内容留下来也有助于其他人查看,说不一定也有其他人遇到了同样的问题呢😂。

相关推荐
小安运维日记1 小时前
Linux云计算 |【第四阶段】NOSQL-DAY1
linux·运维·redis·sql·云计算·nosql
CoolTiger、5 小时前
【Vmware16安装教程】
linux·虚拟机·vmware16
学习3人组6 小时前
CentOS 中配置 OpenJDK以及多版本管理
linux·运维·centos
厨 神6 小时前
vmware中的ubuntu系统扩容分区
linux·运维·ubuntu
Karoku0666 小时前
【网站架构部署与优化】web服务与http协议
linux·运维·服务器·数据库·http·架构
geek_Chen016 小时前
虚拟机共享文件夹开启后mnt/hgfs/下无sharefiles? --已解决
linux·运维·服务器
(⊙o⊙)~哦7 小时前
linux 解压缩
linux·运维·服务器
牧小七8 小时前
Linux命令---查看端口是否被占用
linux
鸡鸭扣9 小时前
虚拟机:3、(待更)WSL2安装Ubuntu系统+实现GPU直通
linux·运维·ubuntu
友友马9 小时前
『 Linux 』HTTP(一)
linux·运维·服务器·网络·c++·tcp/ip·http