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

这篇具有很好参考价值的文章主要介绍了2、Linux驱动开发:模块_引用符号。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

🍅点击这里查看所有博文

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

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

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

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

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

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

什么是符号?

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

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

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

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。

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导出的符号。

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。

#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引入外部的定义即可。

#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,操作正确的情况下,正常是不会有任何的错误和警告的。

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函数。

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

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

root@ubuntu:# rmmod ./helloa.ko
rmmod: ERROR: Module helloa is in use by: hellob
root@ubuntu:# rmmod ./hellob.ko
root@ubuntu:# rmmod ./helloa.ko

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

到了这里,关于2、Linux驱动开发:模块_引用符号的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux驱动开发一、RK3568把hello编译到Linux内核中运行。‘rk_vendor_read’未定义的引用

    1、在字符设备目录下建立hello目录 ~/Linux/rk356x_linux/kernel/drivers/char/hello 2、进入hello目录,新建hello.c、Makefile、Kconfig三个文件 3、Kconfig是打开make menuconfig配置界面是后的选项,这Kconfig是在字符设备下的。 config后面的HELLO就是对应配置后在kernel目录下的**.config中的CONFIG_HELLO配置

    2024年02月11日
    浏览(71)
  • 嵌入式linux驱动开发之移远4G模块EC800驱动移植指南

    回顾下移远4G模块移植过程, 还是蛮简单的。一通百通,无论是其他4G模块都是一样的。这里记录下过程,分享给有需要的人。环境使用正点原子的imax6ul开发板,板子默认支持中兴和移远EC20的驱动,这里要移植使用的是移远4G模块EC800。 imax6ul开发板 虚拟机(Ubuntu18.04) 交叉编译

    2024年02月17日
    浏览(71)
  • 嵌入式linux之iMX6ULL驱动开发 | 移远4G模块EC800驱动移植指南

    回顾下移远4G模块移植过程, 还是蛮简单的。一通百通,无论是其他4G模块都是一样的。这里记录下过程,分享给有需要的人。环境使用正点原子的imax6ul开发板,板子默认支持中兴和移远EC20的驱动,这里要移植使用的是移远4G模块EC800。 imax6ul开发板 虚拟机(Ubuntu18.04) 交叉编译

    2024年02月12日
    浏览(61)
  • Linux驱动3:驱动模块加载与卸载

    目录 一、环境配置  1、开发板环境 2、uboot环境 ①设置bootargs ②设置bootcmd 二、加载驱动与卸载驱动  1、加载命令选择 2、创建目录环境以及驱动文件复制 3、加载驱动  提示①“modprobe: can\\\'t open \\\'modules.dep\\\': No such file or directory”  提示②module license \\\'unspecified\\\' 4、卸载驱动 提示

    2024年02月05日
    浏览(58)
  • Linux下Node.js引用模块报错Error: Cannot find module

    背景:scrapyd上传的py文件,使用execjs调用Linux中的js文件,其中js引用了crypto-js,但是报错找不到这个模块(已安装) 2.1方法一 1, 执行命令 npm -g root ,查看全局安装的 Node.js 模块所在的路径 2, 将引用模块的路径改为绝对路径 const CryptoJS = require(“/usr/local/lib/node_modules/crypto-j

    2024年02月11日
    浏览(56)
  • Linux中驱动模块加载方法分析

    如何管理驱动模块 由于Linux驱动模块众多,系统对模块加载顺序有要求,一些基础模块在系统启动时需要很早就被加载;开发者加入自己的模块时,需要维护一个模块初始化列表,上面两方面的做起来很困难,为了科学地管理这些模块,首先要解决两个问题: 如何方便开发者

    2024年02月12日
    浏览(38)
  • 【Linux驱动】内核模块编译 —— make modules 的使用(单模块编译、多模块编译)

    编译驱动一般采用的是将驱动编译成模块(.ko 文件),然后加载到内核,这其中就用到了 make modules 命令。 目录 一、单模块编译 1、一个 c 文件编译成一个 ko 文件 2、多个文件编译成一个 ko 文件 二、多模块编译(多文件多模块) 下面是最简易的单文件单模块编译,假设我们

    2024年02月10日
    浏览(66)
  • Linux GPIO模块-RK3588 GPIO驱动分析

    GPIO是可编程的通用I/O外设。如下图所示,RK3588 GPIO控制器包含3个部分;APB接口模块和SoC内部的APB总线连接,负责与SoC交换数据,位宽为32位;I/O port接口模块管理外部的引脚,引脚的输入和输出都要经过该模块;中断探测模块负责GPIO控制器的中断上报与处理。 RK3588 GPIO控制器

    2023年04月15日
    浏览(41)
  • <Linux开发>驱动开发 -Linux MISC 驱动

    <Linux开发>驱动开发 -Linux MISC 驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分) <Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分) <Linux开发> -之

    2024年02月13日
    浏览(30)
  • <Linux开发>驱动开发 -之- Linux RTC 驱动

    <Linux开发>驱动开发 -之- Linux RTC 驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分) <Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分) <Linux开发>

    2024年02月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包