module_init宏解析 linux驱动的入口函数module_init的加载和释放
linux驱动的入口函数module_init的加载和释放
http://blog.csdn.net/zhandoushi1982/article/details/4927579
void free_initmem(void)
{
if (!machine_is_integrator() && !machine_is_cintegrator()) {
free_area((unsigned long)(&__init_begin),
(unsigned long)(&__init_end),
"init");
}
}
http://www.cnblogs.com/super-king/p/3286766.html
在init.h中我们看到
#define module_init(x) __initcall(x);
还看到
#define __initcall(fn) device_initcall(fn)
还有
#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn __attribute_used__ \
__attribute__((__section__(".initcall" level ".init"))) = fn __define_initcall 作用 宏定义__define_initcall(level,fn) 对于内核的初始化很重要,它指示编译器在编译的时候,将一系列初始化函数的起始地址值按照一定的顺序放在一个section中。在内核初始化阶 段,do_initcalls() 将按顺序从该section中以函数指针的形式取出这些函数的起始地址,来依次完成相应的初始化。由于内核某些部分的初始化需要依赖于其他某些部分的初始 化的完成,因此这个顺序排列常常非常重要。
下面将从__define_initcall(level,fn) 宏定义的代码分析入手,依次分析名称为initcall.init的section的结构,最后分析内核初始化函数 do_initcalls()是如何利用宏定义__define_initcall(level,fn)及其相关的衍生的7个宏宏定义,来实现内核某些部分的顺序初始化的。
1、分析 __define_initcall(level,fn) 宏定义
1) 这个宏的定义位于inlclude\linux\init.h中:
#define __define_initcall(level,fn) \
static initcall_t __initcall_##fn \
__attribute__((__section__(".initcall" level ".init"))) \
= fn
其中 initcall_t 是一个函数指针类型:
typedef int (*initcall_t)(void);
而属性 __attribute__((__section__())) 则表示把对象放在一个这个由括号中的名称所指代的section中。
所以这个宏定义的的含义是: (1) 声明一个名称为__initcall_##fn的函数指针(其中##表示替换连接);
(2) 将这个函数指针初始化为fn;
(3) 编译的时候需要把这个函数指针变量放置到名称为 ".initcall" level ".init"的section中(比如level="1",代表这个section的名称是 ".initcall1.init")。 2) 举例:__define_initcall(6, pci_init)上述宏调用的含义是: 声明一个函数指针__initcall_pic_init = pci_init;且
这个指针变量__initcall_pic_init 需要放置到名称为 .initcall6.init的section中( 其实质就是将 这个函数pic_init的首地址放置到了这个section中)。 3) 这个宏一般并不直接使用,而是被定义成下述其他更简单的7个衍生宏这些衍生宏宏的定义也位于 inlclude\linux\Init.h 中: #define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
因此通过宏 core_initcall() 来声明的函数指针,将放置到名称为
.initcall1.init的section中,而通过宏 postcore_initcall() 来声明的函数指针,将放置到名称为.initcall2.init的section中,依次类推。 4) 举例:device_initcall(pci_init) 解释同上 1-2)。 2、与初始化调用有关section--initcall.init被分成了7个子section 1) 它们依次是.initcall1.init、.initcall2.init、...、.initcall7.init
2) 按照先后顺序依次排列
3) 它们的定义在文件vmlinux.lds.S中
例如 对于i386+,在i386\kernel\vmlinux.lds.S中有:
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
而在makefile 中有 LDFLAGS_vmlinux += -T arch/$(ARCH)/kernel/vmlinux.lds.s
4) 在这7个section总的开始位置被标识为__initcall_start,而在结尾被标识为__initcall_end。 3、 内核初始化函数do_basic_setup(): do_initcalls() 将从.initcall.init
中,也就是这7个section中依次取出所有的函数指针,并调用这些函数指针所指向的函数,来完成内核的一些相关的初始化。
这个函数的定义位于init\main.c中:
//很简单
static void __init do_initcalls(void)
{
......
for (call = __initcall_start; call < __initcall_end; call++) {
......
result = (*call)();
......
}
......
}
module_init宏解析 linux驱动的入口函数module_init的加载和释放的更多相关文章
- linux驱动的入口函数module_init的加载和释放【转】
本文转载自:http://blog.csdn.net/zhandoushi1982/article/details/4927579 就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含 ...
- Linux下c函数dlopen实现加载动态库so文件代码举例
dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...
- module_init的加载和释放
转自:http://blog.csdn.net/dysh1985/article/details/7597105 像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含Kernel头文件, ...
- Win64 驱动内核编程-13.回调监控模块加载
回调监控模块加载 模块加载包括用户层模块(.DLL)和内核模块(.SYS)的加载.传统方法要监控这两者加在必须 HOOK 好几个函数,比如 NtCreateSection 和 NtLoadDriver ...
- iOS开发 XML解析和下拉刷新,上拉加载更多
iOS开发 XML解析和下拉刷新,上拉加载更多 1.XML格式 <?xml version="1.0" encoding="utf-8" ?> 表示 ...
- Linux中的入口函数main
main()函数,想必大家都不陌生了,从刚开始写程序的时候,大家便开始写main(),我们都知道main是程序的入口.那main作为一个函数,又是谁调用的它,它是怎么被调用的,返回给谁,返回的又是什么 ...
- Linux进程启动过程分析do_execve(可执行程序的加载和运行)---Linux进程的管理与调度(十一)
execve系统调用 execve系统调用 我们前面提到了, fork, vfork等复制出来的进程是父进程的一个副本, 那么如何我们想加载新的程序, 可以通过execve来加载和启动新的程序. x8 ...
- Linux中实现在系统启动时自动加载模块
下面是以前学习Linux时写的,后来仔细研究rc.sysinit后发现,只需要修改下列地方就可以了,不必这么麻烦的: rc.sysinit中有这样的一段代码: # Load other user-de ...
- 深度解析qml引擎---(1)Qml文件加载
"美的事物是永恒的喜悦" --- 济慈 ...
随机推荐
- 深入理解JavaScript中的this关键字
1. 一般用处 2. this.x 与 apply().call() 3. 无意义(诡异)的this用处 4. 事件监听函数中的this 5. 总结 在JavaScript中this变量是一个令人难以 ...
- (转)Mongodb相对于关系型数据库的优缺点
与关系型数据库相比,MongoDB的优点:①弱一致性(最终一致),更能保证用户的访问速度:举例来说,在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到“当前”情况下的精确值 ...
- Java使用泛型类来提高方法的可重用性
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3832268.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- linux之Gcc使用
本篇文章摘自 http://blog.csdn.net/ljzcom/article/details/7213101 对于Gcc自带的很多命令行,只有具体编程里面用到了或者看到别人真真用到的,用的目的 ...
- WSAEventSelect模型详解
WSAEventSelect 是 WinSock 提供的一种异步事件通知I/O模型,与 WSAAsyncSelect模型有些类似. 该模型同样是接收 FD_XXX 之类的网络事件,但是是通 ...
- jQuery学习-----(一)JQuery的'$'符号用法
1.jQuery的三种$() 1)$()可以是$(expresion),即css选择器.Xpath或html元素,也就是通过上述表达式来匹配目标元素. 比如:$("a")构造的 ...
- Qt 日志宏
随便写了一个日志帮助的宏,既可以如同qDebug()一般在调试时输出信息,也可以在输出文本文件 #ifndef LOG_H #define LOG_H #include <QDir> #i ...
- sql新感悟(where 1 = 1)
花了好久把YII框架看完发现一本很不错的书:SQL案例解析(清华大学出版社),看到一些比较有用的东西,感觉应该把他记录下来,看了好多页发现书中一直有 where 1=1,这样的语句,查过发现“wher ...
- Python执行效率测试模块timei的使用方法与与常用Python用法的效率比较
timeit模块用于测试一段代码的执行效率 1.Timer类 Timer 类: __init__(stmt="pass", setup="pass", time ...
- Linux进程间通信IPC学习笔记
linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...