内核模块(传参和依赖)

news2024/10/6 22:27:44

目录

一、模块传参

二、模块依赖

三、内核空间和用户空间

四、执行流

五、模块编程与应用编程的比较

六、内核接口头文件查询

七、小作业


一、模块传参

module_param(name,type,perm);//将指定的全局变量设置成模块参数

name:全局变量名

type:

    使用符号      实际类型                传参方式

    bool         bool           insmod xxx.ko  变量名=0 或 1

    invbool      bool           insmod xxx.ko  变量名=0 或 1

    charp        char *         insmod xxx.ko  变量名="字符串内容"

    short        short          insmod xxx.ko  变量名=数值

    int          int            insmod xxx.ko  变量名=数值

    long         long           insmod xxx.ko  变量名=数值

    ushort       unsigned short insmod xxx.ko  变量名=数值

    uint         unsigned int   insmod xxx.ko  变量名=数值

    ulong        unsigned long  insmod xxx.ko  变量名=数值

perm:给对应文件 /sys/module/name/parameters/变量名 指定操作权限

(这个name是全局变量名)

    #define S_IRWXU 00700

    #define S_IRUSR 00400

    #define S_IWUSR 00200

    #define S_IXUSR 00100

    #define S_IRWXG 00070

    #define S_IRGRP 00040

    #define S_IWGRP 00020

    #define S_IXGRP 00010

    #define S_IRWXO 00007

    #define S_IROTH 00004

    #define S_IWOTH 00002  //不要用 编译出错

    #define S_IXOTH 00001

(这个文件一般设置成0664.就是perm的位置写0664。忘记什么意思的同学可以看下面同学发的。感觉挺全的)

【Linux】文件的权限_linux文件权限_爽帅_的博客-CSDN博客

module_param_array(name,type,&num,perm);

name、type、perm同module_param,type指数组中元素的类型

&num:存放数组大小变量的地址,可以填NULL(确保传参个数不越界)

    传参方式 insmod xxx.ko  数组名=元素值0,元素值1,...元素值num-1  


 

 

用上面命令可以替换字符串

printk和printf差不多但是不支持浮点型打印

下面就是更改完的程序

#include <linux/module.h>
#include <linux/kernel.h>

int gx = 10;
char *gstr = "hello";
int garr[5] = {1,2,3,4,5};

module_param(gx, int, 0664);
module_param(gstr, charp, 0664);
module_param_array(garr, int, NULL, 0664);

int __init testparam_init(void)
{
	int i = 0;

	printk("gx = %d\n", gx);
	printk("gst = %s\n", gstr);

	for(i = 0;i < 5;i++)
	{
		printk("%d ", garr[i]);
	}
	printk("\n");
	return 0;
}
void __exit testparam_exit(void)
{
	printk("testparam will exit\n");
}
MODULE_LICENSE("GPL");
module_init(testparam_init);
module_exit(testparam_exit);

 在makefile里加上我们新的模块

 执行make编译

sudo insmod testparam.ko

dmesg 

 

sudo rmmod testparam 

sudo dmesg -C
sudo insmod testparam.ko gx=100 gstr="hi" garr=5,6,7,8,9

dmesg

 

可用MODULE_PARAM_DESC宏对每个参数进行作用描述,用法:

`MODULE_PARM_DESC(变量名,字符串常量);`

字符串常量的内容用来描述对应参数的作用

modinfo可查看这些参数的描述信息

二、模块依赖

​       既然内核模块的代码与其它内核代码共用统一的运行环境,也就是说模块只是存在形式上独立,运行上其实和内核其它源码是一个整体,它们隶属于同一个程序,因此一个模块或内核其它部分源码应该可以使用另一个模块的一些全局特性。

        一个模块中这些可以被其它地方使用的名称被称为导出符号,所有导出符号被填在同一个表中这个表被称为符号表。

最常用的可导出全局特性为全局变量函数  

查看符号表的命令:nm

