当前位置: 首页 > 科技观察

linux内核如何访问另一个模块的函数和变量

时间:2023-03-15 20:36:00 科技观察

1.问题内核中有两个模块,一个A,一个B,模块A中有操作函数,模块B需要调用的函数moduleA.2.分析这是一个驱动工程师经常遇到的问题。这个问题其实是模块符号导出的问题。实现这个功能比较简单,用EXPORT_SYMBOL()就可以了。1、什么是符号?这里的符号主要是指全局变量和函数。静态全局变量实际上可以被另一个模块访问。2、为什么要导出符号?↓Linux内核以模块化的形式管理内核代码。内核中的每个模块都是相互独立的,也就是说模块A的全局变量和函数是不能被模块B直接访问的。有时候,我们在写一些模块代码的时候,会发现有些功能已经被模块B实现了其他的。这个时候我们就想如果能调用他们实现的函数接口就好了。那么如何做到这一点呢?它依赖于符号的导出,也就是说,你可以将你实现的函数接口和全局变量导出,供其他模块使用。在Linux内核的世界里,如果一个模块已经被静态编译进内核,那么它??导出的符号就会出现在全局内核符号表中。在Ubuntu14.04系统中,Linux内核的全局符号表存放在如下文件中:/usr/src/linux-headers-3.2.0-29-generic-pae/Module.symvers打开这个文件,你可以发现里面的内容是:Addr------>symbolname------>modulename------>exportsymbolmacro3.如何导出符号?Linux内核为我们提供了两个宏:EXPORT_SYMBOL(name);EXPORT_SYMBOL_GPL(名称);上述任何一个宏定义都使得给定的符号在模块外可用;GPL版本的宏定义只能使符号对GPL许可的模块可用;该符号必须在模块文件的全局部分导出,在任何函数之外,因为宏定义扩展为预期可全局访问的特殊用途变量的声明。4.如何找到编译模块时使用的符号?A。在该模块的符号表中,找到符号(函数或变量实现)b.在内核全局符号表中查找c。在模块目录下的Module.symvers文件中找到5.案例演示模块A导出全局变量global_var,函数显示两个符号供模块B使用。模块#include#includestaticintglobal_var=100;staticvoidshow(void){printk("show():global_var=%d\n",global_var);}staticinthello_init(void){printk("moduleb:global_var=%d\n",global_var);return0;}staticvoidhello_exit(void){printk("hello_exit\n");return;}EXPORT_SYMBOL(global_var);EXPORT_SYMBOL(show);MODULE_AUTHOR("yikoulinux");MODULE_LICENSE("GPL");module_init(hello_init);module_exit(hello_exit);B模块#include#includeexternintglobal_var;externvoidshow(void);staticinthello_init(void){printk("modulea:global_var=%d\n",global_var);show();return0;}staticvoidhello_exit(void){printk("hello_exit\n");return;}MODULE_AUTHOR("yikoulinux");MODULE_LICENSE("GPL");module_init(hello_init);module_exit(hello_exit);调试步骤:1.编译模块A,然后加载模块A,模块A编译完成后,会在其当前目录下看到一个Module的.symvers文件,它存储了我们的模块A导出的符号。2、将模块A编译生成的Module.symvers文件复制到模块B的目录下,然后编译模块B,加载模块B。3、通过dmesg查看模块打印的信息。打印信息如下:从结果可以看出,我们在模块B中访问了全局变量global_var和模块A的函数show。