在解释initcall调用顺序, 先要理一下编译链接的知识.

  每个.o文件都有自己的代码段, 数据段(存放初始化的全局变量), bss段(即未初始化的数据段) 在ld链接器将各.o文件的代码段和数据段组织在一起. 一般把各段都放在一起, 如代码段都放在一起:

  .text :  { *(.text)};
  这样各.o文件的代码段都会放在一起.放的顺序是按ld后面接着的文件顺序.如ld a.o b.o

作为链接的结果要有一个入口,由entry标示.entry标示的入口一般在代码段里, 如
ENTRY(_start)
在代码段里
.text : {
_start = .;
}

对于链接器,输入文件是各.o文件,输出文件是可执行文件,输入文件按段(section)来组织.section有几个重要组成部分,一是. 这个把当前地址重新定位,即可执行文件在内存中运行的位置,一般vmlinux.lds.S把.定义为0x300000000+0x800,即3G偏下的0x800位置,对于1G物理内存是这样的,在6795平台,因为是2G内存,初设置为其他值. 

链接脚本也是一种语言,需要稍微了解一下.整个脚本的最终目的是对最终可执行文件在内存各代码段等的合理布局.也有一些说明,如对这个文件指明是在arm体系上运行, 就用OUTPUT_ARCH(arm).

/DISCARD/ 表示符合条件的输入段,都不会输出到输出的可执行文件中

不想当架构师的不是好程序员
关于链接脚本的详细语法,参见: http://www.cnblogs.com/china_blue/archive/2010/04/07/1705976.html
----------
下面来说说initcall调试顺序. 
链接脚本文件也像c语言一样,可以包含.h文件.
在6795中,vmlinux.lds.s inicall部分通过引用.h文件中的INIT_CALLS来完成init.data段的定义. 如下
kernel-3.0/arch/arm/kernel/vmlinux.lds.s
.init.data : {
#ifndef CONFIG_XIP_KERNEL
INIT_DATA
#endif
INIT_SETUP(16)
INIT_CALLS
CON_INITCALL
SECURITY_INITCALL
INIT_RAM_FS
}
INIT_CALLS在kernel-3.0/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) = .;

