免费建立网站的网站都有啥,网站之家,贵州三蒲建设工程有限公司网站,凡科网站建设怎么去掉极速建站问题的起源是一次面试#xff0c;面试官询问加载内核的时候#xff0c;如果insmod失败#xff0c;且提示Unknown symbol in module。请问我里面的原理是什么呢#xff1f;为什么内核知道当前缺少的是这个symbol#xff1f;
想了解下具体的原因。 首先是模拟一个环境。
写…
问题的起源是一次面试面试官询问加载内核的时候如果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 hrefhttp://lib.csdn.net/base/linux classreplace_word titleLinux知识库 target_blank stylecolor:#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
显示
[rootlocalhost 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文件的格式
线性地址类型符号ffffffff81002590tcreate_devffffffff81009c00Tshow_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)