编写linux字符设备驱动时,都要定义出入口函数,并在文件的最后用宏定义来声明这个出入口函数。下面来具体解析这样做的原因。
(1)入口函数
编写入口函数的形式和声明如下:
static int __init hello_init(void)
{
return 1;
}
module_init(hello_init);
为什么使用module_init(hello_init)语句,就能将hello_init声明为入口函数呢?先看一下module_init的定义.
/* Each module must use one module_init(). */
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
这个宏定义的意思是给init_module起个别名#initfn,结合上面的代码可知,module_init(hello_init)的意思就是init_module的别名是hello_init。
为什么定义hello_init时要添加__init关键字呢?想看此关键字的定义
#define __init __attribute__ ((__section__ (".init.text"))) __cold
也就是__init代表了一种属性,使用__init就是给函数添加了一个属性。这个属性的意思是,将此函数放入.init.text段中,在插入模块时调用一次,然后释放内存。
(2)出口函数
编写入口函数的形式和声明如下:
static void __exit hello_exit(void)
{
}
module_exit(hello_exit);
module_exit是什么含义呢?先看宏定义原形
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
static inline exitcall_t __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __attribute__((alias(#exitfn)));
这个宏定义的含义是把出口函数cleanup_module的别名定义为#exitfn。
那定义hello_exit时,前面添加的关键字__exit 又是什么意思呢?先看下原形
#define __exit __section(.exit.text) __exitused __cold notrace
这个宏定义确定了出口函数存放的段,但是出口函数是到删除模块时才会被调用的。模块活跃期间不可能删除出口函数,那除了定义位置以外是不是就没有其他作用了呢?
当然不是,大家想一下,啥时候不会调用出口函数呢?是的,就是驱动模块编进内核的情况下。所以编译器就在此处做了优化,如果是编译进内核的驱动,就不加载它的出口函数,节省了内存。
到此为止,分析完毕,请留下您的指正。