你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

EXPORT_SYMBOL的内在实现机制及其作用

[复制链接]
gaosmile 发布时间:2020-4-10 10:05
[导读] 写驱动时,常常遇到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)

其作用分别为:
  • EXPORT_SYMBOL:导出一般符号,用于使内部符号变成可加载模块。可加载模块的含义是可以通过命令insmod 动态加载内核模块。
  • EXPORT_SYMBOL_GPL:导出只兼容GPL License的符号,这些符号仅对具有GPL兼容许可证的模块可用。GPL-only符号的可能意图:
  • 已有符号,限定使用该符号的模块都只能是内核的派生产品。
  • 对于新创建的符号,其创建者可以通过这个机制限定其仅适用于GPL。
  • EXPORT_SYMBOL_GPL_FUTURE ,其目的是标记将来可能被更改为GPL-only导出的符号。如果非GPL模块使用了此类符号,则内核将发出警告,表明该模块将在将来的某个时间中断。幸运的是,这些警告将帮助专有模块的作者提前为更改做好准备。
  • EXPORT_UNUSED_SYMBOL, EXPORT_UNUSED_SYMBOL_GPL这两个基本没用,估计是预留接口。

以内核调度器举例,先不关心函数内部实现细节。
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定义了,则全部展开为:
微信图片_20200410100409.png

那么全部展开后,得到了什么呢?
    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)展开成这么一个玩意儿,要理解其内在机制,这里涉及到了很多内核代码关键词,比如:
  • asmlinkage
  • __visible
  • extern typeof(schedule) schedule
  • kernel_symbol
  • ……

这个且待下回分解。
收藏 评论0 发布时间:2020-4-10 10:05

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版