注意:使用的內核源碼版本為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先執行