linux内核中的subsys_initcall是干什么的?

注意:使用的内核源码版本为5.1.3

1. subsys_initcall长什么样子?

  它其实是个宏定义,定义如下:

    #define subsys_initcall(fn)     __define_initcall(fn, 4) (注意,这是使用在内置模块中的)

    或

     #define subsys_initcall(fn)     module_init(fn) (注意,这是使用在可加载模块中的)

2. 进一步解剖__define_initcall

 #define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)

3. 再解剖___define_initcall

#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
#define ___define_initcall(fn, id, __sec)           \
    __ADDRESSABLE(fn)                   \
    asm(".section   \"" #__sec ".init\", \"a\"  \n" \
    "__initcall_" #fn #id ":            \n" \
        ".long  " #fn " - .         \n" \
        ".previous                  \n");
#else
#define ___define_initcall(fn, id, __sec) \
    static initcall_t __initcall_##fn##id __used \
        __attribute__((__section__(#__sec ".init"))) = fn;
#endif

4. 结合以上内容可知

 如果未定义宏CONFIG_HAVE_ARCH_PREL32_RELOCATIONS,那么subsys_initcall就被展开为:

  static initcall_t __initcall_fn4 __used \

    __attribute__((__section_(.initcall4.init))) = fn

  也就是将fn链接到段.initcall4.init中

 

5. subsys_initcall与module_init有何联系?

 5.1 先看看module_init是什么吧?

/* Each module must use one module_init(). */ (在编译为可加载模块时使用这个定义)
#define module_init(initfn)                 \
    static inline initcall_t __maybe_unused __inittest(void)        \
    { return initfn; }                  \
    int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

 

   或  

define module_init(x)  __initcall(x); (在编译为内置模块时使用这个定义)

 

 5.2 __initcall的定义是怎样的呢?

#define __initcall(fn) device_initcall(fn)

 5.3 device_initcall是怎样的呢?

#define device_initcall(fn)     __define_initcall(fn, 6)

 

  

 5.4 结论

  从以上分析可以看出:

    在编译某驱动为内置代码时,subsys_initcall与module_init仅仅是__define_initcall的第二个参数不同而已,前者使用4,后者使用6,因此归纳出仅仅是谁先被执行的差异,subsys_initcall比module_init先执行

 

 

  

    

   

posted @ 2019-06-09 23:34  Jello  阅读(7832)  评论(0编辑  收藏  举报