原文地址:http://blog.chinaunix.net/uid-24631445-id-3423408.html
仅仅是对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定义的两个函数哪个先执行呢?与其编译顺序有关,哪个先编译,哪个先链接。
参考:
阅读(984) | 评论(0) | 转发(0) |