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

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扩展软件包
关注我们
st-img 微信公众号
st-img 手机版