nm查看elf格式的可执行文件或目标文件中包含的符号表,用法:

`nm  文件名`  (可以通过man nm查看一些字母含义)

 (.o和.ko也是elf格式的文件)

第一列是相对地址

D表示全局变量

T一般指函数

B未初始化的全局变量或静态局部变量

R加了const的全局变量

上面比较常用,下面是man nm查到的全部含义


           "A" The symbol's value is absolute, and will not be changed by further linking.

           "B"
           "b" The symbol is in the BSS data section.  This section typically contains zero-
               initialized or uninitialized data, although the exact behavior is system
               dependent.

           "C" The symbol is common.  Common symbols are uninitialized data.  When linking,
               multiple common symbols may appear with the same name.  If the symbol is
               defined anywhere, the common symbols are treated as undefined references.

           "D"
           "d" The symbol is in the initialized data section.

           "G"
           "g" The symbol is in an initialized data section for small objects.  Some object
               file formats permit more efficient access to small data objects, such as a
               global int variable as opposed to a large global array.

           "i" For PE format files this indicates that the symbol is in a section specific to
               the implementation of DLLs.  For ELF format files this indicates that the
               symbol is an indirect function.  This is a GNU extension to the standard set of
               ELF symbol types.  It indicates a symbol which if referenced by a relocation
               does not evaluate to its address, but instead must be invoked at runtime.  The
               runtime execution will then return the value to be used in the relocation.

           "I" The symbol is an indirect reference to another symbol.

           "N" The symbol is a debugging symbol.

           "p" The symbols is in a stack unwind section.

           "R"
           "r" The symbol is in a read only data section.

           "S"
           "s" The symbol is in an uninitialized or zero-initialized data section for small
               objects.

           "T"
           "t" The symbol is in the text (code) section.

           "U" The symbol is undefined.

           "u" The symbol is a unique global symbol.  This is a GNU extension to the standard
               set of ELF symbol bindings.  For such a symbol the dynamic linker will make
               sure that in the entire process there is just one symbol with this name and
               type in use.

           "V"
           "v" The symbol is a weak object.  When a weak defined symbol is linked with a
               normal defined symbol, the normal defined symbol is used with no error.  When a
               weak undefined symbol is linked and the symbol is not defined, the value of the
               weak symbol becomes zero with no error.  On some systems, uppercase indicates
               that a default value has been specified.

           "W"
           "w" The symbol is a weak symbol that has not been specifically tagged as a weak
               object symbol.  When a weak defined symbol is linked with a normal defined
               symbol, the normal defined symbol is used with no error.  When a weak undefined
               symbol is linked and the symbol is not defined, the value of the symbol is
               determined in a system-specific manner without error.  On some systems,
               uppercase indicates that a default value has been specified.

           "-" The symbol is a stabs symbol in an a.out object file.  In this case, the next
               values printed are the stabs other field, the stabs desc field, and the stab
               type.  Stabs symbols are used to hold debugging information.

           "?" The symbol type is unknown, or object file format specific.

       ·   The symbol name.

 

两个用于导出模块中符号名称的宏:

EXPORT_SYMBOL(函数名或全局变量名)

EXPORT_SYMBOL_GPL(函数名或全局变量名)   需要GPL许可证协议验证

使用导出符号的地方,需要对这些符号进行extern声明后才能使用这些符号

B模块使用了A模块导出的符号,此时称B模块依赖于A模块,则:

1. 编译次序:先编译模块A,再编译模块B,当两个模块源码在不同目录时,需要:i. 先编译导出符号的模块A ii. 拷贝A模块目录中的Module.symvers到B模块目录 iii. 编译使用符号的模块B。否则编译B模块时有符号未定义错误

2. 加载次序:先插入A模块,再插入B模块,否则B模块插入失败

3. 卸载次序:先卸载B模块,在卸载A模块,否则A模块卸载失败

 

#include <linux/module.h>
#include <linux/kernel.h>

