Linux 驱动开发之内核模块开发(四)—— 符号表的导出

 Linux内核头文件提供了一个方便的方法用来管理符号的对模块外部的可见性,因此减少了命名空间的污染(命名空间的名称可能会与内核其他地方定义的名称冲突),并且适当信息隐藏。 如果你的模块需要输出符号给其他模块使用,应当使用下面的宏定义:

EXPORT_SYMBOL(name);

EXPORT_SYMBOL_GPL(name);   //只适用于包含GPL许可权的模块;

     这两个宏均用于将给定的符号导出到模块外. _GPL版本的宏定义只能使符号对GPL许可的模块可用。 符号必须在模块文件的全局部分导出,不能在函数中导出,这是因为上述这两个宏将被扩展成一个特殊用途的声明,而该变量必须是全局的。这个变量存储于模块的一个特殊的可执行部分(一个"ELF段" ),在装载时,内核通过这个段来寻找模块导出的变量(感兴趣的读者可以看<linux/module.h>获知更详细的信息)。


一、宏定义EXPORT_SYMBOL分析

1、源码

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. <include/linux/moudule.h>  
  2.   
  3. …….  
  4.   
  5. #ifndef MODULE_SYMBOL_PREFIX  
  6. #define MODULE_SYMBOL_PREFIX ""  
  7. #endif  
  8.   
  9. …….  
  10.   
  11. struct kernel_symbol       //内核符号结构  
  12. {  
  13.        unsignedlong value;  //该符号在内存地址中的地址  
  14.        constchar *name;     //该符号的名称  
  15.   
  16. };  
  17.   
  18. ……  
  19.   
  20. #define __EXPORT_SYMBOL(sym,sec)                                 \  
  21.        externtypeof(sym) sym;                                                        \  
  22.        __CRC_SYMBOL(sym,sec)                                            \  
  23.        staticconst char __kstrtab_##sym[]                                 \  
  24.        __attribute__((section(“__ksymtab_strings”),aligned(1)))   \  
  25.        =MODULE_SYMBOL_PREFIX#sym;                      \  
  26.        staticconst struct kernel_symbol __ksymtab_##sym         \  
  27.        __used                                                                          \  
  28.        __attribute__((section(“__ksymatab”sec),unused))                   \  
  29.        ={(unsignedlong)&sym,_kstrab_#sym}   
  30.   
  31. #define    EXPORT_SYMBOL(sym)                   \  
  32.               __EXPOTR_SYMBOL(sym,””)  
  33.   
  34. #define    EXPORT_SYMBOL_GPL(sym)           \  
  35.               __EXPOTR_SYMBOL(sym,”_gpl”)  
  36.   
  37. #define    EXPORT_SYMBOL(sym)                   \  
  38.               __EXPOTR_SYMBOL(sym,”_gpl_future”)  

在分析前,先了解如下相关知识:

1)#运算符,##运算符

     通常在宏定义中使用#来创建字符串 #abc就表示字符串”abc”等。

    ##运算符称为预处理器的粘合剂,用来替换粘合两个不同的符号,

如:#define xName (n)  x##n

则xName(4)  则变为x4


2)gcc的 __attribute__ 属性:

     __attribute__((section(“section_name”)))的作用是将指定的函数或变量放入到名为”section_name”的段中

    __attribute__属性添加可以在函数或变量定义的时候直接加入在定义语句中。

如:

int myvar__attribute__((section("mydata"))) = 0;

表示定义了整形变量myvar=0;并且将该变量存放到名为”mydata”的section中

关于gcc_attribute详解可以参考:http://blog.sina.com.cn/s/blog_661314940100qujt.html


2、EXPORT_SYMBOL的作用是什么?

       EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。

       这里要和System.map做一下对比:System.map 中的是连接时的函数地址。连接完成以后,在2.6内核运行过程中,是不知道哪个符号在哪个地址的。

       EXPORT_SYMBOL的符号,是把这些符号和对应的地址保存起来,在内核运行的过程中,可以找到这些符号对应的地址。而模块在加载过程中,其本质就是能动态连接到内核,如果在模块中引用了内核或其它模块的符号,就要EXPORT_SYMBOL这些符号,这样才能找到对应的地址连接。


二、 EXPORT_SYMBOL使用方法