#define INIT_CALLS_LEVEL(level) \
VMLINUX_SYMBOL(__initcall##level##_start) = .; \
*(.initcall##level##.init) \
*(.initcall##level##s.init) \

#define VMLINUX_SYMBOL(x) x

##一般只用在宏定义中,将两个字串与替换者连在一起,组成一个新的字符串. 
INIT_CALLS最终被替换为: 

__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)
......

__initcallx_start 地址会被依次定义,这个地址在do_initcalls()时依次遍历.编号越小,越在内存布局中靠前的位置,越被先遍历到.
内核的各.o文件init函数会被定义为initcallx.init这样的函数. 这个编号决定了这个init被调用的时间.可以按时间先后,依次列为第0时间,第1时间,第2时间...
内核中各init函数如何被定义为initcallx.init函数.以常见的module_init为例.

#define module_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn) __define_initcall(fn, 6)

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

以ltr559.c为例,
这样module_init(ltr559_init)最终定义为:
static initcall_t __initcall_ltr559_init6 __used
__attribute__((__section__(".initcall6.init"))) = ltr559_init

__attribute__((__section__(".initcall6.init") 告诉编译器把ltr559_init放在名为.initcall6.init代码段中. 
即所有传入module_init所有初始化函数都会放在.initcall6.init代码段中. 
这个代码段根据vmlinux.lds.S指定在最终可执行文件的内存布局的第6区域.__initcall6_start是这个区域的起始位置.这个区域的函数由以下函数依次遍历执行:
static void __init do_pre_smp_initcalls(void)
{
initcall_t *fn;

for (fn = __initcall_start; fn < __initcall0_start; fn++)
do_one_initcall(*fn);
}
所有在.initcall6.init区域的函数在第6时间执行. 

core_init被放在第1时间, arch_initcall被放在第3时间,  fs_initcall被放在第5时间. 这些在kernel-3.0/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)

module_initcall即device_initcall在第6时间, 比较靠后的了.

initcall调用顺序的更多相关文章

  1. AsyncTask内的各个方法调用顺序

    |- AsyncTask内的各个方法调用顺序:|- 首先,用户调用execute方法,启动AsyncTask .然后在execute方法中:|- 首先调用onPreExecute方法,执行初始化操作. ...

  2. C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题

    #include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...

  3. UITableView 接口的调用顺序

    ios7启用estimatedHeightForRowAtIndexPath之后的api调用顺序called -[XHYTableViewController tableView:heightForR ...

  4. C++C++中构造函数与析构函数的调用顺序

    http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...

  5. C++类构造析构调用顺序训练(复习专用)

    //对象做函数参数 //1 研究拷贝构造 //2 研究构造函数,析构函数的调用顺序 //总结 构造和析构的调用顺序 #include "iostream" using namesp ...

  6. Unity3D中关于场景销毁时事件调用顺序的一点记录

    先说一下我遇到的问题,我弄了一个对象池管理多个对象,对象池绑定在一个GameObject上,每个对象在OnBecameInvisible时会进行回收(即移出屏幕就回收),但是当场景切换或停止运行程序时 ...

  7. UIViewController中各方法调用顺序及功能详解

    UIViewController中各方法调用顺序及功能详解 UIViewController中loadView, viewDidLoad, viewWillUnload, viewDidUnload, ...

  8. cocos2d-x 2.x版本中,场景切换各方法调用顺序

    假设从A场景切换到B场景,调用各场景方法的顺序为: 如果没有切换效果(transition),则先调用B的init(),再调用A的onExitTransitionStart(),接着调用A的onExi ...

  9. Java类加载及实例化的调用顺序

    标题起得略拗口,大概意思就是说在一个Java类中,域和构造方法的调用顺序. 1. 没有继承的情况 单独一个类的场景下,初始化顺序为依次为 静态数据,继承的基类的构造函数,成员变量,被调用的构造函数. ...

随机推荐

  1. Hprose question

    1 在服务端 接口的开发中 如果定义了index()方法 中间不能够有参数,否则报错. 2 接口方法中的参数 最好使用单参数 如fun($uid ) 或者 如果需要多个参数 fun($param){$ ...

  2. Java—图形处理

    抽象窗口化工具(AWT)为图形用户界面编程提供API编程接口,使得Java可以提供较好的图形用户界面. AWT把图形处理分为两个层次:一是处理原始图形,这一层较原始,图形直接以点.线和面的形式画到界面 ...

  3. MVC5+EF6 入门完整教程八

    本篇是相对独立的一篇,主要讲解不丢失数据进行数据库结构升级. 前面我们讲解EF功能时,已经介绍过一种更新数据库的方式: EF比较model和database,如果两边不一致,程序将会drop and ...

  4. [转载]ASP.NET中TextBox控件设立ReadOnly="true"后台取不到值

    原文地址:http://www.cnblogs.com/yxyht/archive/2013/03/02/2939883.html ASP.NET中TextBox控件设置ReadOnly=" ...

  5. PHP 常用函数的解释

    1.trim() 去掉字符序列左边和右边的空格 2.stripslashes() 去掉反斜线字符 3.htmlspecialchars() 把预定义的字符 "<" (小于)和 ...

  6. Amazon EC2免费VPS防止超额被扣钱三大方法:流量 硬盘读写 运行时长

    Amazon EC2也就是亚马逊云服务免费VPS主机服务,内存是613MB,月流量是30GB,主机空间是30GB,可以免费使用一年,又加上Amazon服务器全球多个节点CDN和本身的名气,早在2010 ...

  7. Fake chat script for website download

    Are you searching for free fake webchat script then you are at the right place go get download your ...

  8. 在 Xcode 7 中安装 Alcatraz

    http://www.jianshu.com/p/5c8ed25ad434 安装Xcode7后,继续采用官方方法安装Alcatraz,发现不成功.单独安装XVim也不成功.看了一下Alcatraz的i ...

  9. 在centos环境安装mysql

    在Linux上安装mysql数据库,我们可以去其官网上下载mysql数据库的rpm包,http://dev.mysql.com/downloads/mysql/5.6.html#downloads,大 ...

  10. 面试复习(C++)之堆排序

    #include <iostream> using namespace std; void Maxheap(int *a,int i,int heapSize)//最大数调整 { +;// ...