书接浅尝辄止36-module init0
我们知道module_init(x)的结果是static initcall_t __initcall_x6 = x;
,并且这个变量是放在.initcall6.init
段
initcall6.init是什么?
initcall6.init
不是显式定义的,所以不能从代码中直接grep到它。这是内核的代码最麻烦的点之一,很多宏是非显式定义的,再厉害的代码工具也不能帮助你直接找到一些宏的定义,这段代码也就成了天书。
对于这种非显式定义的宏,也不是完全没有办法,我的经验是把它拆开程单独的词,再去搜索那些词,就可能找到了。
例如在kernel/include/asm-generic/vmlinux.lds.h中有如下定义
#define INIT_CALLS_LEVEL(level) \
VMLINUX_SYMBOL(__initcall##level##_start) = .; \
*(.initcall##level##.init) \
*(.initcall##level##s.init) \
INIT_CALLS_LEVEL(6)
展开就是
VMLINUX_SYMBOL(__initcall6_start) = .; \
*(.initcall6.init) \
*(.initcall6s.init) \
至少.initcall6.init
出现了。就在这个define的下面,还有
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
*(.initcallearly.init) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
VMLINUX_SYMBOL(__initcall_end) = .;
VMLINUX_SYMBOL
关于VMLINUX_SYMBOL
,我们就按照下面最简单的版本理解好了。
#define __VMLINUX_SYMBOL(x) x
#define VMLINUX_SYMBOL(x) __VMLINUX_SYMBOL(x)
*(.initcall6.init)
*(.initcall6.init)
这个写法在比较新的版本中会写成KEEP(*(.initcall6.init))
,意思是告诉编译器将局部符号包含在目标文件的符号表中,我理解是__initcall6_start
与.initcall6.init
等价。
且听下回分解……