在Linux内核启动过程中,在init()函数执行过程中会调用do_basic_setup函数,进程调用 do_initcalls()函数,该函数实现如下:
451 static void __init do_initcalls(void)
452 {
453 initcall_t *call;
454
455 call = &__initcall_start;
456 do {
457 (*call)();
458 call++;
459 } while (call < &__initcall_end);
460
461 /* Make sure there is no pending stuff from the initcall sequence */
462 flush_scheduled_tasks();
463 }
其中,__initcall_start是段.initcall.init的起始地址,由链接脚本在编译内核时确定,而对于模块中的module_init有:
84 #define __init_call __attribute_used__ __attribute__ ((__section__ (".initcall.init")))
85 #define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
...
49 typedef int (*initcall_t)(void);
50 typedef void (*exitcall_t)(void);
51
52 extern initcall_t __initcall_start, __initcall_end;
53
54 #define __initcall(fn) \
55 static initcall_t __initcall_##fn __attribute_used__ __init_call = fn
56 #define __exitcall(fn) \
57 static exitcall_t __exitcall_##fn __exit_call = fn
...
102 #define module_init(x) __initcall(x);
可见,module_init是把定义的函数通过gcc拓展属性attribute,把函数放在了 section (“.initcall.init”))中。
而do_initcalls对该段中存放的每一个函数都通过函数指针initcall_t *call来指向,并通过(*call)()执行。