【2】模块参数与模块之间的通信
模块参数
我们在运行用户空间的程序的时候可以接参数,驱动程序也可以接参数运行。参数在加载模块的时候指定,在模块代码中用module_param(参数名,参数类型,参数读写权限)来为模块定义参数。具体用法看代码如下:
#include <linux/init.h>
#include <linux/module.h>static char* str = "hello";
static int value = 1;static int hello_init(void) {printk(KERN_EMERG "hello_init str: %s\n", str);return 0;
}static void hello_exit(void) {printk(KERN_EMERG "hello_exit value: %d\n", value);
}module_param(value, int, 0644);
module_param(str, charp, 0644);module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");
上面的驱动在加载的时候就可以将a的值通过参数来指定,命令如下
sudo insmod hello.ko value=5 str="vegeta"
这样在加载模块时就会打印str=vegeta,卸载模块时打印value=5。
sysfs
sysfs是内核给资源创建的目录或者文件,模块会在/sys/module下创建一个跟模块名称一样的目录,目录在模块卸载的时候也会被一并删除掉。
例如上述hello模块加载之后,就会生成/sys/module/hello目录,在其中存放hello模块的资源信息。
上述模块传参中使用的str/value,会在/sys/module/hello/parameters目录下创建两个文件,跟参数名称一致
str和value中存放的的内容跟我们传参的内容是一致的
我所使用的版本,vim是可以修改value和str的内容的,并且是能生效的。例如当你修改了value之后,卸载模块打印的就是你修改之后的值了。
模块的文件格式
通过命令file hello.ko来查看模块是以何种格式存储在硬盘中。基本可以分为如下几个结构
名称 | 释义 |
---|---|
ELF Header | 描述整个文件的基本属性 |
.text | 代码段,存放文件的代码部分 |
.data | 数据段,存放已经初始化的数据等 |
.Section Table | 描述了ELF文件包含的所有段的信息 |
.symtab | 符号表,映射函数到真实内存地址的数据结构,就像一个字典,记录了在编译阶段无法确定地址的函数,在模块加载的时候由系统赋予真实的地址 |
模块通信(符号导出)
需要实现2个模块,目标是模块1(add_sub.ko)提供函数供模块2(hello.ko)来进行调用。
具体实现方式是将模块1的符号表提供给模块2,从而使得模块2能调用到模块1的函数和变量等。
模块(add_sub.ko)代码
/*模块1代码 add_sub.c,提供2个函数供其他模块调用*/
#include <linux/module.h>
#include <linux/init.h>int add_integer(int value1, int value2) {printk(KERN_EMERG "add_integer value1:%d value2:%d \n", value1, value2);return value1 + value2;
}int sub_integer(int value1, int value2) {printk(KERN_EMERG "sub_integer value1:%d value2:%d \n", value1, value2);return value1 - value2;
}static int add_sub_init(void) {return 0;
}static void add_sub_exit(void) {}EXPORT_SYMBOL(add_integer);
EXPORT_SYMBOL(sub_integer);module_init(add_sub_init);
module_exit(add_sub_exit);MODULE_LICENSE("GPL");
模块1提供了加和减(add_integer/sub_integer)2个函数,这2个函数需要导出到内核符号表,才能被其他模块调用。EXPORT_SYMBOL()就是导出宏,就是定义函数能够被其他模块调用到。要注意的是内核函数很多,不能出现重名。但是编译器认为所有模块的函数都是私有的,不同模块之间出现重名不影响编译,所以如果只是模块自己内部使用的话不需要担心重名问题。
模块2(hello.ko)代码
/*模块2代码 hello.c,调用模块1的函数*/
/*模块2代码 hello.c,调用模块1的函数*/
#include <linux/module.h>
#include <linux/init.h>static int value1 = 2;
static int value2 = 1;extern int add_integer(int value1, int value2);
extern int sub_integer(int value1, int value2);static int hello_init(void) {int result = add_integer(value1, value2); /*调用模块1的函数*/printk(KERN_EMERG "hello_init value1:%d value2:%d result: %d\n", value1, value2, result);return 0;
}static void hello_exit(void) {int result = sub_integer(value1, value2); /*调用模块1的函数*/printk(KERN_EMERG "hello_exit value1:%d value2:%d result: %d\n", value1, value2, result);
}module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");
模块2在加载的时候调用模块1的加法,卸载的时候调用模块2的减法。
模块通信的编译
add_sub模块的编译的Makefile与上一篇的hello world程序没有差异,直接可用。但是hello模块的Makefile需要修改一下,加上KBUILD_EXTRA_SYMBOLS
否则会报错找不到add_sub两个函数的实现。Makefile如下:
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
KBUILD_EXTRA_SYMBOLS += ./Modules.symvers
export KBUILD_EXTRA_SYMBOLSall:make -C $(KDIR) M=$(PWD) modules
clean:rm -rf *.o *~ codre .depend .*.cmd *.ko *.mod *.mod.c *.tmp_versions *.order *.symvers .cache.mk .tmp_versions
endif
编译的步骤为:
- 编译add_sub模块
- 将add_sub模块生成的Module.symvers复制到hello模块Makefile同级目录下
- 编译hello模块
模块通信测试
在加载的时候需要先加载add_sub.ko再加载hello.ko。在hello.ko加载的时候调用add_sub.ko中的加法,卸载的时候调用add_sub.ko中的减法。输出log如下
模块的加载过程解释
模块1(add_sub.ko)的加载过程:
1、内核为模块1分配空间,将模块的代码和数据装入分配的内存中
2、内核发现模块1的符号表中有函数可以导出,就将其内存地址记录在内核的符号表中
模块2(hello.ko)的加载过程:
1、内核为模块2分配空间,将模块的代码和数据装入分配的内存中
2、内核在模块2的符号表中发现一些未解析的函数。所以查找内核符号表找到对应的函数,将函数的地址填到模块2的符号表中,这个地址就是模块1中的函数地址。
通过上述的操作,就可以实现模块之间函数的调用
【2】模块参数与模块之间的通信相关推荐
- insmod module_param 模块参数
模块参数 引导模块时,可以向它传递参数.要使用模块参数加载模块,这样写: insmod module.ko [param1=value param2=value ...] 为了使用这些参数的值,要在模 ...
- HC-05(ZS-040)蓝牙模块使用详情(蓝牙模块配置、手机蓝牙控制单片机、蓝牙与蓝牙之间的通信)含51、32程序
HC-05是一款主从一体化的蓝牙模块,因此其使用起来比较方便,只需要进行简单的配置即可. 本文就手把手的介绍小白入手模块后如何使用. 对于模块使用:1.蓝牙配置→2.手机与蓝牙的传输→3.手机通过蓝牙 ...
- linux 内核空间 sy,在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysf...
级别: 初级 燚 杨 (), 计算机科学硕士 2006 年 2 月 16 日 本系列文章包括两篇,它们文详细地介绍了 Linux 系统下用户空间与内核空间数据交换的九种方式,包括内核启动参数.模块参数 ...
- Python命令行参数解析模块getopt使用实例
这篇文章主要介绍了Python命令行参数解析模块getopt使用实例,本文讲解了使用语法格式.短选项参数实例.长选项参数实例等内容,需要的朋友可以参考下 格式 getopt(args, options ...
- ESP8266调试-P2P(AP模块与STA模块通信)
ESP8266调试-P2P(AP模块与STA模块通信) ESP8266有三种模式可以选择,AP/STA/AP+STA, 下面我们要实现的是模块与模块之间点对点的通信 通信的三个过程 1. 建立WiFi ...
- python getopt使用_Python命令行参数解析模块getopt使用实例
这篇文章主要介绍了Python命令行参数解析模块getopt使用实例,本文讲解了使用语法格式.短选项参数实例.长选项参数实例等内容,需要的朋友可以参考下 格式 getopt(args, options ...
- 电平是什么?单片机的I/0口输入和输出,1和0是什么?什么是TTL电平?TTL电平分析?TTL、CMOS、RS232、RS485电平差异?usb转ttl?CH340模块驱动安装?电平之间的转换?
电平是什么 理想的数字电路电平是这样的: 输入小于1/2VCC(电源电压)就是低电平,反之是高电平.实际的器件是做不到的,也不实用,如果输入电压在1/2VCC附近有干扰,就会发生错误的输入信号.现在常 ...
- 简述GPRS模块和GSM模块之间的区别
GSM模块是将GSM射频芯片,基带处理芯片,存储器,放大器设备等集成在基板上的功能模块,以提供独立的OS,GSM射频处理,基带处理和标准接口. 简单来讲,GPRS无线模块就是将串口通讯转为GPRS无线 ...
- 三菱fx3u使用st语言adprw指令通过485-adp-mb模块与台达变频器进行通信
三菱fx3u使用st语言adprw指令通过485-adp-mb模块与台达变频器进行通信 作者:东莞市天翔环境工程有限公司,广东东极环保科技有限公司 使用ST语言作为PLC控制程序编写的通信方面的资料比 ...
最新文章
- 读取csv数据存到list,批量写入mysql
- AP付款出现(-1)例外处理
- 浅析IT软件项目团队人力资源管理
- 好程序员大数据点睛:关于HDFS的二三事
- Base64加密处理
- 蔚来汽车为国人长脸,牌照和品牌将是今后的两大重点
- java graham_Graham Scan凸包算法
- 在线就能用的 SQL 练习平台我给你找好了
- JAAS(Java 认证和授权服务)
- layui下select大数据卡顿问题
- Kotlin 动态代理的使用以及一些坑点
- 万字长文分析递归算法的时间和空间复杂度,从此对递归不再迷茫!
- 《大秦帝国之裂变》感悟与经典语录
- 为什么现在一些年轻人放弃缴纳社保?
- Unreal Engine 4 —— Smear Frame效果的实现与分析
- matlab之计算排列组合
- 微信jssdk图片上传给服务器,使用微信JSSDK进行图片选择和上传
- 【C++笔记】 判断两个数互质(做大公约数为1)
- 班级分组小程序-列表
- ADMET性质预测服务:药物分子吸收评估服务与药物分子毒性评估服务