Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3167639
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-09-05 10:29:59

原文地址:http://blog.chinaunix.net/uid-24631445-id-3423408.html

仅仅是对do_initcalls及相关的简单介绍,因为深入的还不懂。

1:函数do_initcalls

  1. typedef int (*)(void);

  2. extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

  3. static void __init do_initcalls(void)
  4. {
  5.     initcall_t *call;

  6.     for (call = __early_initcall_end; call < __initcall_end; call++)
  7.         do_one_initcall(*call);

  8.     /* Make sure there is no pending stuff from the initcall sequence */
  9.     flush_scheduled_work();
  10. }
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宏

  1. #define INITCALLS                            \
  2.     *(.initcallearly.init)                        \
  3.     VMLINUX_SYMBOL(__early_initcall_end) = .;            \
  4.       *(.initcall0.init)                        \
  5.       *(.initcall0s.init)                        \
  6.       *(.initcall1.init)                        \
  7.       *(.initcall1s.init)                        \
  8.       *(.initcall2.init)                        \
  9.       *(.initcall2s.init)                        \
  10.       *(.initcall3.init)                        \
  11.       *(.initcall3s.init)                        \
  12.       *(.initcall4.init)                        \
  13.       *(.initcall4s.init)                        \
  14.       *(.initcall5.init)                        \
  15.       *(.initcall5s.init)                        \
  16.     *(.initcallrootfs.init)                        \
  17.       *(.initcall6.init)                        \
  18.       *(.initcall6s.init)                        \
  19.       *(.initcall7.init)                        \
  20.       *(.initcall7s.init)
首先观察下,排列整齐,也看到了__early_initcall_end,没看到__initcall_start和__initcall_end,这两个是在INIT_CALLS中定义的。


3:include/linux/init.h文件
这里没定义了一些列的initcall宏,如subsys_initcall,device_initcall等等

  1. #define __define_initcall(level,fn,id) \
  2.     static initcall_t __initcall_##fn##id __used \
  3.     __attribute__((__section__(".initcall" level ".init"))) = fn

  4. /*
  5.  * Early initcalls run before initializing SMP.
  6.  *
  7.  * Only for built-in code, not modules.
  8.  */
  9. #define early_initcall(fn)        __define_initcall("early",fn,early)

  10. /*
  11.  * A "pure" initcall has no dependencies on anything else, and purely
  12.  * initializes variables that couldn't be statically initialized.
  13.  *
  14.  * This only exists for built-in code, not for modules.
  15.  */
  16. #define pure_initcall(fn)        __define_initcall("0",fn,0)

  17. #define core_initcall(fn)        __define_initcall("1",fn,1)
  18. #define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)
  19. #define postcore_initcall(fn)        __define_initcall("2",fn,2)
  20. #define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
  21. #define arch_initcall(fn)        __define_initcall("3",fn,3)
  22. #define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)
  23. #define subsys_initcall(fn)        __define_initcall("4",fn,4)
  24. #define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
  25. #define fs_initcall(fn)            __define_initcall("5",fn,5)
  26. #define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
  27. #define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)
  28. #define device_initcall(fn)        __define_initcall("6",fn,6)
  29. #define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
  30. #define late_initcall(fn)        __define_initcall("7",fn,7)
  31. #define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)

  32. #define __initcall(fn) device_initcall(fn)

  33. #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) |
给主人留下些什么吧!~~