查看linux/export.h文件:
struct kernel_symbol //内核符号结构
{
unsigned long value; //该符号在内存地址中的地址
const char *name; //该符号的名称
};
预备知识:
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中。
示例分析:如调用EXPORT_SYMBOL(myfc)
展开为__EXPORT_SYMBOL(myfc," ")
继续展开为:
static const char __kstrtab_myfc[]
__attribute__((section("__ksymtab_strings"), aligned(1))) \
= VMLINUX_SYMBOL_STR(myfc);
static const struct kernel_symbol __ksymtab_myfc \
__used \
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
= { (unsigned long)&sym, __kstrtab_myfc }
定义了一个字符数组__kstrtab_myfc[]用于存放导出的符号名myfc。
定义了一个内核符号结构__ksymtab_myfc用于存放引出符号myfc在内存中的地址和名称
总结: 在内核符号导出中,调用了EXPORT_SYMBOL(sym), 则会完成以下操作:
(1) 定义一个字符数组存放内核符号的名称,并放置到"__ksymtab_strings"的section中.
(2)定义一个内核符号结构用于存放导出符号的内存地址和名称,并放置到"__ksymatab"中.
即通过EXPORT_SYMBOL(sym)先放了内核以外的世界关于这个符号两点信息: 内核符号的名称和其内存地址.