【开发日常】insmod: error inserting ‘*.ko‘: -1 Unknown symbol in module原理分析
问题的起源是一次面试,面试官询问加载内核的时候,如果insmod失败,且提示Unknown symbol in module。请问我里面的原理是什么呢?为什么内核知道当前缺少的是这个symbol?
想了解下具体的原因。
首先是模拟一个环境。
写一个module模块,里面调用了其他模块的符号表。同时给予函数声明。在编译的阶段,不会报错,但是在加载KO的时候,报错了。提示“Unknown symbol in module”
原因和内核符号表有关。
linux2.6开始的“/prob/kallsyms”文件对应着内核符号表,记录了符号以及符号所在的内存地址。
内核符号表:记录了内核中所有的符号(函数、全局变量等)的地址以及名字,这个符号表被嵌入到内核镜像中,使得内核可以在运行过程中随时获得一个符号地址对应的符号名
在Linux内核中,驱动程序和内核的其他部分之间是通过叫做symbol(符号)的接口来通信的,一个symbol可以是一个函数、一个全局变量或其他对象等等。默认情况下,这些symbol只能在内核中使用,因此,它们不会被其他程序访问。如果想要将symbol导出给外部模块使用,可以使用EXPORT_SYMBOL和EXPORT_SYMBOL_GPL宏来实现。
模块可以使用如下宏导出符号到内核符号表:
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名)
导出的符号可以被其他模块使用,不过使用之前一定要声明一下。
EXPORT_SYMBOL和EXPORT_SYMBOL_GPL的区别在于,EXPORT_SYMBOL_GPL只导出给使用了GPL或可以互操作的许可证的模块使用。由于这些许可证限制了使用这些符号的模块的范围,因此EXPORT_SYMBOL_GPL被认为比EXPORT_SYMBOL更加安全。
代码演示:
//hello.c文件,定义2个函数,用于导出
#include <<a href="http://lib.csdn.net/base/linux" class='replace_word' title="Linux知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Linux</a>/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
int add_integar(int a,int b)
{ return a + b;
}
int sub_integar(int a,int b)
{ return a - b;
}
EXPORT_SYMBOL(add_integar);
EXPORT_SYMBOL(sub_integar);
//test.c 用于调用hello模块导出的函数
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
extern int add_integar(int ,int); //声明要调用的函数
extern int sub_integar(int ,int); //声明要调用的函数
int result(void)
{ int a,b; a = add_integar(1,1); b = sub_integar(1,1); printk("%d/n",a); printk("%d/n",b); return 0;
}
make后,先加在hello模块,再加载test模块。
然后cat /proc/kallsyms | grep integer
显示:
[root@localhost test]# cat /proc/kallsyms |grep integar
e053d000 u add_integar [test]
e053d004 u sub_integar [test]
e053d02c r __ksymtab_sub_integar [hello]
e053d03c r __kstrtab_sub_integar [hello]
e053d034 r __ksymtab_add_integar [hello]
e053d048 r __kstrtab_add_integar [hello]
e053d000 T add_integar [hello]
e053d004 T sub_integar [hello]
再深入了解,什么是内核符号表?
一、什么是符号(Symbols)?
什么是Symbol? 其实就是kernel中的变量(Variable Name)或函数名称(Function Name)
这样可以方便程序员在写程序时可以直接参照这一份Symbol的索引文件,找到所需要的kernel信息,这一份Symbol的索引文件又称为kernel symbol table。
二、内核符号表(Kernel Symbol Table)?
定义:
内核符号表,就是在内核的内部函数或变量中,可供外部引用的函数和变量的符号表。
其实说白了就是一个索引文件,它存在的目的就是让外部软件可以知道kernel文件内部实际分配的位置。
所在文件:
编译内核时,System.map文件用于存放内核符号表信息。
(System.map文件位于/或者/boot、/usr/src/linux/下)
文件的生成:
符号表是所有内核符号及其对应地址的一个列表,随着每次内核的编译,就会产生一个新的对应System.map文件,当内核运行出错时,通过System.map中的符号表解析,就可以查到一个地址值对应的变量名。System.map文件记录了所有代码的运行地址(所有函数和变量)。
【内核并不使用符号名。它是通过变量或函数的地址(指针)来使用变量或函数的。其实内核连System.map文件都不使用,只是生成用于调试用的。】
system.map文件的格式:
| 线性地址 | 类型 | 符号 |
|---|---|---|
| ffffffff81002590 | t | create_dev |
| ffffffff81009c00 | T | show_regs |
其中,类型 若是小写字母则表示局部引用, 若是大写字母则表示全局引用(外部)。
内核符号表的存在意义:
1)把内核的符号地址,转化为程序猿可以看懂的符号名称。
内核符号表就是为程序员通过符号来访问程序体的对应地址(指针),建立了一个动态的,可变更的映射表格。
例如:
内核不会使用符号名create_dev,而会使用ffffffff81002590来引用这个变量。但程序猿们更喜欢符号名create_dev这样直观的名字。
所以就需要这么一个对应关系表。这个类似于网络里的DNS,没有谁愿意去记那没规律的IP地址,而记个网址就好记多了。
2)转换之后,就可以更方便的调试内核代码。
对于系统的oop消息、或者通过gdb的调试消息,都需要根据该对照表,将内核熟悉的函数地址转化为用户熟悉的函数名称,便于用户进行故障定位、运行监控。
而内核本身并不真正使用System.map,而只是用于做调试用。
2.6)内核符号表存储位置
System.map
磁盘中真实存在的文件,存储内核中静态编译的函数和变量地址,每个新编译内核对应一个System.map文件,当klogd输出内核消息时,会通过/boot/System.map来将函数、变量地址转换为名称,方便用户理解。该文件对应不同的编译内核有对应的实现文件。
/proc/kallsyms
内核启动时候创建,供oops时定位错误,文件大小总为0,包含当前内核导出的、可供使用的变量或者函数;它只是内核数据的简单表示形式。
System.map 和 /proc/kallsyms 区别
二者相似点:
都是内核函数、变量的符号表,结构一致;对于可导出的内核变量、函数,其运行时在物理内存中的位置是一样的。
二者区别:
两者侧重点不同,
System.map文件面向内核,对于内核中的没有导出的变量或者函数名,比如kthread_create_list链表头指针,也有其相应的内核地址,该文件一般是只读的、固定大小的,没有动态添加模块中的变量、函数名;
而kallsyms在内核启动过程中创建,并实时更新,反映的是系统的当前最新情况,其内部也包含内核或者是已加载模块导出的函数、变量名称。
所以和System.map文件有差别,kallsyms文件动态变化,大小不固定。
总结就是:
System.map文件较单纯,是在用户一开始编译就产生的固定文件,不会因为任何原因更改,除非被换掉。
而/proc/kallsyms是一个在启动时由Linux kernel实时产生的文件,当系统有任何变更时,它就会马上做出修正。
因为这是动态的信息,当用户新增或删除一个module,都会自动做实时的修正(/proc下的都是这一类型的文件)
分类
Linux内核的符号表位于两个部分。
首先是内核的静态部分,也就是内核文件映像vmlinuz部分的符号表,对应于/proc/kallsyms和System.map这两个文件。
还有一部分则是Linux可配置模块部分的符号表。
形成过程
Linux内核符号表/proc/kallsyms的形成过程
./scripts/kallsyms.c负责生成System.map
./kernel/kallsyms.c负责生成/proc/kallsyms
./scripts/kallsyms.c解析vmlinux(.tmp_vmlinux)生成kallsyms.S(.tmp_kallsyms.S),然后内核编译过程中将kallsyms.S(内核符号表)编入内核镜像uImage 内核启动后./kernel/kallsyms.c解析uImage形成/proc/kallsyms
要在一个内核中启用 kallsyms 功能,必须用进行内核配置,make menuconfig设置 CONFIG_KALLSYMS 选项为y;如果你要在 kallsyms 中包含全部符号信息,必须设置 CONFIG_KALLSYMS_ALL 为y。
三、导出符号表
驱动程序中,如果该驱动程序中有被其他内核代码调用的部分,可以用EXPORT_SYMBOL导出到内核符号表中。
参考:
http://blog.csdn.net/lisan04/article/details/4076013
Linux内核:符号表详解 - 知乎 (zhihu.com)
相关文章:
【开发日常】insmod: error inserting ‘*.ko‘: -1 Unknown symbol in module原理分析
问题的起源是一次面试,面试官询问加载内核的时候,如果insmod失败,且提示Unknown symbol in module。请问我里面的原理是什么呢?为什么内核知道当前缺少的是这个symbol? 想了解下具体的原因。 首先是模拟一个环境。 写…...
圆弧插补【C#】
圆弧: 圆弧插补方法可以通过提供圆弧的起点、终点和半径来画弧。下面是一个用C#实现的圆弧插补方法的示例代码: public void DrawArc(Point startPoint, Point endPoint, int radius, bool isClockwise) {// 计算圆心坐标int centerX (startPoint.X e…...
Redis EmbeddedString
前言 Redis 写入键值对时,首先会先创建一个 RedisObject 对象来存储 Value。 如果写入的 Value 是字符串,那么 Redis 会再根据写入的字符串长度,来创建对应的 sdshdr 来存储字符串,最后把 RedisObject 的 ptr 指针指向 sdshdr。 …...
SpringMVC之WEB-INF下页面跳转@ModelAttributeIDEA tomcat控制台中文乱码问题处理
WEB-INF下页面跳转 ModelAttribute来注解非请求处理方法 用途:预加载数据,会在每个RequestMapping方法执行之前调用。 特点:无需返回视图,返回类型void IDEA tomcat控制台中文乱码问题处理 复制此段代码:-Dfile.e…...
利用ChatGPT练习口语
目录 ChatGPT 这两天发布了一个激动人心的新功能,App端(包括iOS和Android)开始支持语音对话以及图片识别功能。 这两个功能一如既往的优先开放给Plus用户使用,现在将App更新到最新版本,就能体验。 为什么说激动人心&a…...
【Django 01】环境搭配与项目配置
1. 介绍 https://github.com/Joe-2002/sweettalk-django4.2#readme Django 是一个使用 Python 编写的开源 Web 应用程序框架,它提供了一套用于快速开发安全、 可扩展和高效的 Web 应用程序的工具和功能。Django 基于 MVC(Model-View-Controller…...
PyCharm配置运行参数
...
ChatGPT AIGC 实现Excel 交叉查找 Index+match 函数
行与列交叉多条件查找需求如下: 这个需求要使用Excel中最经典的组合函数Index+match函数。 函数公式可以交给ChatGPT AIGC来实现。 Prompt: 有一个表格A列为品牌,B列为月份,C列为销量,61行数据,请写出Excel函数公式根据E3单元格的品牌与F2单元格的月份查找对应的销量,…...
【前端学习】—多种方式实现数组拍平(十一)
【前端学习】—多种方式实现数组拍平(十一) 一、数组拍平 数组拍平也叫数组扁平化、数组拉平、数组降维,指的是把多维数组转化为一维数组。 二、使用场景 复杂场景下的数据处理(echarts做大屏数据展示) 三、如何实…...
智慧远程医疗服务:从零开始搭建互联网医院APP
互联网医院APP作为远程医疗服务的一部分,正在为患者和医生带来更便捷的医疗体验。本文将探讨如何从零开始构建一个互联网医院APP,包括关键步骤、技术要点和挑战。 一、确定项目目标和范围 在开始之前,您需要明确定义您的互联网医院APP的目标…...
ADAS可视化系统,让自动驾驶更简单 -- 入门篇
随着车载芯片的升级、技术的更新迭代,可视化ADAS逐渐变成汽车的标配走入大家的生活中,为大家的驾车出行带来切实的便捷。那么你了解HMI端ADAS的实现过程吗?作为ADAS可视化系统的入门篇,就跟大家聊一聊目前较常见的低消耗的一种ADA…...
探索低代码技术
低/无代码的高速发展,属于软件市场的选择,相较于传统编写代码的开发方式,低/无代码开发效率高、投入成本低、技术门槛也更低,未来更多软件应用将使用低/无代码技术完成,这也是趋势。 身为开发人员经常需要花大量时间在…...
头歌的数据库的第二次作业的答案
目录 MySQL-视图 第1关:创建所有保险资产的详细记录视图 第2关:基于视图的查询 MySQL数据库 - 连接查询 第1关:内连接查询 第2关:外连接查询 第3关:复合条件连接查询 MySQL数据库 - 子查询 第1关:…...
基于R329 SOC智能音响开发编译环境搭建
R329智能音响开发编译环境搭建 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务, R329编译命令 source build/envsetup.sh lunch make -j4 pack 编译工程选择 baidu_panshan...
libplctag开源库的API介绍
文章目录 1 开源库概要2 API介绍2.1 Tag Model(标签模型)2.2 Status Codes(状态码)2.3 Versions and Checking Library Compatibility(版本和检查库的兼容性)2.4 Tag Life Cycle(标签生命周期&a…...
智能化安全巡更巡查系统—提升安全管理效率
传统的巡检都是手工完成,记录、拍照,回到办公室打印表单再交给作业队伍整改,再去现场核实复查,流程繁琐,效率低。而且大部分工地为了减少麻烦,人员往往都是口头沟通,存在很大质量风险࿰…...
SAP MM学习笔记36 - 释放支付保留的发票
SAP中,请求书照合之后,发现不一致,就会支付保留。 支付保留,可以参考如下文章。 SAP MM学习笔记34 - 请求书照合中的支付保留(发票冻结)_东京老树根的博客-CSDN博客 当然发现不一致之后,如果不…...
MySQL数据库的ID列添加索引
要为MySQL数据库的ID列添加索引,可以使用以下语法: ALTER TABLE table_name ADD INDEX index_name (id);其中,table_name是要添加索引的表名,index_name是索引的名称,id是要添加索引的列名。 例如,如果要…...
LuaJIT编写的解析十六进制数据
以下是使用LuaJIT编写的解析十六进制数据并将uint16转换为JSON的示例代码: local ffi require("ffi") local bit require("bit") local cjson require("cjson")-- 定义结构体 ffi.cdef[[typedef struct {uint16_t value;} uint16…...
【SA8295P 源码分析 (一)】09 - XBL Loader 加载 QSEE、SEC、CPUCPFW、QHEE、APPSBL过程分析
【SA8295P 源码分析】09 - XBL Loader 加载 QSEE、SEC、CPUCPFW、QHEE、APPSBL过程分析 一、QSEE二、SEC三、CPUCPFW四、QHEE五、APPSBL系列文章汇总见:《【SA8295P 源码分析 (一)】系统部分 文章链接汇总 - 持续更新中》 本文链接:《【SA8295P 源码分析 (一)】09 - XBL Load…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
