内核符号表问题

问题描述

 

有两个模块,mod1和mod2。

在mod1中定义了func()函数,并且经EXPORT_SYMBOL()导出。

在mod2中extern func(),调用func()。

 

编译模块mod2,成功。

加载mod2时,输出:

insmod: error inserting 'mod2.ko': -1 Invalid parameters

dmesg查看:

mod2: no symbol version for func

mod2: Unknown symbol func (err -22)

 

内核符号表

 

Kernel symbol table,内核符号表。

Linux内核的符号表位于两个部分:

静态的符号表,即内核映像vmlinuz的符号表(System.map)

动态的符号表,即内核模块的符号表(/proc/kallsyms)

 

符号标志

T    External text

t     Local text

D    External initialized data

d    Local initialized data

B    External zeroed data

b    Local zeroed data

A    External absolute

a    Local absolute

U    External undefined

G    External small initialized data

g    Local small initialized data

I    Init section

S    External small zeroed data

s    Local small zeroed data

R    External read only

r    Local read only

C    Common

E    Small common

 

我们可以看到,大写标志都是全局的、可被外部引用的,而小写标志都是局部的、不能被外部引用的。

可以用nm命令查看可执行文件的符号表(nm - list symbols from object files)。

 

insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局函数和全局

变量的地址。当模块被装入内核后,它所导出的任何内核符号都会变成内核符号表的一部分。

EXPORT_SYMBOL(name); // 所有模块可见

EXPORT_SYMBOL_GPL(nae); // 含有GPL许可证模块可见

 

问题解决

 

了解了什么是内核符号表之后,我们回到之前的问题。

我们查看/proc/kallsyms,发现mod1的func函数的标志为t,而此标志表示函数是局部的。

此问题是内核2.6.26之后版本的bug,并且不会被修复。

 

解决办法有几种:

(1)把mod1的Module.symvers放到mod2中,这样在编译mod2时符号信息会自动链接进去。

(2)在mod2的Makefile中添加符号信息

echo '0x01873e3f        func  mod1 EXPORT_SYMBOL_GPL' > Module.symvers

这样mod2在编译时就知道mod1中func符号的地址。

 

Q:这个问题是由什么引起的呢?

A:生成mod2的时候不知道mod1中func的校验码,mod2加载时检查校验码出错。

在内核主线代码树的一个提交修改了内核挂载模块时的函数版本校验机制,使得在挂载模块时候对于编译

时个别函数没有确定CRC校验值无法通过check_version函数检查。

这是内核有意要禁止存在个别无版本校验信息的函数的模块挂载。

 

Reference

 

[1]. http://blog.chinaunix.net/uid-20543672-id-3023148.html

 

内核符号表是操作系统内核中的一个重要组成部分,它存储了内核中所有函数和变量的符号信息。在大多数操作系统中,内核符号表是通过调试信息生成的,例如在Linux中,可以使用GCC编译器的"-g"选项来生成调试信息。 下面是一些可能用于内核符号表相关函数实现的伪代码示例: 1. 初始化符号表: - 创建符号表数据结构 - 遍历内核中的函数和变量 - 将每个函数和变量的符号信息添加到符号表中 2. 查找符号: - 接收一个符号名称作为参数 - 在符号表中查找与该名称匹配的符号条目 - 如果找到匹配的符号条目,则返回该条目的地址或其他相关信息,否则返回错误代码 3. 添加符号: - 接收一个符号名称和地址作为参数 - 创建一个新的符号条目,并将符号名称和地址存储其中 - 将新的符号条目添加到符号表中 4. 更新符号: - 接收一个符号名称和新地址作为参数 - 在符号表中查找与该名称匹配的符号条目 - 如果找到匹配的符号条目,则更新其地址为新地址 5. 删除符号: - 接收一个符号名称作为参数 - 在符号表中查找与该名称匹配的符号条目 - 如果找到匹配的符号条目,则从符号表中删除该条目 这些函数的具体实现方式可能因操作系统而异。在Linux内核中,可以使用特定的数据结构如哈希表或红黑树来实现符号表,并使用适当的算法来进行查找、添加、更新和删除操作。此外,还需要考虑多线程环境下的同步和互斥问题,以确保符号表的一致性和线程安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值