int gx = 19;

EXPORT_SYMBOL(gx);

int __init modulea_init(void)
{
	printk("In module_a init gx = %d\n", gx);
	return 0;
}
void __exit modulea_exit(void)
{
	printk("modulea will exit\n");
}
MODULE_LICENSE("GPL");

module_init(modulea_init);
module_exit(modulea_exit);

 

#include <linux/module.h>
#include <linux/kernel.h>

extern int gx;

int __init moduleb_init(void)
{
	printk("In module_b init gx = %d\n", gx);
	return 0;
}
void __exit moduleb_exit(void)
{
	printk("moduleb will exit\n");
}
MODULE_LICENSE("GPL");

module_init(moduleb_init);
module_exit(moduleb_exit);

 一定要先编译提供方在编译使用方

如果先插入B会报错

 

先插入a在插入b就没错

dmesg

 这里有之前插入出错的信息

先移除modulea会出错提示modulea正在被moduleb使用

这样就成功了

 如果这两个模块在两个目录下

进入a目录更改makefile然后make编译成功

 

 

 但是在b中就会失败,因为他缺少a中的全局变量

 Linux内核中模块的编译一般分为以下步骤:

  • 将每个源文件编译为对应的.o目标文件
  • 将每个单独的目标文件链接成模块文件module.o
  • 生成对应的module.mod文件,该文件保存链接到模块的所有原始 .o目标文件
  • 生成modules.order文件,里面保存的是所有的KO文件
  • 从modules.order中查找所有的KO模块
  • 使用modpost,为每个KO模块创建module.mod.c文件
  • 创建Module.symvers文件,保存模块中通过export导出的符号及其CRC值
  • 生成和模块相关的信息(版本魔幻数、模块信息、License、version、alias)
  • 外部模块的版本验证
  • 通过module.symvers文件,检测模块编译需要的内核符号是否存在

 所以我们把符号表粘过去就能正确编译了

补充说明:

内核符号表(直接当文本文件查看)

   /proc/kallsyms运行时    /boot/System.map编译后

这台虚拟机可能是升级过有五个版本的符号表

 

 在内核的源码里可以直接用nm命令查看vmLinux

 非常的多

也可查看

这里就是符号表,可以在这里查看全部的全局特性

 

三、内核空间和用户空间

        为了彻底解决一个应用程序出错不影响系统和其它app的运行,操作系统给每个app一个独立的假想的地址空间,这个假想的地址空间被称为虚拟地址空间(也叫逻辑地址),操作系统也占用其中固定的一部分,32位Linux的虚拟地址空间大小为4G,并将其划分两部分:

1. 0~3G 用户空间 :每个应用程序只能使用自己的这份虚拟地址空间

2. 3G~4G 内核空间:内核使用的虚拟地址空间,应用程序不能直接使用这份地址空间,但可以通过一些系统调用函数与其中的某些空间进行数据通信

实际内存操作时,需要将虚拟地址映射到实际内存的物理地址,然后才进行实际的内存读写

百度百科-验证

内核启动时。在MMU以前使用的都是真实的物理地址。启动后使用的是虚拟地址(3G~4G)

这些虚拟内存都和实际的物理内存有对应关系。

后面驱动操作内核所以使用的也是3G~4G的虚拟内存

四、执行流

执行流:有开始有结束总体顺序执行的一段独立代码,又被称为代码上下文

计算机系统中的执行流的分类:

执行流:

1. 任务流--任务上下文(都参与CPU时间片轮转,都有任务五状态:就绪态  运行态  睡眠态  僵死态  暂停态)

   1.  进程

   2.  线程

       1.  内核线程:内核创建的线程

       2.  应用线程:应用进程创建的线程

(进程线程都是任务,进程是资源占用多的任务。线程是资源占用少的任务) 

2. 异常流--异常上下文

   1. 中断

   2. 其它异常

 (任务流的优先级高于异常流,执行时整个时间轮转都会暂停。所以这个程序不能写的太占用时间。要不给用户的感觉会很不好)

