一般我们编写C程序时,要调用某个文件中的函数,需要在本文件中包含声明有被调用函数的头文件,然后编译连接后,方能找到调用函数。对于模块依赖的情况,不能简单的使用上面的方法,内核提供了一个机制,就是EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。您还可以手工修改内核源代码来导出另外的函数,用于重新编译并加载新内核后的测试。

  1. include/module.h:
  2.  
  3. struct kernel_symbol
  4. {
  5. unsigned long value;
  6. const char *name;
  7. };
  8. /* For every exported symbol, place a struct in the __ksymtab section */
  9. #define __EXPORT_SYMBOL(sym, sec) \
  10. __CRC_SYMBOL(sym, sec) \
  11. static const char __kstrtab_##sym[] \
  12. __attribute__((section("__ksymtab_strings"))) \
  13. = MODULE_SYMBOL_PREFIX #sym; \
  14. static const struct kernel_symbol __ksymtab_##sym \
  15. __attribute_used__ \
  16. __attribute__((section("__ksymtab" sec), unused)) \
  17. = { (unsigned long)&sym, __kstrtab_##sym }
  18.  
  19. #define EXPORT_SYMBOL(sym) \
  20. __EXPORT_SYMBOL(sym, "")
  21.  
  22. #define EXPORT_SYMBOL_GPL(sym) \
  23. __EXPORT_SYMBOL(sym, "_gpl")
  24.  
  25. #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                                                                                                            

  1. /*********************************************************************************
  2. * Copyright: (C) 2013 fulinux<fulinux@sina.com>
  3. * All rights reserved.
  4. *
  5. * Filename: mod_a.c
  6. * Description: This file
  7. *
  8. * Version: 1.0.0(07/12/2013~)
  9. * Author: fulinux <fulinux@sina.com>
  10. * ChangeLog: 1, Release initial version on "07/12/2013 10:06:50 AM"
  11. *
  12. ********************************************************************************/
  13.  
  14. #include <linux/init.h>
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17.  
  18. static int func1(void)
  19. {
  20. printk("In Func: %s...\n",__func__);
  21. return 0;
  22. }
  23. EXPORT_SYMBOL(func1);
  24.  
  25. static int __init hello_init(void)
  26. {
  27. printk("Module 1, Init!\n");
  28. return 0;
  29. }
  30.  
  31. static void __exit hello_exit(void)
  32. {
  33. printk("Module 1, Exit!\n");
  34. }
  35.  
  36. module_init(hello_init);
  37. module_exit(hello_exit);
  38.  
  39. MODULE_LICENSE("GPL");

其中EXPORT_SYMBOL(func1)导出func1函数符号,保存函数地址和名称.

这个模块的第一个Makefile文件:

[lingyun@localhost mod1]$ ls
Makefile  mod_a.c
[lingyun@localhost mod1]$ vim Makefile 

  1. obj-m:=mod1.o
  2. mod1-y:=mod_a.o
  3.  
  4. KERNELDIR := /lib/modules/$(shell uname -r)/build
  5.  
  6. PWD:=$(shell pwd)
  7.  
  8. modules:
  9. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  10.  
  11. modules_install:
  12. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
  13. clean:
  14. 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 

  1. /*********************************************************************************
  2. * Copyright: (C) 2013 fulinux<fulinux@sina.com>
  3. * All rights reserved.
  4. *
  5. * Filename: mod_b.c
  6. * Description: This file
  7. *
  8. * Version: 1.0.0(07/12/2013~)
  9. * Author: fulinux <fulinux@sina.com>
  10. * ChangeLog: 1, Release initial version on "07/12/2013 10:29:55 AM"
  11. *
  12. ********************************************************************************/
  13.  
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17.  
  18. static int func2(void)
  19. {
  20. extern int func1(void);
  21. func1();
  22. printk("In Func: %s...\n",__func__);
  23. return 0;
  24. }
  25.  
  26. static int __init hello_init(void)
  27. {
  28. printk("Module 2, Init!\n");
  29. func2();
  30. return 0;
  31. }
  32.  
  33. static void __exit hello_exit(void)
  34. {
  35. printk("Module 2, Exit!\n");
  36. }
  37.  
  38. module_init(hello_init);
  39. module_exit(hello_exit);
  40.  
  41. MODULE_LICENSE("GPL");

在这里调用了第一个模块中的func1函数。

对应的Makefile文件:

[lingyun@localhost mod2]$ vim Makefile 

  1. obj-m:=mod2.o
  2. mod2-y:=mod_b.o
  3.  
  4. KERNELDIR := /lib/modules/$(shell uname -r)/build
  5.  
  6. PWD:=$(shell pwd)
  7.  
  8. modules:
  9. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  10.  
  11. modules_install:
  12. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
  13. clean:
  14. 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文件如下:

  1. obj-m:=mod2.o
  2. mod2-y:=mod_b.o
  3.  
  4. KBUILD_EXTRA_SYMBOLS=~/fulinux/export_symbol/mod1/Module.symvers
  5. KERNELDIR := /lib/modules/$(shell uname -r)/build
  6.  
  7. PWD:=$(shell pwd)
  8.  
  9. modules:
  10. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  11.  
  12. modules_install:
  13. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
  14. clean:
  15. 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解析的更多相关文章

  1. 深入解析Linux内核I/O剖析(open,write实现)

    Linux内核将一切视为文件,那么Linux的文件是什么呢?其既可以是事实上的真正的物理文件,也可以是设备.管道,甚至还可以是一块内存.狭义的文件是指文件系统中的物理文件,而广义的文件则可以是Linu ...

  2. linux设备驱动程序-i2c(2)-adapter和设备树的解析

    linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 在本系列linux内核i2c框架的前两篇,分别讲 ...

  3. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  4. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  5. Html Agility Pack 解析Html

    Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面  用Fir ...

  6. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  8. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  9. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

随机推荐

  1. 编写高质量代码改善java程序的151个建议——[52-57]String !about String How to use them?

    原创地址:   http://www.cnblogs.com/Alandre/  (泥沙砖瓦浆木匠),须要转载的,保留下! Thanks Although the world is full of s ...

  2. HDOJ 1800 Flying to the Mars 盲目搜索......................so easy...........

    check the original problem here:http://acm.hdu.edu.cn/showproblem.php?pid=1800 the AC code: #include ...

  3. Endnote X6 如何修改输出格式(output style)成为自己想要的输出格式:

    Endnote X6 如何修改输出格式(output style)成为自己想要的输出格式: (1)首先尝试在endnote output style 网站中查找: http://www.endnote ...

  4. 删除workspace下的vss的scc文件

    public class DeleteAA { public static void main(String[] args) { DeleteAA aa=new DeleteAA(); aa.dele ...

  5. Tesseract Ocr引擎

    Tesseract Ocr引擎 1.Tesseract介绍 tesseract 是一个google支持的开源ocr项目,其项目地址:https://github.com/tesseract-ocr/t ...

  6. delphiXE调用Objective-c库

    http://stackoverflow.com/questions/16515218/xe4-firemonkey-ios-static-library-pascal-conversion-from ...

  7. DButils工具类能够用来获取数据库连接向数据库插入更新删除对象2

    package com.ctl.util; import java.awt.Color; import java.awt.Font; import java.awt.Insets; import ja ...

  8. HDU 4709 Herding 几何题解

    求全部点组成的三角形最小的面积,0除外. 本题就枚举全部能够组成的三角形,然后保存最小的就是答案了.由于数据量非常少. 复习一下怎样求三角形面积.最简便的方法就是向量叉乘的知识了. 并且是二维向量叉乘 ...

  9. Eclipse ADT 更换主题

    如果Eclipse 版本3.6以上 在 Help→Eclipse Marketplace 搜索 Theme 之后安装即可 如果Eclipse版本3.5 一下, 通过地址安装插件: http://ecl ...

  10. 使用python进行加密解密AES算法

    使用python进行加密解密AES算法-代码分享-PYTHON开发者社区-pythoner.org 使用python进行加密解密AES算法 TY 发布于 2011-09-26 21:36:53,分类: ...