|
[导读] 写驱动时,常常遇到EXPORT_SYMBOL,这究竟做了啥,对于做底层开发而言,了解其内在实现机制,对于开发还是很有益的。本文就来剖析一下其内在实现机制及其作用。从本文开始,将开始不定期更新阅读内核代码的笔记,内核代码庞大,且限于水平,如发现错误,文末开了个小程序留言功能进行讨论,真诚欢迎讨论交流。让我们一起来阅读内核代码吧~~~ 概要介绍内核代码中几个常见用于导出符号的宏为: #define EXPORT_SYMBOL(sym)#define EXPORT_SYMBOL_GPL(sym) #define EXPORT_SYMBOL_GPL_FUTURE(sym) #define EXPORT_UNUSED_SYMBOL(sym) #define EXPORT_UNUSED_SYMBOL_GPL(sym) 其作用分别为:
以内核调度器举例,先不关心函数内部实现细节。 asmlinkage __visible void __sched schedule(void){ struct task_struct *tsk = current; sched_submit_work(tsk); do { preempt_disable(); __schedule(false); sched_preempt_enable_no_resched(); } while (need_resched()); } EXPORT_SYMBOL(schedule); 其中:EXPORT_SYMBOL 宏定义为: #define EXPORT_SYMBOL(sym) \__EXPORT_SYMBOL(sym, "") 而__EXPORT_SYMBOL 的宏定义为: #define __EXPORT_SYMBOL(sym, sec) \extern typeof(sym) sym; \ __CRC_SYMBOL(sym, sec) \ static const char __kstrtab_##sym[] \ __attribute__((section("__ksymtab_strings"), aligned(1))) \ = VMLINUX_SYMBOL_STR(sym); \ extern const struct kernel_symbol __ksymtab_##sym; \ __visible const struct kernel_symbol __ksymtab_##sym \ __used \ __attribute__((section("___ksymtab" sec "+" #sym), unused)) \ = { (unsigned long)&sym, __kstrtab_##sym } 而__CRC_SYMBOL的宏定义为: #define __CRC_SYMBOL(sym, sec) \extern __visible void *__crc_##sym __attribute__((weak)); \ static const unsigned long __kcrctab_##sym \ __used \ __attribute__((section("___kcrctab" sec "+" #sym), unused)) \ = (unsigned long) &__crc_##sym; 这里还有个VMLINUX_SYMBOL_STR宏,其定义如下: /* Some toolchains use a `_' prefix for all user symbols. */#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX #define __VMLINUX_SYMBOL(x) _##x #define __VMLINUX_SYMBOL_STR(x) "_" #x #else #define __VMLINUX_SYMBOL(x) x #define __VMLINUX_SYMBOL_STR(x) #x #endif #define VMLINUX_SYMBOL_STR(x) __VMLINUX_SYMBOL_STR(x) 假定CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX定义了,则全部展开为:
那么全部展开后,得到了什么呢? extern typeof(schedule) schedule; \extern __visible void *__crc_schedule __attribute__((weak)); \ static const unsigned long __kcrctab_schedule \ __used \ __attribute__((section("___kcrctab" sec "+" "schedule"), unused)) \ = (unsigned long) &__crc_schedule; static const char __kstrtab_schedule[] \ __attribute__((section("__ksymtab_strings"), aligned(1))) \ = "_" "schedule"; \ extern const struct kernel_symbol __ksymtab_schedule; \ __visible const struct kernel_symbol __ksymtab_schedule \ __used \ __attribute__((section("___ksymtab" sec "+" "schedule"), unused)) \ = { (unsigned long)&schedule, __kstrtab_schedule }; 这样还是不直观,去掉不必要的换行符,整理一下: asmlinkage __visible void __sched schedule(void){ struct task_struct *tsk = current; sched_submit_work(tsk); do { preempt_disable(); __schedule(false); sched_preempt_enable_no_resched(); } while (need_resched()); } /*以下部分都属于EXPORT_SYMBOL(schedule)的展开*/ extern typeof(schedule) schedule; extern __visible void *__crc_schedule __attribute__((weak)); static const unsigned long __kcrctab_schedule __used \ __attribute__((section("___kcrctab" sec "+" "schedule"), unused)) \ = (unsigned long) &__crc_schedule; static const char __kstrtab_schedule[] __attribute__((section("__ksymtab_strings"), aligned(1))) = "_" "schedule"; extern const struct kernel_symbol __ksymtab_schedule; __visible const struct kernel_symbol __ksymtab_schedule __used __attribute__((section("___ksymtab" sec "+" "schedule"), unused)) = { (unsigned long)&schedule, __kstrtab_schedule }; EXPORT_SYMBOL(schedule)展开成这么一个玩意儿,要理解其内在机制,这里涉及到了很多内核代码关键词,比如:
这个且待下回分解。 |
微信公众号
手机版