一文讲解内核模块依赖!

news2024/11/19 14:45:40

前言

不知大家有没有想过,在一个内核模块代码中,会用到printk函数,而这个函数不是我们实现的,它是内核代码的一部分,但我们为什么能够编译通过呢?

我们的代码之所以能够编译通过,是因为对模块的编译仅仅是编译,并没有链接

编译出来的.ko文件是一个普通的ELF文件,使用file命令和nm命令,我们可以看到相关的信息:

# file vser.ko
vser.ko ELF 32-bit LSB relocatable, Intel 80386, vserion 1 (SYSV), BuildID[sha1]=0x09ca747e6f75c65v19a5da9102113v98d7cea24, not stripped
# nm vser.ko
......
00000004 d port
    U printk
00000000 t vser_exit
00000000 t vser_init

vser_initvser_exit分别是模块的入口函数和出口函数,使用nm命令查看模块目标文件的符号信息时,可以看到vser_exitvser_init的符号类型是t,表示它们是函数

printk的 符号类型是U,表示它是一个未决符号。意思是说在编译阶段不知道这个符号的地址,因为它被定义在其他文件中,没有放在模块代码一起编译。

那printk函数的地址问题怎么解决呢?答案是用EXPORT_SYMBOL宏将printk导出即可。

EXPORT_SYMBOL导出符号

大致原理:利用EXPORT_SYMBOL宏生成一个特定的结构并放在ELF文件的一个特定段中,在内核的启动过程中,会将符号的确切地址填充到这个结构的特定成员中

模块加载时,加载程序将去处理未决符号,在特殊段中搜索符号的名字,如果找到,则将获得的地址填充在被加载模块的相应段中,这样符号的地址就可以确定。

使用这种方式处理未决符号,其实相当于把链接的过程推后,进行了动态链接,和普通的应用程序使用共享库函数的道理是类似的。可以发现,内核将会有大量的符号导出,为模块提供了丰富的基础设施。

内核模块依赖

通常情况下,一个模块只使用内核导出的符号,自己不导出符号。但是如果一个模块需要提供全局变量或函数给另外的模块使用,那么就需要将这些符号导出。

这在一个驱动调用另一个驱动代码时比较常见,这样模块和模块之间就形成了依赖关系,使用导出符号的模块将会依赖于导出符号的模块。

举个具体的例子,下面是两个C文件,vser.c调用了dep.c中的变量和函数:

vser.c

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

extern int expval;
extern void expfun(void);

