初始化與退出函數:
module_init(dm9000_init);
module_exit(dm9000_cleanup);
其實是宏定義,在模塊執行時告訴內核初始化函數和去初始化的位置讓其執行初始化和退出操作。
目前linux支持兩種方式運行設備驅動,一種是built-in kernel,另一種module。
module_init(x) 相關宏定義:
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
typedef int (*initcall_t)(void);
把上面的宏變換展開:
Static initcall_t __initcall_dm9000_init_6 __used __attribute__((__section__(“.initcall” 6 “.init”)))=dm9000_init
其實是定義了一個Static initcall_t類型的函數指針__initcall_dm9000_init_6
這裡我們需要了解一下gcc的__attribute__機制,是在編譯的過程中告訴編譯器該函數一些屬性,__attribute__((__section__(“.initcall” 6 “.init”)))意思是把函數放入“.initcall” 6 “.init” 段中,然後把dm9000_init賦值給它。
__used也是一個__attribute__相關宏:
#if __GNUC_MINOR__ >= 3
# define __used __attribute__((__used__))
#else
# define __used __attribute__((__unused__))
#endif
http://gcc.gnu.org/onlinedocs/gcc-4.3.2//gcc/Function-Attributes.html
中關於used與unused有解釋,__attribute__修飾的函數或變量可能使用/不使用,可以避免編譯器產生告警。
結合vmlinux.lds中的
.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
__initcall_start = .;
*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;
}
系統啟動時
start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()
do_initcalls:
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++)
do_one_initcall(*call);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
按如下宏展開:
/* Each module must use one module_init(). */
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
static inline exitcall_t __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __attribute__((alias(#exitfn)));
在用insmod加載模塊時會調用模塊的init函數.