第一、在模块函数定义之后使用EXPORT_SYMBOL(函数名)

第二、在调用该函数的模块中使用extern对之声明

第三、首先加载定义该函数的模块,再加载调用该函数的模块

要调用别的模块实现的函数接口和全局变量,就要导出符号 /usr/src/linux-headers-2.6.32-33-generic/Module.symvers

A B
static int num =10;
static void show(void)
{
printk("%d  \n",num);
}
EXPORT_SYMBOL(show);
extern void show(void);


函数A先将show() 函数导出,函数B 使用extern 对其声明,要注意:

a -- 编译a模块后,要将 Module.symvers 拷贝到b模块下

b -- 然后才能编译b模块

c -- 加载:先加载a模块,再加载b模块

d -- 卸载:先卸载b模块,再卸载a模块


三、示例

代码a ,hello.c
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/module.h>  
  2.   
  3. static int num =10;  
  4. static void show(void)  
  5. {  
  6.     printk("show(),num = %d\n",num);  
  7. }  
  8. static int hello_init(void)  
  9. {  
  10.     printk("hello_init");  
  11.     return 0;  
  12. }  
  13. static void hello_exit(void)  
  14. {  
  15.     printk("hello_exit \n");  
  16. }  
  17. EXPORT_SYMBOL(show);  
  18. MODULE_LICENSE("GPL");  
  19. module_init(hello_init);  
  20. module_exit(hello_exit);  

代码b show.c
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/module.h>  
  2.   
  3. extern void show(void);  
  4.   
  5. static int show_init(void)  
  6. {  
  7.     printk("show_init");  
  8.     show();  
  9.     return 0;  
  10. }  
  11. static void show_exit(void)  
  12. {  
  13.     printk("show_exit \n");  
  14. }  
  15.   
  16. MODULE_LICENSE("GPL");  
  17.   
  18. module_init(show_init);  
  19. module_exit(show_exit);<strong>  
  20. </strong>  

编译后加载模块,卸载模块,可以用 dmesg 查看内核打印信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python的time模块和datatime模块

https://www.cnblogs.com/tkqasn/p/6001134.html

Linux 驱动开发之内核模块开发 (三)—— 模块传参

一、module_param() 定义 通常在用户态下编程&#xff0c;即应用程序&#xff0c;可以通过main()的来传递命令行参数&#xff0c;而编写一个内核模块&#xff0c;则通过module_param() 来传参。 module_param()宏是Linux 2.6内核中新增的&#xff0c;该宏被定义在include/linux…

Linux 驱动开发之内核模块开发 (二)—— 内核模块编译 Makefile 入门

一、模块的编译 我们在前面内核编译中驱动移植那块&#xff0c;讲到驱动编译分为静态编译和动态编译&#xff1b;静态编译即为将驱动直接编译进内核&#xff0c;动态编译即为将驱动编译成模块。 而动态编译又分为两种&#xff1a; a -- 内部编译 在内核源码目录内编译 b -- 外部…

Exynos4412 文件系统制作(三)—— 文件系统移植

根文件系统一直以来都是所有类Unix操作系统的一个重要组成部分&#xff0c;也可以认为是嵌入式Linux系统区别于其他一些传统嵌入式操作系统的重要特征&#xff0c;它给Linux带来了许多强大和灵活的功能&#xff0c;同时也带来了一些复杂性。我们需要清楚的了解根文件系统的基本…

Snapchat, 给年轻人要的安全感

这几天&#xff0c;Snapchat因拒绝Facebook和谷歌的收购请求而名声大噪。40亿美金的收购请求&#xff0c;并不是任何一个人都可以淡然处之的。一、关于SnapchatSnapchat由两位斯坦福大学生创办&#xff0c;在2011 年9月上线。Snapchat的主要是所有照片都有一个1到10秒的生命期&…

Exynos4412 文件系统制作(二)—— 文件系统简介

一、Linux磁盘分区和目录 Linux发行版本之间的差别很少&#xff0c;差别主要表现在系统管理的特色工具以及软件包管理方式的不同。目录结构基本上都是一样的。 Windows的文件结构是多个并列的树状结构&#xff0c;最顶部的是不同的磁盘&#xff08;分区&#xff09;&#xff0c…

python的urllib2模块