static int __init vser_init(void)
{
 printk("vser_init\");
 printk("expval:%d\n", expval);
 expfun();
 
 return 0;
}

static void __exit vser_exit(void)
{
 printk("vser_exit\n");
}

module_init(vser_init);
module_exit(vser_exit);

dep.c

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

static int expval = 5;
EXPORT_SYMBOL(expval);

static void expfun(void)
{
 printk("expfun");
}EXPORT_SYMBOL_GPL(expfun);

Makefile关键处:

obj-m := vser.o
obj-m += dep.o

上述代码中,dep.c定义了一个变量expval和一个函数expfun,并分别用EXPORT_SYMBOLEXPORT_SYMBOL_GPL导出。而vser.c里则调用了dep.c的变量和函数,编译安装后:

# modprobe vser
# dmesg
[58278.204677] vser_init
[58278.204683] expval:5
[58287.206464] expfun

从输出信息中可以看到,vser.c正确引用到了dep.c的变量和函数。

  资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

这里有三点重要说明:

  • 如果使用insmod命令加载模块,则必须先加载dep模块,再加载vser模块

因为vser模块用到了dep模块的东西。从这里可以看出,modprobe命令优于insmod命令的地方在于其可以自动加载被依赖的模块。而这又要归功于depmod命令,depmod命令会生成模块的依赖信息,保存在/lib/modules/5.10.111-64-generic/modules.dep文件中。其中,5.10.111-64-generic是内核源码版本。查看该文件可以发现vser模块所依赖的模块。

# cat /lib/modules/5.10.111-64-generic/modules.dep
......
extra/vser.ko: extra/dep.ko
extra/dep.ko:
  • 两个模块存在依赖关系,如果分别编译两个模块,会出现类似下面的警告信息,并且即便加载顺序正确,加载也不会成功:
WARNING: "expfun" [/home/ubuntu/driver/module/vser.ko] undefined!
WARNING: "expval" [/home/ubuntu/driver/module/vser.ko] undefined!

# sudo insmod dep.ko
# sudo insmod vser.ko
insmod:error inserting 'vser.ko': -1 Invalid parameters

这是因为在编译vser模块时在内核的符号表中找不到expvalexpfun的项,而vser模块又完全不知道dep模块的存在。

解决这个问题的方法是将两个模块放在一起编译,或者将dep模块放在内核源码中,先在内核源码下编译完所有的模块,再编译vser模块。

  • 卸载模块时要先卸载vser模块,再卸载dep模块,否则会因为dep模块被vser模块使用而不能卸载

内核将会创建模块依赖关系的链接,只有当依赖于这个模块的链表为空时,模块才能被卸载.

 

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

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

相关文章

Kubernetes安装

Kubernetes 也称为 K8s&#xff0c;是用于自动部署、扩缩和管理容器化应用程序的开源系统。 Kubernetes 核心能力&#xff1a; 服务发现和负载均衡 Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器&#xff0c;如果进入容器的流量很大&#xff0c; Kubernetes 可以负载…

艾瑞报告:预计2023年家用智能照明市场规模过百亿,Yeelight易来引领行业发展

照明是家居的主要部分&#xff0c;以智能化控制技术光环境设计为核心的智能照明成为智能家居重要的子系统与子应用&#xff0c;智能照明通过精准的设计&#xff0c;将单品链接成系统&#xff0c;通过算法和云平台实现智能化&#xff0c;针对不同的空间适配不同的灯光&#xff0…

使用注解存储Bean对象

日升时奋斗&#xff0c;日落时自省 目录 1、存储Bean对象 1.1、五大类注解 1.2、添加注解存储Bean对象&#xff08;Controller&#xff09; 1.3、Bean的命名规则 1.4、其他类注解演示 1.5、为什么需要五大类注解 1.5.1、JavaEE标准分层 1.5.2、实例分层结构 1.5.3、分…

GPT模型支持下的Python-GEE遥感云大数据分析、管理与可视化技术及多领域案例实践应用

目前&#xff0c;Earth Engine上包含超过900个公共数据集&#xff0c;每月新增约2 PB数据&#xff0c;总容量超过80PB。与传统的处理影像工具&#xff08;例如ENVI&#xff09;相比&#xff0c;Earth Engine在处理海量遥感数据方面具有不可比拟的优势。一方面&#xff0c;它提供…

【Linux】线程同步分析:什么是条件变量?生产者消费者模型是什么?POSIX信号量怎么用?阻塞队列和环形队列模拟生产者消费者模型

上一篇文章我们分析了什么是线程互斥, 以及线程互斥的特点和使用. 说白了, 线程互斥就是多线程在争抢使用临界资源, 谁抢到了谁就用, 抢不到的就等. 这样不会因为多线程同时访问临界资源而造成错误. 虽然没有错误, 但是, 思考另外一个问题&#xff1a;这样合理吗&#xff1f…

Android Studio连接使用第三方模拟器

使用Android Studio自带的模拟器&#xff0c;第一会比较卡&#xff0c;第二配置容易出错&#xff0c;第三&#xff0c;自带的模拟器很吃电脑配置。如果电脑配置较差&#xff0c;会比较耽误事。所以为例解决上面三个问题&#xff0c;可以在电脑上按照第三方手机模拟器&#xff0…

陶泓达:4.18午间欧盘黄金原油最新精准操作建议!

黄金方面&#xff1a; 黄金消息面解析&#xff1a;周一&#xff08;4月17日&#xff09;美市盘中&#xff0c;美国公布的4月纽约联储制造业指数和4月NAHB房产市场指数均超出预期&#xff0c;提振了美联储在5月继续加息的预期。数据公布之后&#xff0c;美元指数加速上扬&#x…

【wireshark】Ubuntu 安装 wireshark 以及 wireshark 过滤器的使用

目录 1、安装wireshark 2、wireshark 过滤器比较符号 3、wireshark 过滤方式 (1) 根据 IP 地址过滤 (2) 根据端口号过滤 (3) 根据报文长度过滤 (4) HTTP协议过滤 参考文章链接&#xff1a;Wireshark 过滤器使用 1、安装wireshark 在命令行输入如下命令安装 wireshark …

Flutter与Android开发:构建跨平台移动应用的新选择

Flutter与Android开发&#xff1a;构建跨平台移动应用的新选择 本文内容提纲如下&#xff1a; 介绍Flutter技术&#xff1a;Flutter是一种由Google推出的开源UI工具包&#xff0c;用于构建高性能、跨平台的移动应用。文章将介绍Flutter的基本概念、特点和优势&#xff0c;包括其…

计算机设置定时任务及自动开关机

目录 创建定时任务 自动开关机 创建定时任务 1、右击桌面计算机&#xff0c;点击管理&#xff0c;打开计算机管理或通过控制面板打开[控制面板-管理工具-计算机管理] 2、依次选择&#xff1a;系统工具->任务计划程序->任务计划程序库->Microsoft->Windows&#…

MOD8ID 加密芯片的 AES-GCM 模式使用

一&#xff1a;什么是 AES-GCM 加密&#xff1f; AES-GCM是一种高级加密标准&#xff08;AES&#xff09;的加密模式&#xff0c;同时使用加密和身份验证&#xff08;AEAD&#xff09;功能。它使用加密算法AES和Galois Counter Mode&#xff08;GCM&#xff09;计数器模式&…

5行Python代码采集3000+上市公司信息,很爽

嗨害大家好鸭&#xff01;我是爱摸鱼的芝士❤ 毕业季也到了找工作的季节了&#xff0c; 很多小伙伴都会一家一家的公司去看&#xff0c; 这得多浪费时间啊。 今天用Python教大家怎么采集公司的信息&#xff0c; 相信大家会很喜欢这个教程的&#xff0c;nice&#xff01; pyth…

中介者设计模式(Mediator Design Pattern)[论点:概念、组成角色、相关图示、示例代码、适用场景]

文章目录 概念组成角色相关图示示例代码适用场景 概念 中介者设计模式是一种行为型设计模式&#xff0c;它通过引入一个中介对象来封装一组对象之间的交互&#xff0c;使得对象之间不需要显式地相互引用&#xff0c;从而降低它们之间的耦合。通过将对象间的通信封装到中介者对象…

Ubuntu20.4利用httpd(Apache2)源码搭建web服务器

Apache取自“a patchy server”的读音&#xff0c;源于NCSAhttpd服务器&#xff0c;经过多次修改&#xff0c;成为世界上最流行的Web服务器软件之一&#xff0c;Apache的特点是简单、速度快、性能稳定&#xff0c;并可做代理服务器来使用。 本来它只用于小型或试验Internet网络…

TinyOS 配置教程

文章目录 前言1. 安装1.1. 实验环境1.2. TinyOS基础工作1.3. TinyOS 的配置1.4. 安装 java1.5. 安装编译器 2. 测试仿真程序总结 前言 本文主要用于记录在 WSN 课程中&#xff0c;配置大作业所需使用的 TinyOS 仿真环境 1. 安装 1.1. 实验环境 本实验以如下版本为例&#xf…

Python面向对象详解(非常详细)

非常详细的讲解&#xff08;爆肝1w字&#xff09;&#x1f44f;&#x1f3fb;&#x1f44f;&#x1f3fb;&#x1f44f;&#x1f3fb; 零基础一样学得会&#x1f44c;&#x1f3fb; 干货满满不看后悔&#x1f44d;&#x1f44d;&#x1f44d; &#x1f4dd;个人主页→数据…

函数重载注意事项

C为什么支持函数重载&#xff0c;C语言不支持函数重载&#xff1f; C代码产生函数符号时&#xff0c; 是函数名参数列表类型组成的&#xff01;如_Z3sumii C代码产生函数符号时&#xff0c;只由函数名决定 什么是函数重载&#xff1f; 一组函数&#xff0c;其中函数名相同&…

读书笔记-《ON JAVA 中文版》-摘要14[第十四章 流式编程]

文章目录 第十四章 流式编程1. 流支持2. 流创建2.1 流创建2.2 随机数流2.3 int 类型的范围2.4 generate()2.5 iterate()2.6 流的建造者模式2.7 Arrays2.8 正则表达式 3. 中间操作3.1 跟踪和调试3.2 流元素排序3.3 移除元素3.4 应用函数到元素3.5 在 map() 中组合流 4. Optional…

电脑文件恢复怎么做?3个方法快速恢复文件!

案例&#xff1a;电脑文件恢复怎么操作&#xff1f; 【我的电脑已经好久没用了&#xff0c;最近因为需要查看一些相关的文件才用到电脑&#xff0c;但是我打开后发现里面很多重要的文件都不见了&#xff0c;请问电脑文件应该怎么恢复呢&#xff1f;感谢回答&#xff01;】 电…

AIGC从入门到精通

一键起飞 # 提前安装好python 3.10.9 ​git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui cd stable-diffusion-webui ./webui.sh -f --api --listen --enable-insecure-extension-access 非常详细&#xff01;6000字详解AI绘画文生图干货、技巧&#xf…