GCC特性之__init修饰解析

做底层驱动的人都知道,在driver文件中会经常看见“__init“修饰的代码,那么__init标记有什么意义?
        下面我们就来看看。

在GCC拓展的特殊属性中section时会提及这个__init,他所修饰的所有代码都会放到.init.text节中,当初始化结束后就可以释放这部分内存,这样就减少了内存的占用空间。
        那么另外一个问题就来了,什么时候调用到该函数?
        要回答这个问题首先要先讲解这个宏:subsys_initcall,在文件kernel/include/linux/init.h中。定义方式如下:
        #define subsys_initcall(fn)             __define_initcall("4",fn,4)

又带来了一个新的宏__define_initcall,定义方式如下:
        #define __define_initcall(level,fn,id) \
                 static initcall_t __initcall_##fn##id __used \
                 __attribute__((__section__(".initcall" level ".init"))) = fn

那么 __define_initcall是用来修饰将指定的函数指针fn存放到".initcall.init"节中。因此可以断定subsys_initcall宏将fn存放到“.initcall.init”节中的“..initcall4.init”里。

我们需要理解一下.initcall.init和.init.text和".initcall4.init"之类的符号的含义,这就需要我们了解和内核可执行文件的相关概念。
什么是内核可执行文件?
        可执行文件映像中包含了进程执行的代码和数据,同时也包含了操作系统用来将映像正确装入内存并执行的信息。具体信息大家可以上网搜索,这里就一笔带过。

这些信息包含了如下文本段、数据段、init数据段、bass段等。这些数据都是由一个称为“链接器脚本”的文件链接并装入的,这个文件的功能时间这些输
入信息的各段装入到指定的地址处。vmlinux.lds就是存在"arch/xxx/"目录中哦你的内核连接其脚本,他负责链接内核的各个段并将他们装
入到内存中特定偏移量处。
         下面让我们看一下这个链接器脚本文件,路径是"arch/arm/kernel",名称为vmlinux.lds.
          找到关键程序:INIT_SETUP(16)--->init_main.c的__setup_start指向的.init.setup节的开始
                                       INIT_CALLS---->init_main.c的__initcall_start指向的.initcallearly.init节的开始
                                      CON_INITCALL---->./drivers/char/tty_io.c的__con_initcall_start指向的.con_initcall.init节的开始。
                                      其他的宏就不讲解了。
其中INIT_CALL是主要的,分为了九段:
                 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)
