kbuild系統(tǒng)-編譯到內(nèi)核和編譯成模塊的區(qū)別
代碼編譯到內(nèi)核和編譯成模塊在代碼中有什么區(qū)別呢?
從模塊的代碼中看是一樣的。入口函數(shù)都是MODULE_init(fun),但是代碼中的條件編譯會使宏module_init()在編譯到內(nèi)核和編譯成模塊的情況下替換成不同的代碼。
include/linux/init.h中可知
#ifndef MODULE
...
#define module_init(x) __initcall(x);
...
#else /* MODULE */
...
/* Each module must use one module_init(), or one no_module_init */
#define module_init(initfn)
static inline initcall_t __inittest(void)
{ return initfn; }
int init_module(void) __attribute__((alias(#initfn)));
...
#endif
當(dāng)代碼編譯成模塊時,會定義MODULE宏,否則不會。因?yàn)樵?usr/src/linux/Makefile中可以看到
336 MODFLAGS = -DMODULE
337 CFLAGS_MODULE = $(MODFLAGS)
338 AFLAGS_MODULE = $(MODFLAGS)
這兩個變量又被export成為全局變量。所以可以知道,在編譯成模塊時,會有MODULE這個宏。
由以下代碼可以知道
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn)
085 #define __define_initcall(level,fn)
086 static initcall_t __initcall_##fn __attribute_used__
087 __attribute__((__section__(".initcall" level ".init"))) = fn
前者實(shí)際上是編譯入內(nèi)核中的.initcall6.init 這個section
而在
arch/i386/kernel/vmlinux.lds.S中可以知道:
083 __initcall_start = .;
084 .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
085 *(.initcall1.init)
086 *(.initcall2.init)
087 *(.initcall3.init)
088 *(.initcall4.init)
089 *(.initcall5.init)
090 *(.initcall6.init)
091 *(.initcall7.init)
092 }
093 __initcall_end = .;
arch/i386/kernel/vmlinux.lds.S
.initcall6.init是.initcall.init的一部分
執(zhí)行順序:
start_kernel->rest_init
系統(tǒng)啟動后在rest_init中會創(chuàng)建init內(nèi)核線程
init->do_basic_setup->do_initcalls
do_initcalls中會把.initcall.init中的函數(shù)依次執(zhí)行一遍
for (call = __initcall_start; call < __initcall_end; call++) {
...
(*call)();
...
}
于是執(zhí)行了module_init(fn)函數(shù)