源代码:
<include/linux/moudule.h>
…….
#ifndef MODULE_SYMBOL_PREFIX
#define MODULE_SYMBOL_PREFIX ""
#endif
…….
struct kernel_symbol //内核符号结构
{
unsignedlong value; //该符号在内存地址中的地址
constchar *name; //该符号的名称
};
……
#define __EXPORT_SYMBOL(sym,sec) \
externtypeof(sym) sym; \
__CRC_SYMBOL(sym,sec) \
staticconst char __kstrtab_##sym[] \
__attribute__((section(“__ksymtab_strings”),aligned(1))) \
=MODULE_SYMBOL_PREFIX#sym; \
staticconst struct kernel_symbol __ksymtab_##sym \
__used \
__attribute__((section(“__ksymatab”sec),unused)) \
={(unsignedlong)&sym,_kstrab_#sym}
#define EXPORT_SYMBOL(sym) \
__EXPOTR_SYMBOL(sym,””)
#define EXPORT_SYMBOL_GPL(sym) \
__EXPOTR_SYMBOL(sym,”_gpl”)
#define EXPORT_SYMBOL(sym) \
__EXPOTR_SYMBOL(sym,”_gpl_future”)
1、预备知识:
在分析前,先了解如下相关知识:
(1)#运算符,##运算符
通常在宏定义中使用#来创建字符串 #abc就表示字符串”abc”等。
##运算符称为预处理器的粘合剂,用来替换粘合两个不同的符号,
如:#definexName (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、代码分析:
举例说明:若要导出内核符号(内核函数)myfc,
如调用 EXPORT_SYMBOL(myfc)
展开为 __EXPORT_SYMBOL(myfc,””)
展开为
static const char __kstrtab_myfc[] __attribute__((section(“__ksymtab_strings”),aligned(1)))
=MODULE_SYMBOL_PREFIX myfc;
static const struct kernel_symbol __ksymtab_myfc
__used
__attribute__((section(“__ksymatab”),unsed))
={(unsigned long)&sym,_kstrab_myfc}
由前面可知__attribute__是gcc中的属性(__used也是gcc属性),用于向指定的函数或者变量添加相关的属性,为了不影响对变量定义的理解,先将__attribute__属性掩盖,则上面的定义变为:
static const char __kstrtab_myfc[] =” myfc”;
static const struct kernel_symbol__ksymtab_myfc={(unsigned long)&myfc,_kstrab_myfc};
//定义了一个字符数组__kstrtab_myfc[]用于存放导出的符号名myfc
//定义了一个内核符号结构__ksymtab_myfc用于存放引出符号myfc在内存中的地址和名称。
添加了__attribute__属性后,则表示:
将字符数组__kstrtab_myfc[]放置到一个名为“__ksymtab_strings”的section中。
将内核符号结构__ksymtab_myfc放置到一个名为”__ksymatab”的section中。
若是调用了EXPORT_SYMBOL_GPL(myfc),则对应的内核符号结构被放置到名 为”__ksymatab_gpl”的section中。
3、总结:在内核符号导出中,调用了EXPORT_SYMBOL(sym),则会完成以下操作:
(1) 定义一个字符数组存放内核导出符号的名称,并放置到“__ksymtab_strings”的section中。
(2) 定义一个内核符号结构用于存放导出符号的内存地址和名称,并放置到”__ksymatab”中。
即通过EXPORT_SYMBOL(sym)告诉了内核以外的世界关于这个符号的两点信息:内核符号的名称和其内存地址。
Linux内核导出符号宏定义EXPORT_SYMBOL的源码分析