而INIT_CALL_LEVEL宏定义如下:
#define INIT_CALLS_LEVEL(level)                                         \
                 VMLINUX_SYMBOL(__initcall##level##_start) = .;          \
                 *(.initcall##level##.init)                              \
                 *(.initcall##level##s.init)


际就是.initcall0.init~.initcall7.init。那么subsys_initcall将值定的话函数指针放在
了".initcall4.init"子段中。例如:device_initcall将函数指针存放到了".initcall6.init"
中;core_initcall将函数指针存放到了".initcall1.init"子段中。
        各个子段的顺序是确定的,是先调用".initcall4.init"中的函数指针再去执行“.initcall5.init”中的函数指针。

那么__init修饰的初始化函数在内核初始化过程中调用的顺序和.initcall.init里面的函数指针的顺序有关,因此不同的初始化函数是被放在不同的子段中,因此就决定了他们的调用顺序。

时间: 2024-10-10 13:29:55

GCC特性之__init修饰解析的相关文章

GCC特性之__init修饰解析 - kasalyn的专栏 - 博客频道 - CSDN.NET

, GCC特性之__init修饰解析 - kasalyn的专栏 - 博客频道 - CSDN.NET.MathJax_Hover_Frame {border-radius: .25em; -webkit-border-radius: .25em; -moz-border-radius: .25em; -khtml-border-radius: .25em; box-shadow: 0px 0px 15px #83A; -webkit-box-shadow: 0px 0px 15px #83A; -

Linux 内核中的 GCC 特性

转载:http://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/?S_TACT=105AGX52&S_CMP=tec-csdn Linux 内核中的 GCC 特性 了解用于 C 语言的 GCC 扩展 Linux? 内核使用 GNU Compiler Collection (GCC) 套件的几个特殊功能.这些功能包括提供快捷方式和简化以及向编译器提供优化提示等等.了解这些特殊的 GCC 特性,学习如何在 Linux 内核中使用它们. 0 评论:

gcc和g++的区别解析

1.误区:gcc只能编译C源代码,g++只能编译C++源代码 解析:其实gcc和g++都可以编译c/c++源代码,只是细节不同,后缀名为.c的源文件,gcc将其当作C程序,而g++则当作c++程序来处理:后缀名为.cpp的源文件,gcc和g++都会当作C++程序来处理.编译阶段,g++会调用gcc来进行编译,但由于gcc不能链接程序所使用的库,所以需要通过g++来链接库文件,即在编译阶段都是使用gcc来进行编译,但当进入链接阶段的时候,由于gcc无法自动链接库文件,要想使用gcc链接库文件必须使

Java高级特性 第14节 解析XML文档(2) - SAX 技术

一.SAX解析XML文档 SAX的全称是Simple APIs for XML,也即XML简单应用程序接口.与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式.当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口. 1. SAX解析原理: 加载一点,读取一点,处理一点.对内存要求比较低. SAX解析工具内置在jdk中:org.xml.sax.*

SGI-STL简记(三)-构造、类型萃取特性、未初始化解析

stl_construct.h : 提供多种构造器.销毁器模板函数: 构造器construct提供了给定值构造和默认构造方式,通过调用重载函数_Construct实现: 销毁器destroy提供了销毁指针和迭代器的方式,通过调用重载函数_Destroy实现: _Construct:通过“放置”new,构造实现: _Destroy:通过调用模板类型对象析构函数实现,对于迭代器器方式,则通过__destroy(内部通过__destroy_aux)遍历销毁,因内置数据类型不需要销毁, 故内部需要判断是

Android 5.X新特性之RecyclerView基本解析及无限复用

说到RecyclerView,相信大家都不陌生,它是我们经典级ListView的升级版,升级后的RecyclerView展现了极大的灵活性.同时内部直接封装了ViewHolder,不用我们自己定义ViewHolder就能实现item的回收和复用功能.当然它肯定不止这些好处,比如我们可以自定义分割线,可以更加方便的实现列表的布局方式等等.虽说我们自己在第一次使用时,会比使用listView和gridView稍微的复杂一些,需要自定义的也多了一点,但是它却更好的体现了灵活性,可以随自己的喜好来随便的

iOS开发——高级特性&Runtime运行时特性详解

Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 简介 与Runtime交互 Runtime术语 消息 动态方法解析 消息转发 健壮的实例变量(Non Fragile ivars) Objective-C Associated Objects Method Swizzling 总结 引言 曾经觉得Objc特别方便上手,面对着 Cocoa 中大量

GCC扩展(转--对看kernel代码有帮助

Linux Kernel的代码,上次就发现一个结构体的定义形式看不懂,后来才知道它用的不是标准的ANSI C,而是GCC的一些扩展.刚好看到<Linux内核修炼之道>中对GCC扩展有所描述,转载一下吧,对看kernel代码有所帮助. 3.5内核代码的特点 Linux内核同时使用C语言和汇编语言实现,C语言编写的代码移植性较好.易于维护,而汇编语言编写的代码相当于针对特定的平台做了优化,速度较快,所以需要在它们之间寻找一定的平衡. 一般而言,在体系结构的底层或对执行时间要求严格的地方,会使用汇编

[Linux] __init &amp; __setup 等宏的代码追踪

Platform:Linux 3.0.35 模仿 fbmem.c 的代码添加了 __setup 却无法触发效果(代码如下),所以原本的打算是追一下这个 __setup 的流程,结果还牵扯到了 kernel 初始化的一些相关知识,在此作简单记录. static int __init my_video_setup(char *options) { printk("%s-------------------------%s\n",__FUNCTION__, options); return