仅仅是对do_initcalls及相关的简单介绍,因为深入的还不懂。
1:函数do_initcalls
- typedef int (*)(void);
- extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
- static void __init do_initcalls(void)
- {
- initcall_t *call;
- for (call = __early_initcall_end; call < __initcall_end; call++)
- do_one_initcall(*call);
- /* Make sure there is no pending stuff from the initcall sequence */
- flush_scheduled_work();
- }
do_one_initcall就是执行了call指针指向的函数。
2:/arch/x86/kernel/vmlinux.lds.S文件
大概意思是这样的。(我不确定是不是对的)
内核各个子系统有大量源代码,进行make之后会编译出相应的.o文件和.ko文件,还有vmlinux文件。
在生成vmlinux文件之前需要进行链接,即将其他.o文件中的函数链接进去。
而vmlinux.lds.S这个汇编代码就是用来做链接这项工作的?
(嗯?..... 总觉有点奇怪? gcc不是就链接工具吗?怎么还得自己链接?这里的链接和通常的ld链接有什么区别?)
(由于我的电脑是x86体系结构的,因此我是看的/arch/x86目录,其他体系结构,自己去找目录看)
这个文件里调用了宏: INIT_DATA_SECTION(16)
这个宏在include/asm-generic/vmlinux.lds.h头文件中定义,这个宏里面调用了宏 INIT_CALLS,而INIT_CALLS宏里面又调用了INITCALLS
下面是INITCALLS宏
- #define INITCALLS \
- *(.initcallearly.init) \
- VMLINUX_SYMBOL(__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)
首先观察下,排列整齐,也看到了__early_initcall_end,没看到__initcall_start和__initcall_end,这两个是在INIT_CALLS中定义的。
3:include/linux/init.h文件
这里没定义了一些列的initcall宏,如subsys_initcall,device_initcall等等
- #define __define_initcall(level,fn,id) \
- static initcall_t __initcall_##fn##id __used \
- __attribute__((__section__(".initcall" level ".init"))) = fn
- /*
- * Early initcalls run before initializing SMP.
- *
- * Only for built-in code, not modules.
- */
- #define early_initcall(fn) __define_initcall("early",fn,early)
- /*
- * A "pure" initcall has no dependencies on anything else, and purely
- * initializes variables that couldn't be statically initialized.
- *
- * This only exists for built-in code, not for modules.
- */
- #define pure_initcall(fn) __define_initcall("0",fn,0)
- #define core_initcall(fn) __define_initcall("1",fn,1)
- #define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
- #define postcore_initcall(fn) __define_initcall("2",fn,2)
- #define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
- #define arch_initcall(fn) __define_initcall("3",fn,3)
- #define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
- #define subsys_initcall(fn) __define_initcall("4",fn,4)
- #define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
- #define fs_initcall(fn) __define_initcall("5",fn,5)
- #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
- #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
- #define device_initcall(fn) __define_initcall("6",fn,6)
- #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
- #define late_initcall(fn) __define_initcall("7",fn,7)
- #define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
- #define __initcall(fn) device_initcall(fn)
- #define module_init(x) __initcall(x);
明显关键在于__define_initcall,这个宏里面有一句:
__attribute__((__section__(".initcall" level ".init")))
关于__attribute__及参数__section__的作用可以参考gcc的manual。
大致意思是说“通常情况下,gcc将代码生成到text section中,有些时候如果你需要特定的函数处于特定的section,那就可用__section__属性来指定“
注意level是个字符串,以subsys_initcall为例,subsys_initcall(pci_subsys_init)宏展开后得到的东西是:
static initcall_t __initcall_pci_subsys_init4 __used __attribute__((__section__(".initcall.4.init"))) = pci_subsys_init
也就是说它定义了一个类型为initcall_t的函数,而且该函数(就是__initcall_pci_subsys_init4)在编译时要放到section “.initcall.4.init"中去。
可见在宏INITCALLS中定义的这些section中放了一系列的函数,这些函数是用pure_initcall,core_initcall之类宏定义的,
而且pure_initcall定义的initcall函数放在.initcall.0.init中,而core_initcall定义的initcall函数放在.initcall.1.init中,
因此pure_initcall定义的函数要比core_initcall定义的先执行。
那么同样使用core_initcall定义的两个函数哪个先执行呢?与其编译顺序有关,哪个先编译,哪个先链接。
参考:
阅读(2743) | 评论(0) | 转发(0) |