注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

Linux内核中的xx_initcall  

2011-10-10 14:53:03|  分类: Linux内核 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本文编辑整理自:http://www.linuxidc.com/Linux/2011-09/43354.htm
先看这些宏的定义(定义在文件include/linux/init.h中)
#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(),再看看它的定义(同样定义在文件include/linux/init.h中)
#define __define_initcall(level,fn,id) \   
        static initcall_t __initcall_##fn##id __used \  
        __attribute__((__section__(".initcall" level ".init"))) = fn
这其中initcall_t是函数指针,原型如下,
typedef int (*initcall_t)(void);  
而编译器宏 __attribute__((__section__())) 则表示把对象放在一个这个由括号中的名称所指代的section中。
__define_initcall("6",fn,6) 则是把fn的地址放到.initcall6.init这个selection中
另外,注意这里static的作用,只是当前编译单元可见,从全局来看的__initcall_##fn##id完整名字,是要加当前编译文件名(或称当前编译单位名)作为前缀的
所以__define_initcall的含义是:
1) 声明一个名称为__initcall_##fn的函数指针;
2) 将这个函数指针初始化为fn;
3) 编译的时候需要把这个函数指针变量放置到名称为 ".initcall" level ".init"的section中
明确了__define_initcall的含义,就知道了它其实是分别将这些初始化标号修饰的函数指针放到各自的section中的。
SECTION“.initcalllevel”.init”被放入INITCALLSinclude/asm-generic/vmlinux.lds.h)
#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)  
VMLINUX_SYMBOL(__early_initcall_end) = .;  这里的 .是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置(或某section内的偏移,如果它在SECTIONS命令内的某section描述内),该符号只能在SECTIONS命令内使用。
这句命令的意思,是对__early_initcall_end变量赋值为当前section内的偏移
*(.initcall7s.init表示的是所有输入文件中的名为.initcall7s.initSECTIONS
__initcall_start__initcall_end以及INITCALLS中定义的SECTION都是在arch/xxx/kernel/vmlinux.lds.S中放在.init段的。
SECTIONS  
{  
        .init : {  
                __initcall_start = .;  
                        INITCALLS  
                __initcall_end = .;  
        }  
.init只是用于对SECTIONS进行分类  
 __initcall_start = .;  __initcall_end = .;  表示分别对变量 __initcall_start__initcall_end 赋值为当前section内的偏移。
而这些SECTION里的函数在初始化时被顺序执行(init内核线程->do_basic_setup()[main.c#778]->do_initcalls())。
程序(init/main.c文件do_initcalls()函数)如下,do_initcalls()XX.initcallXX.init中的函数按顺序都执行一遍。
for (call = __early_initcall_end; call < __initcall_end; call++)  
        do_one_initcall(*call);  
关于SECTION的更多内容请参考《Linux下的lds链接脚本简介

  评论这张
 
阅读(919)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017