/*本文由真胖子同志私人定制,烦请转载保留来源http://blog.csdn.net/figtingforlove/article/details/20155485*/
内核模块不但可以使用内核和其他模块导出的符号,还可以向外部导出自己的符号。如果一个模块向外界导出符号,那么模块的编译工具链将负责生成这写导出符号的section(都带有SHF_ALLOC标志),所以在模块的加载过程中会被搬移到CORE section区域。
(1) 导出符号的定义
内核用structkernel_symbol来表示一个内核符号的实例
19 struct kernel_symbol
20 {
21 unsigned long value; //该符号在内存中的地址
22 const char *name; //符号名
23 };
内核导出符号的宏定义
48 /* For every exported symbol, place a struct in the __ksymtab section */
49 #define __EXPORT_SYMBOL(sym, sec) \
50 extern typeof(sym) sym; \
51 __CRC_SYMBOL(sym, sec) \
52 static const char __kstrtab_##sym[] \
53 __attribute__((section("__ksymtab_strings"), aligned(1))) \
54 = MODULE_SYMBOL_PREFIX #sym; \
55 static const struct kernel_symbol __ksymtab_##sym \
56 __used \
57 __attribute__((section("___ksymtab" sec "+" #sym), unused)) \
58 = { (unsigned long)&sym, __kstrtab_##sym }
59
60 #define EXPORT_SYMBOL(sym) \
61 __EXPORT_SYMBOL(sym, "")
从源码可以看出,EXPORT_SYMBOL实际上就是定义了两个变量,一个char指针表示符号名,一个stuct kernel_symbol表示一个导出符号。
看一个例子EXPORT_SYMBOL(my_exp_function)
static const char__kstrtab_my_exp_function = “my_exp_function”;
static const struct kernel_symbol__ksymtab_ my_exp_function = { (unsigned long)& my_exp_function,__kstrtab_ my_exp_function };
实际上内核就是通过一个stuct kernel_symbol对象来向外界表示关于这个符号的两个信息:符号名称和地址。
上面的__kstrtab_my_exp_function会被放在“__ksymtab_strings”段,__ksymtab_ my_exp_function会被放在“__ksymtab”段中,也就是导出符号字符串表段和导出符号表段。而在对这些段的使用需要经过一个中间环节,及链接脚本和链接器部分,下面看一个具体的链接脚本的例子
Linux/include/asm-generic/vmlinux.lds.h
1 #ifndef LOAD_OFFSET
2 #define LOAD_OFFSET 0
3 #endif
4
5 #ifndef VMLINUX_SYMBOL
6 #define VMLINUX_SYMBOL(_sym_) _sym_
7 #endif
60 /* Kernel symbol table: Normal symbols */ \
61 __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
62 VMLINUX_SYMBOL(__start___ksymtab) = .; \
63 *(__ksymtab)