应用编程可能涉及到的执行流:

1. 进程

2. 线程    

 

内核编程可能涉及到的执行流:  

1. 应用程序自身代码运行在用户空间,处于用户态   -----------------  用户态app

2. 应用程序正在调用系统调用函数,运行在内核空间,处于内核态,即代码是内核代码但处于应用执行流(即属于一个应用进程或应用线程) ----  内核态app

3. 一直运行于内核空间,处于内核态,属于内核内的任务上下文 --------- 内核线程

4. 一直运行于内核空间,处于内核态,专门用来处理各种异常 --------- 异常上下文

(当在用户APP中调用了系统函数时。在执行到这个函数时会跳转到内核执行。完了再回来继续执行。虽然使用到了内核空间。但是他还是有个执行流。)

五、模块编程与应用编程的比较

| 不同点                       |                内核模块                                     | 应用程序       |

| API来源  |               不能使用任何库函数                      |    各种库函数均可以使用             |

| 运行空间 |             内核空间                        | 用户空间                             |

| 运行权限 |              特权模式运行                                 | 非特权模式运行                       |

| 编译方式 | 静态编译进内核镜像或编译特殊的ko文件       | elf格式的应用程序可执行文件  |

| 运行方式 | 模块中的函数在需要时被动调用                 | 从main开始顺序执行                   |

| 入口函数 | init_module                                  | main                                 |

| 退出方式 |          cleanup_module                     | main函数返回或调用exit               |

| 浮点支持 | 一般不涉及浮点运算,因此printk不支持浮点数据 | 支持浮点运算,printf可以打印浮点数据 |

| 并发考虑 | 需要考虑多种执行流并发的竞态情况             | 只需考虑多任务并行的竞态     |

| 程序出错 | 可能会导致整个系统崩溃                       | 只会让自己崩溃                       |

六、内核接口头文件查询

大部分API函数包含的头文件在include/linux目录下,因此:

1. 首先在include/linux 查询指定函数:grep  名称  ./   -r   -n

2. 找不到则更大范围的include目录下查询,命令同上

 

 

七、小作业

 编写3个内核模块A、B、C,A依赖于B,B依赖于C,完成对它们的编译、运行、卸载

 

 这个写错了,最后一个应该是a

 

有点小瑕疵打印没改

 

 

#include <linux/module.h>
#include <linux/kernel.h>

extern char char_a;


int __init modulea_init(void)
{
	printk("In module_a init char = %c\n", char_a);
	return 0;
}
void __exit modulea_exit(void)
{
	printk("modulea will exit\n");
}
MODULE_LICENSE("GPL");

module_init(modulea_init);
module_exit(modulea_exit);
#include <linux/module.h>
#include <linux/kernel.h>

extern char char_b;
char char_a = 'a';

EXPORT_SYMBOL(char_a);

int __init moduleb_init(void)
{
	printk("In module_b init char = %c\n", char_b);
	return 0;
}
void __exit moduleb_exit(void)
{
	printk("moduleb will exit\n");
}
MODULE_LICENSE("GPL");

module_init(moduleb_init);
module_exit(moduleb_exit);
#include <linux/module.h>
#include <linux/kernel.h>

char char_c = 'c';
char char_b = 'b';
EXPORT_SYMBOL(char_b);

int __init modulec_init(void)
{
	printk("In module_a init char = %c\n", char_c);
	return 0;
}
void __exit modulec_exit(void)
{
	printk("modulec will exit\n");
}
MODULE_LICENSE("GPL");

module_init(modulec_init);
module_exit(modulec_exit);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/350437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MFC消息机制

1.消息映射消息映射是一个将消息和成员函数相互关联的表。比如&#xff0c;框架窗口接收到一个鼠标左击消息&#xff0c;MFC将搜索该窗口的消息映射&#xff0c;如果存在一个处理WM_LBUTTTONDOWN消息的处理程序&#xff0c;然后就调用OnButtonDown。2.消息映射机制2.1 声明宏 写…