https://www.cnblogs.com/erliang/p/4063883.html https://blog.csdn.net/u014343243/article/details/49308043 https://docs.python.org/zh-cn/2.7/library/urllib2.html

Python中的yield

《python中yield的用法详解——最简单&#xff0c;最清晰的解释》 https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/ https://www.runoob.com/w3cnote/python-yield-used-analysis.html

Exynos4412 内核移植(七)—— 内核相关知识补充

一、内核调试方法简单分析 1、addr2line: 解决oops错误 a -- oops消息 oops&#xff08;也称 panic&#xff09;&#xff0c;称程序运行崩溃&#xff0c;程序崩溃后会产生oops消息。应用程序或内核线程的崩溃都会产生oops消息&#xff0c;通常发生oops时&#xff0c;系统不会发…

MM引擎新应用——爱车加油记

基于MM应用引擎开发的EXTJS应用&#xff0c;车主每次加完汽油后&#xff0c;记录加油时的里程数以及加油金额和汽油价格&#xff0c;就可计算出上次加油后行驶的里程数、上次加油的平均油耗。点击刷新按钮&#xff0c;即可计算有记录以来的行驶公里数和再次期间加油金额和平均油…

Python风格

Python3学习之Python风格指南 PEP8 – Python代码样式指南&#xff08;中文版&#xff09;

### 阅读之痕-2013/11

2019独角兽企业重金招聘Python工程师标准>>> 阅读之痕-2013/11 Andy erpingwugmail.com 2013/11/01-2013/11/30 2013/11/01-2013/11/30 The story of rocksdb - Embedded key-value store for Flash and RAM http://rocksdb.org/intro.pdf High Performance Network…

Exynos4412 内核移植(六)—— 设备树解析

一、描述ARM Device Tree起源于OpenFirmware (OF)&#xff0c;在过去的Linux中&#xff0c;arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码&#xff0c;相当多数的代码只是在描述板级细节&#xff0c;而这些板级细节对于内核来讲&#xff0c;不过是垃圾&#xff…

Github Page创建个人主页以及绑定域名

2019独角兽企业重金招聘Python工程师标准>>> 在github中 我们可以通过github page创建个人主页 以及绑定域名 据说有300m空间 以及无限流量 不过只能支持静态html 以及一些脚本语言 顺便吐槽一下 阿里云最低配那个云空间服务器 512m内存 启动web服务器后 mys…

python基础-类

实例属性和类属性 类中&#xff0c;没有self指定的是类属性&#xff0c;有self指定的是实例属性。类中的方法是类属性。 类和实例都是名字空间。类是类属性的名字空间&#xff0c;实例时实例属性的名字空间。 可以通过类访问类属性&#xff0c;通过实例访问实例属性。如果实例…

Exynos4412 内核移植(五)—— 驱动的移植

以移植自己制作的驱动&#xff0c;学习内核移植中的驱动移植&#xff0c;及 驱动程序的动态编译和静态编译 硬件环境&#xff1a; Linux 内核版本&#xff1a;Linux 3.14 主机&#xff1a;Ubuntu 12.04发行版 目标机&#xff1a;FS4412平台 交叉编译工具&#xff1a;arm-none-l…

FTP文件共传输服务

FTP文件共传输服务一&#xff0c;vsftpd服务基础&#xff08;1&#xff09;&#xff0c;FTP服务概述FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;是典型的C/S结构的应用层协议&#xff0c;需要由服务端软件、客户端软件共同实现文件传达输功能…

python基础-super

Super返回的是mro列表中的下一个类 python的super详解(二) 文档解释顺序MRO用于在祖先类中查找属性。每个定义的类&#xff0c;都有一个名为__mro__的属性&#xff0c;他是一个元组。 super(type[, ojb]) 给出type&#xff0c;super()返回type的父类。如果希望父类被绑定&#…

Exynos4412 内核移植(四)—— MMU 相关知识解析

一、MMU的产生 许多年以前&#xff0c;当人们还在使用DOS或是更古老的操作系统的时候&#xff0c;计算机的内存还非常小&#xff0c;一般都是以K为单位进行计算&#xff0c;相应的&#xff0c;当时的程序规模也不大&#xff0c;所以内存容量虽然小&#xff0c;但还是可以容纳当…