驅動程序module_init()在編譯成模塊或編譯進內核時的區別

內核版本linux-2.6.22.6

在內核目錄include/linux/init.h中會解析,是否定義了MODULE宏來區分編譯進內核還是編譯成模塊。

 

 

編譯進內核的宏展開過程

module_init(x)->__initcall(x);->device_initcall(fn)->__define_initcall("6s",fn,6s) 

#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __attribute_used__ \
__attribute__((__section__(".initcall" level ".init"))) = fn

宏展開後,驅動初始化函數就會帶有.initcall6.init屬性,那麼在其編譯時將會被安排到__initcall_start__initcall_end範圍之間(定義在arch/cpu-type/kernel/vmlinux.lds.S中),之後由init/main.c的do_initcalls()函數進行統一的初始化。

static void __init do_initcalls(void)
{
    initcall_t *call;
    ...
    for (call = __initcall_start; call < __initcall_end; call++) {
    result = (*call)();    
        }
    ...   
}

 

編譯成模塊

 

module_init(x)

#define module_init(initfn)					\
	static inline initcall_t __inittest(void)		\
	{ return initfn; }					\
	int init_module(void) __attribute__((alias(#initfn)));

int init_module(void) __attribute__((alias(#initfn)));

用來告訴編譯器將init_module作爲#initfn的別名替代#initfn。

 

比如定義了一個led_init函數

static int __init led_init(void)
{
    ......
}
......
module_init(led_init);
......

 

經過module_init(led_init);之後led_init被別名init_module取代,所以可以理解爲:

int init_module( void) //static int __init led_init( void)被編譯器幹掉了,由int init_module( void)取代
{   
   ......
}
......

 

這樣可以不用顯式的聲明init_module,而是使用更具有模塊化、人性化的名字led_init來讓人更容易理解的定義入口,之後insmod解析init_module入口執行之。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章