教务查询系统简介

教务查询系统简介 项目核心代码展示 service层如下&#xff1a; Teacher老师Service层&#xff1a; public interface TeacherService {//根据id更新老师信息void updateById(Integer id, TeacherCustom teacherCustom) throws Exception;//根据id删除老师信息void removeB…

SheetJS的通用电子表格对象简介和使用

简言 “通用电子表格格式”&#xff08;CSF&#xff09;是SheetJS使用的对象模型。 例如使用xlsx插件时&#xff0c;获得的excel文件数据对象就是依据这个模型设计的。 SheetJs通用电子表格对象 介绍 cdn导入&#xff1a; <script lang"javascript" src"ht…

uprobe 实战

观测数据源 目前按照我的理解&#xff0c;和trace相关的常用数据源–探针 大致分为四类。 内核 Trace point kprobe 用户程序 USDT uprobe 在用户程序中&#xff0c;USDT是所谓的静态Tracepoint。和内核代码中的Trace point类似。实现方式是在代码开发时&#xff0c;使用USDT…

Visual Studio开启clang-tidy代码检查

在CLion中有针对C的静态代码检查工具clang-tidy&#xff0c;感觉非常好用&#xff0c;能养成好的编码习惯&#xff0c;后来写Qt转入了VS平台&#xff0c;想要继续使用功能一致的clang-tidy体验&#xff0c;所以研究出来在VS中开启clang-tidy的方法。 版本&#xff1a;Visual S…

XML 基础知识 XXE 漏洞原理解析及实验(基础篇)

XML 介绍 XXE全称XML外部实体注入&#xff0c;所以在介绍XXE漏洞之前&#xff0c;先来说一说什么是XML以及为什么使用XML进而再介绍一下XML的结构。 XML全称 可拓展标记语言&#xff0c;与HTML相互配合后&#xff1a; HMTL用来显示数据 HTML的焦点在于数据的外观&#xff08;…

双网卡(有线和wifi)同时连接内网和外网

双网卡&#xff08;有线和wifi&#xff09;同时连接内网和外网 Win10技巧&#xff1a;如何修改有线/WiFi网络优先级&#xff1a;https://www.ithome.com/html/win10/253612.htm双网卡实现两个网络的自由访问&#xff1a;https://blog.51cto.com/ghostlan/1299090Linux服务器安…

【Linux】网络编程 - 基础概念

目录 一.OSI七层模型vsTCP/IP五层模型 1.一些周边概念 2.OSI七层模型 3.TCP/IP五层模型 4.网络传输流程图 二.什么是MAC地址 三.什么是IP/IP地址 1.什么是IP 2.什么是IP地址 四.什么是端口号 一.OSI七层模型vsTCP/IP五层模型 1.一些周边概念 局域网vs广域网 网络互…

LeetCode——2341. 数组能形成多少数对

一、题目 给你一个下标从 0 开始的整数数组 nums 。在一步操作中&#xff0c;你可以执行以下步骤&#xff1a; 从 nums 选出 两个 相等的 整数 从 nums 中移除这两个整数&#xff0c;形成一个 数对 请你在 nums 上多次执行此操作直到无法继续执行。 返回一个下标从 0 开始、…

亚马逊云科技重磅发布《亚马逊云科技汽车行业解决方案》

当今&#xff0c;随着万物智联、云计算等领域的高速发展&#xff0c;创新智能网联汽车和车路协同技术正在成为车企加速发展的关键途径&#xff0c;推动着汽车产品从出行代步工具向着“超级智能移动终端”快速转变。挑战无处不在&#xff0c;如何抢先预判&#xff1f;随着近年来…

31-Golang中的二维数组

