在解释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. (转载)数据库出现ORA-00283/ORA-01610的问题

    在这里需要感谢棉花糖给予无私帮助,真的谢谢他!http://blog.itpub.net/67668/viewspace-353270/处理过程可以参照http://www.itpub.net/vie ...

  2. angularJs|es6|reactJs|vueJs相关技术(请访问https://expendo.github.io/)

    技术博客地址:https://expendo.github.io/

  3. <context:component-scan>使用说明

    Spring组件扫描<context:component-scan/>使用详解 在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫 ...

  4. 当 jquery.unobtrusive-ajax.js 遇上Web API

    最近在熟悉Abp框架,其基于DDD领域驱动设计...前段可以绕过mvc直接调用根据app层动态生成的webapi,有点神奇~,Web API之前有简单接触过,WCF的轻量级版,一般用于做一写开发性的服 ...

  5. linux 下 PHP Notice: session_start(): ps_files_cleanup_dir 报错 问题剖析

    如果在ubuntu/Debian下, 采用apt安装的PHP, 那么在使用Session的时候, 就可能会有小概率遇到这个提示. 代码如下: PHP Notice: session_start(): ...

  6. UDP传输

    @@@基于UDP的客服端代码 public class Service { // 服务器 public static void main(String[] args) { DatagramPacket ...

  7. C++小项目:directx11图形程序(二):systemclass

    先上代码: systemclass.h #pragma once #include"graphicsclass.h" const bool FULLSCREEN = true; c ...

  8. CSS3入门--线条动画特效实例

    HTML: <div></div> CSS: div{ width: 200px; height: 200px; margin: 200px auto; background: ...

  9. 数组求和,计算给定数组 arr 中所有元素的总和

    一,题目分析:可以使用数组的归并方法计算,reduce和reduceRight.二者作用几乎相同.只是归并方向相反.reduce和reduceRight都可以接收两个参数.第一个是在每一项上调用的函数 ...

  10. placeholder 不支持IE修复

    <script type="text/javascript"> var JPlaceHolder = { //检测 _check : function(){ retur ...