Linux Linker 的顺序

今天发现initramfs的产生比driver的加载早,感觉有点奇怪,仔细看了一下。


1.

init/initramfs.c

rootfs_initcall(populate_rootfs);


2.

include/linux/init.h

#define pure_initcall(fn)               __define_initcall(fn, 0)
#define core_initcall(fn)               __define_initcall(fn, 1)
#define core_initcall_sync(fn)          __define_initcall(fn, 1s)
#define postcore_initcall(fn)           __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
#define arch_initcall(fn)               __define_initcall(fn, 3)
#define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
#define subsys_initcall(fn)             __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
#define fs_initcall(fn)                 __define_initcall(fn, 5)
#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
#define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
#define device_initcall(fn)             __define_initcall(fn, 6)
#define device_initcall_sync(fn)        __define_initcall(fn, 6s)
#define late_initcall(fn)               __define_initcall(fn, 7)
#define late_initcall_sync(fn)          __define_initcall(fn, 7s)

这样看来,rootfs_initcall视乎比device_init的linker顺序前面。


3.

include/asm-generic/vmlinux.lds.h

#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) = .;


$OUT/arch/arm/kernel/vmlinux.lds

__initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init)__initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;


上面是arm 平台上的linker script和结果, 果然如此啊。


4. init/main.c

 823 static initcall_t *initcall_levels[] __initdata = {
 824         __initcall0_start,
 825         __initcall1_start,
 826         __initcall2_start,
 827         __initcall3_start,
 828         __initcall4_start,
 829         __initcall5_start,
 830         __initcall6_start,
 831         __initcall7_start,
 832         __initcall_end,
 833 };       835 /* Keep these in sync with initcalls in include/linux/init.h */
 836 static char *initcall_level_names[] __initdata = {
 837         "early",
 838         "core",
 839         "postcore",
 840         "arch",
 841         "subsys",
 842         "fs",
 843         "device",
 844         "late",
 845 };
 846 
 847 static void __init do_initcall_level(int level)
 848 {
 849         initcall_t *fn;
 850        
 851         strcpy(initcall_command_line, saved_command_line);
 852         parse_args(initcall_level_names[level],
 853                    initcall_command_line, __start___param,
 854                    __stop___param - __start___param,
 855                    level, level,
 856                    NULL, &repair_env_string);
 857                        
 858         for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
 859                 do_one_initcall(*fn);
 860 }       

 861                        
 862 static void __init do_initcalls(void)
 863 {
 864         int level;
 865 
 866         for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
 867                 do_initcall_level(level);
 868 }
 869                

 虽然__initcallrootfs_start没有出现在initcall_levels的数组里,但这个不妨碍它的

执行,它比__initcall5_start大,比__initcall6_start小,所以,当__initcall5里的

都执行完后,__initcallrootfs段的函数就开始执行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值