EXPORT_SYMBOL解析
一般我们编写C程序时,要调用某个文件中的函数,需要在本文件中包含声明有被调用函数的头文件,然后编译连接后,方能找到调用函数。对于模块依赖的情况,不能简单的使用上面的方法,内核提供了一个机制,就是EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。您还可以手工修改内核源代码来导出另外的函数,用于重新编译并加载新内核后的测试。
include/module.h: struct kernel_symbol
{
unsigned long value;
const char *name;
};
/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec) \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"))) \
= MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \
__attribute_used__ \
__attribute__((section("__ksymtab" sec), unused)) \
= { (unsigned long)&sym, __kstrtab_##sym } #define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "") #define EXPORT_SYMBOL_GPL(sym) \
__EXPORT_SYMBOL(sym, "_gpl") #endif
下面是这种方法是演示:
第一个模块文件如下:
[lingyun@localhost export_symbol]$ ls
mod1 mod2
[lingyun@localhost export_symbol]$ cd mod1/
[lingyun@localhost mod1]$ ls
Makefile mod_a.c
[lingyun@localhost mod1]$ vim mod_a.c
mod_a.c
/*********************************************************************************
* Copyright: (C) 2013 fulinux<fulinux@sina.com>
* All rights reserved.
*
* Filename: mod_a.c
* Description: This file
*
* Version: 1.0.0(07/12/2013~)
* Author: fulinux <fulinux@sina.com>
* ChangeLog: 1, Release initial version on "07/12/2013 10:06:50 AM"
*
********************************************************************************/ #include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> static int func1(void)
{
printk("In Func: %s...\n",__func__);
return 0;
}
EXPORT_SYMBOL(func1); static int __init hello_init(void)
{
printk("Module 1, Init!\n");
return 0;
} static void __exit hello_exit(void)
{
printk("Module 1, Exit!\n");
} module_init(hello_init);
module_exit(hello_exit); MODULE_LICENSE("GPL");
其中EXPORT_SYMBOL(func1)导出func1函数符号,保存函数地址和名称.
这个模块的第一个Makefile文件:
[lingyun@localhost mod1]$ ls
Makefile mod_a.c
[lingyun@localhost mod1]$ vim Makefile
obj-m:=mod1.o
mod1-y:=mod_a.o KERNELDIR := /lib/modules/$(shell uname -r)/build PWD:=$(shell pwd) modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET)
其中内嵌对象 - obj-y,可加载模块 - obj-m,
KERNELDIR指向指向内核代码目录。
编译编译并加载:
[lingyun@localhost mod1]$ ls
Makefile mod_a.c
[lingyun@localhost mod1]$ make
make -C /lib/modules/2.6.32-279.el6.x86_64/build M=/usr/local/src/lingyun/fulinux/export_symbol/mod1 modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
CC [M] /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod_a.o
LD [M] /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.o
Building modules, stage 2.
MODPOST 1 modules
CC /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.mod.o
LD [M] /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.ko.unsigned
NO SIGN [M] /usr/local/src/lingyun/fulinux/export_symbol/mod1/mod1.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
[lingyun@localhost mod1]$ sudo insmod mod1.ko
[lingyun@localhost mod1]$ cat /proc/kallsyms | grep func1
0000000000000000 r __ksymtab_func1 [mod1]
0000000000000000 r __kstrtab_func1 [mod1]
0000000000000000 r __kcrctab_func1 [mod1]
0000000000000000 T func1 [mod1]
[lingyun@localhost mod1]$
[lingyun@localhost mod1]$ dmesg | grep Module
- User ID: CentOS (Kernel Module GPG key)
Module 1, Init!
第二个模块的文件如下:
[lingyun@localhost mod1]$ cd ../mod2/
[lingyun@localhost mod2]$ vim mod_b.c
/*********************************************************************************
* Copyright: (C) 2013 fulinux<fulinux@sina.com>
* All rights reserved.
*
* Filename: mod_b.c
* Description: This file
*
* Version: 1.0.0(07/12/2013~)
* Author: fulinux <fulinux@sina.com>
* ChangeLog: 1, Release initial version on "07/12/2013 10:29:55 AM"
*
********************************************************************************/ #include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h> static int func2(void)
{
extern int func1(void);
func1();
printk("In Func: %s...\n",__func__);
return 0;
} static int __init hello_init(void)
{
printk("Module 2, Init!\n");
func2();
return 0;
} static void __exit hello_exit(void)
{
printk("Module 2, Exit!\n");
} module_init(hello_init);
module_exit(hello_exit); MODULE_LICENSE("GPL");
在这里调用了第一个模块中的func1函数。
对应的Makefile文件:
[lingyun@localhost mod2]$ vim Makefile
obj-m:=mod2.o
mod2-y:=mod_b.o KERNELDIR := /lib/modules/$(shell uname -r)/build PWD:=$(shell pwd) modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET)
[lingyun@localhost mod2]$ make
make -C /lib/modules/2.6.32-279.el6.x86_64/build M=/usr/local/src/lingyun/fulinux/export_symbol/mod2 modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
Building modules, stage 2.
MODPOST 1 modules
WARNING: "func1" [/usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.ko] undefined!
make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
[lingyun@localhost mod2]$
[lingyun@localhost mod2]$ sudo insmod mod2.ko
insmod: error inserting 'mod2.ko': -1 Unknown symbol in module
[lingyun@localhost mod2]$
解决上面的问题如下:
解决办法是把mod_a的Module.symvers放到mod_b的当前路径,从而编译mod_b,符号信息会自动连接进去.
或者在mod_b的makefile中使用KBUILD_EXTRA_SYMBOLS指定mod_a的Module.symvers, 如:
KBUILD_EXTRA_SYMBOLS=/mod_a/Module.symvers
编译mod_b时,搜索Module.symvers的路径是:
1, kernel source path, e.g. /usr/src/kernels/linux-2.6.28.10
2, makefile中M=所指定的路径, 它等效于变量KBUILD_EXTMOD的值
3, 变量KBUILD_EXTRA_SYMBOLS的值
此时Makefile文件如下:
obj-m:=mod2.o
mod2-y:=mod_b.o KBUILD_EXTRA_SYMBOLS=~/fulinux/export_symbol/mod1/Module.symvers
KERNELDIR := /lib/modules/$(shell uname -r)/build PWD:=$(shell pwd) modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~core .depend .*.cmd *.ko *.ko.* *.mod.c .tmp_versions *odule* $(TARGET)
在编译加载如下:
[lingyun@localhost mod2]$ make
make -C /lib/modules/2.6.32-279.el6.x86_64/build M=/usr/local/src/lingyun/fulinux/export_symbol/mod2 modules
make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
CC [M] /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod_b.o
LD [M] /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.o
Building modules, stage 2.
MODPOST 1 modules
CC /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.mod.o
LD [M] /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.ko.unsigned
NO SIGN [M] /usr/local/src/lingyun/fulinux/export_symbol/mod2/mod2.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
[lingyun@localhost mod2]$ sudo insmod mod2.ko
[lingyun@localhost mod2]$
[lingyun@localhost mod2]$ dmesg | grep "In Func:"
In Func: func1...
In Func: func2...
可见模块二调用模块一的func1成功!!!
EXPORT_SYMBOL解析的更多相关文章
- 深入解析Linux内核I/O剖析(open,write实现)
Linux内核将一切视为文件,那么Linux的文件是什么呢?其既可以是事实上的真正的物理文件,也可以是设备.管道,甚至还可以是一块内存.狭义的文件是指文件系统中的物理文件,而广义的文件则可以是Linu ...
- linux设备驱动程序-i2c(2)-adapter和设备树的解析
linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 在本系列linux内核i2c框架的前两篇,分别讲 ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- Html Agility Pack 解析Html
Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面 用Fir ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- Asp.Net WebApi核心对象解析(下篇)
在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...
随机推荐
- CentOS6 yum源支持更多rpm包的升级(使用第三方软件库EPEL、RPMForge与RPMFusion)
转载于http://blog.csdn.net/erazy0/article/details/6878153 在CentOS下运行yum install flash-plugin或yum instal ...
- hdu1370-Biorhythms
http://acm.hdu.edu.cn/showproblem.php?pid=1370 中国剩余定理 已知(n+d)%23=a; (n+d)%28=b; (n+c)%33=i ...
- 【Tips】Endnote导入IEEE Xplore文献方法《转载》
1. 在IEEE XPlore中点击“Download Citation”: 2. 选中“Citation & Abstract”和“EndNote,Procite,RefMan”两个选项: ...
- 动手学Javascript(1)——PopStar
PopStar是一款很流行的手机游戏.它的基本规则是在某个方块上单击,如果该方块周围有和它颜色一样的方块,那么这些方块都被选中.之后在选中方块的某一个上再次单击,所有选中的方块就会消失. 如下图所示, ...
- 认识axure部件库中各个部件的属性
在axure中每一个部件都有自己的属性,下面这个表格,我们就首先来了解认识一下!以下内容来自网站蓝图,版权归原作者所有! 属性名称 属性说明 属性举例 标签 用来标示部件的名称,在axure中,部件名 ...
- 基于visual Studio2013解决C语言竞赛题之1051数的顺序
题目 解决代码及点评 /* 功能:自然数N一般写成如下形式: N=d[k]d[k-1]d[1] (d[1]-d[k] 均是十进制数字) 如果d[i+1]>d[i] (i=k-1 ...
- linux下C/C++IDE比较——Code::Blocks
工欲善其事,必先利其器.用了这么久的linux,现在比较主流的几个C/C++的IDE基本已都用过了,现在来对他们做一下简单的比较. 1.VIM首先要说的是VIM.我认为,VIM只是一个编辑器,不能算是 ...
- 单选按钮易忽略的Group属性
Group就其意思就是一组的意思.就是说用于选择多个控件组合,选了TRUE后,你就可以为这组新建一个变量.把一组控件当一个控件来使用.例如多个单选按钮用group属性,这样你就可以用一个变量来管理这些 ...
- 性能测试之LoardRunner 结果分析
性能结果分析是性能测试中的重中之重,也是难点所在,以下总结了看图的一些顺序: 1.首先可以检查Analysis模块提供的Summary Report,整个测试过程中我们所关心的各业务 2.首先关注性能 ...
- dos批量替换当前目录后缀名
有时候有些后缀名不满足条件,就需要进行批量的替换,如果人为的去替换,那么如果量少的话还好说,量多的话一个个去替换就太傻了,今天从网络上面查找了一些批量替换的dos命令,用起来还挺好用的,就直接把代码贴 ...