initcall调用顺序
在解释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调用顺序的更多相关文章
- AsyncTask内的各个方法调用顺序
|- AsyncTask内的各个方法调用顺序:|- 首先,用户调用execute方法,启动AsyncTask .然后在execute方法中:|- 首先调用onPreExecute方法,执行初始化操作. ...
- C++继承,多重继承,虚继承的构造函数以及析构函数的调用顺序问题
#include <iostream> using namespace std; class A{ int data_a; public: A(){ data_a = ; cout < ...
- UITableView 接口的调用顺序
ios7启用estimatedHeightForRowAtIndexPath之后的api调用顺序called -[XHYTableViewController tableView:heightForR ...
- C++C++中构造函数与析构函数的调用顺序
http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2 ...
- C++类构造析构调用顺序训练(复习专用)
//对象做函数参数 //1 研究拷贝构造 //2 研究构造函数,析构函数的调用顺序 //总结 构造和析构的调用顺序 #include "iostream" using namesp ...
- Unity3D中关于场景销毁时事件调用顺序的一点记录
先说一下我遇到的问题,我弄了一个对象池管理多个对象,对象池绑定在一个GameObject上,每个对象在OnBecameInvisible时会进行回收(即移出屏幕就回收),但是当场景切换或停止运行程序时 ...
- UIViewController中各方法调用顺序及功能详解
UIViewController中各方法调用顺序及功能详解 UIViewController中loadView, viewDidLoad, viewWillUnload, viewDidUnload, ...
- cocos2d-x 2.x版本中,场景切换各方法调用顺序
假设从A场景切换到B场景,调用各场景方法的顺序为: 如果没有切换效果(transition),则先调用B的init(),再调用A的onExitTransitionStart(),接着调用A的onExi ...
- Java类加载及实例化的调用顺序
标题起得略拗口,大概意思就是说在一个Java类中,域和构造方法的调用顺序. 1. 没有继承的情况 单独一个类的场景下,初始化顺序为依次为 静态数据,继承的基类的构造函数,成员变量,被调用的构造函数. ...
随机推荐
- 屏蔽zencart logs文件夹下不断生成的日志文件
在根目錄下的logs文件夾中,經常生成一些錯誤文件類似myDEBUGxxxxx.log這樣的錯誤文件(而且這樣的錯誤文件由來并非網站出現什麽嚴重不可挽救的錯誤,大部分是一些未定義變量這樣的不起眼的小錯 ...
- 代码成长记录之jquery this使用
后台管理的一个项目,第一次主动尝试自己动手写交互,果然问题来了,之前想当然觉得自己能写,不动笔,真的是对自己不负责任啊! 效果图是这样的,按我的思维写下来是点击一个‘更改’ 多个地方会同时触发下拉 ...
- OptionsMenu
菜单是用户界面中最常见的元素之一,使用非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu),今天这讲是O ...
- 坑备忘error: expected class-name before '{' token
今日重构之前的代码,修改了命名空间,然后一处派生的子类定义处总是总是报error: expected class-name before '{' token,网上查了查原因,出现这种情况大致有两种情况 ...
- winform webbrowser flash显示
string flashSrc = "e:\\t.swf"; StringBuilder sb = new StringBuilder(); sb.Append("< ...
- spark发行版笔记11
本期概览: ReceiverTracker架构设计 消息循环系统 ReceiverTracker具体的实现 Spark Streaming作为Spark Core基础 架构之上的一个应用程序,其中的R ...
- HTTP 错误 404.2 - Not Found 由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面
详细错误:HTTP 错误 404.2 - Not Found. 由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面. 出现环境:win7 + IIS7.0 解决办法 ...
- Bootstrap <基础二十五>警告(Alerts)
警告(Alerts)以及 Bootstrap 所提供的用于警告的 class.警告(Alerts)向用户提供了一种定义消息样式的方式.它们为典型的用户操作提供了上下文信息反馈. 您可以为警告框添加一个 ...
- 机器学习相关的Awesome系列
Index Awesome 备注 1 Awesome Machine Learning 机器学习资源大全中文版 2 Awesome Artificial Intelligence 人工智能 3 Awe ...
- jQuery LigerUI V1.2.3 (包括API和全部源码) 发布
前言 这次版本主要是增加了Panel和Portal组件,并增加了一套皮肤,并解决了部分兼容性的问题,添加了几个功能点. 欢迎使用反馈. 相关链接 API: http://api.lig ...