注:以下讨论建立在内核 3.2.9基础之上。
linux中驱动模块的加载由module_init() 宏功能出发,其用法例:
int __init fimc_md_init(void)
{
int ret;
request_module("s5p-csis");
ret = fimc_register_driver();
if (ret)
return ret;
return platform_driver_register(&fimc_md_driver);
}
module_init(fimc_md_init);
从上面的例子可以看出,该宏函数的参数是以宏__init 修饰的函数的函数名,故而可知其传入的是函数指针。那__init这个又是什么呢,我们把它展开来看一下,
#define __init __attribute__ ((__section__ (".text.init")))
好的,这里遇到了__attribute__ ,为了更进一步的理解,这里不得不提及到 GNU C编译器扩展的一些知识作为辅助,其具体内容可见转载的《GNU C 扩展之__attribute__ 机制简介》这篇文章,这里只对__attribute__ 做简单的描述,__attribute__是GNU C编译器的扩展功能,其作用是修改函数、变量和类型的编译属性,括号内的__section__表示段属性,整句的意思是将该宏修饰的函数或变量放入指定的段中,这里是.text.init 段,该例子中 __init 的作用就是 将函数fimc_md_init(void)编译的时候放入段.text.init 中,由于一些初始化操作只会运行一次,为了节约内存,在这些段内的代码运行完之后,linux会将其代码占用的内存释放掉。现在转过来继续聊module_init(),先把它逐层展开:
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
好的,基本展开完成,这里出现了initcall_t,查看一下定义,
typedef int (*initcall_t)(void);很清晰,就是typedef了个函数指针类型,连贯起来理解以上宏内容就是,定义了一个函数指针变量__initcall_##fn##id,然后将其初始化为fn,并通过__attribute__的编译选项,将其放入段".initcall" level ".init" 中,这里的##是预编译时的字串连接符,该例子中把字串替换进去后的结果是:
static initcall_t __initcall_fimc_md_init6 __used
__attribute__((__section__(".initcall6.init"))) = fn
到现在我们明白了,module_init(x)的作用就是在.initcall6.init段中定义一个函数指针变量,然后将其初始化成 x。那这样做的具体作用是啥呢,这个时候我们有必要先看看.initcall6.init了。
上面说到的