二维数组的使用方式 使用方式一&#xff1a;先声明/定义再赋值 1.语法&#xff1a;var数组名 [大小] [大小]类型2.比如&#xff1a;var arr [2] [3]int,再赋值 package main import ("fmt" )func main() {//定义/声明数组var arr [4][6]int//赋初值arr[1][2] 1ar…

volatile,内存屏障

volatile的特性可见性: 对于其他线程是可见,假设线程1修改了volatile修饰的变量,那么线程2是可见的,并且是线程安全的重排序: 由于CPU执行的时候,指令在后面的会先执行,在指令层级的时候我们晓得volatile的特性后,我们就要去volatile是如何实现的,这个很重要&#xff01;&#…

金三银四面试必备的软件测试八股文,看完拿捏面试官

1、问&#xff1a;你在测试中发现了一个 bug&#xff0c;但是开发经理认为这不是一个 bug&#xff0c;你应该怎样解决&#xff1f;首先&#xff0c;将问题提交到缺陷管理库里面进行备案。然后&#xff0c;要获取判断的依据和标准&#xff1a; 根据需求说明书、产品说明、设计文…

蓝屏怎么办电脑蓝屏怎么办?蓝屏问题详细分析

蓝屏怎么办电脑蓝屏怎么办&#xff1f;最近很多小伙伴在咨询这个问题&#xff0c;其实电脑蓝屏了进不去&#xff0c;我们可以重新启动电脑&#xff0c;如果进入系统后还是直接蓝屏&#xff0c;那么你可以尝试一下&#xff0c;关机重启&#xff0c;然后在进入系统的时候&#xf…

路肩石水渠机在施工公路项目中工艺特点的匹配

新建公路路肩项目在目前公路项目中的技术手段和实现方式,大多数依靠机械设备来机械来进行,还有一部分通过人工传统的预制作业和安装模式来进行,两种工艺特点的对比来说对于补充完善建设手段和效果实现有很重要的意义. 其中采用了机械设备进行一次成型制作的过程,按照设计需求匹…

useRef 几种使用场景

图修改自 dev.to Demystifying React Hooks: useRef useRef神奇的地方除了可以在不重新渲染的状态下更有价值,也可以直接获取D加粗样式OM 进入而控制DOM的行为 Ref 有什么用? useRef返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数 ( initialValue)。返回…

常用vim命令和vim基本使用及Linux用户的管理,用户和组相关文件

常用vim命令和vim基本使用及Linux用户的管理&#xff0c;用户和组相关文件1. vim 的基本介绍和使用1.1 vim的三种模式1.2 常用vim命令【小白】1.3 Vim键盘图&#xff1a;2. Linux用户管理2.1 添加用户2.2 删除用户2.3 修改账号3. Linux系统用户组的管理4. 用户和组相关文件4.1 …

RuoYi-Vue部署(Nginx+Tomcat)

环境搭建RuoYi-Vue搭建、Linux安装Nginx、Linux安装JDK8、Linux安装MySql8、Linux安装Redis、Linux安装Tomcat9前端打包 1.ruoyi-ui鼠标右键-->打开于终端2.安装依赖&#xff1a;npm install --registryhttps://registry.npm.taobao.org-->node_modules3.编译打包&#x…

中国天气——西风带环流和寒潮

中国天气——西风带环流和寒潮 一. 西风环流概述 1. 概念 西风带&#xff1a;中高纬度地区平均水平环流在对流层盛行西风&#xff0c;称之为西风带西风带波动&#xff1a;西风带围绕极涡沿纬圈运动&#xff0c;平均而言表现为冬季三槽三脊&#xff0c;夏季四槽四脊&#xff…

盘点八个简单易上手的前端低代码框架项目

低代码近年来做为前端市场上火爆到不行的项目&#xff0c;其热度也是长久不衰&#xff0c;本文就为大家盘点了8个简单易上手的前端低代码框架项目&#xff0c;并各自都附上了体验链接&#xff0c;欢迎大家前往体验哦&#xff5e;&#xff5e;&#xff5e;&#xff5e; 1. Appsm…