module_init与module_exit的分析

        在编写驱动模块的时候有两个函数经常被使用也必须被使用,分别是module_init和module_exit,这两个函数分别在加载和卸载驱动时被调用,即调用insmod和rmmod命令的时候,但是insmod和rmmod不能识别这两个函数,它只能识别init_module和cleanup_module其实init_module和cleanup_module相当于是module_init和module_exit的别名,下面会详细讲解

我们知道驱动可以作为一个模块动态的加载到内核里,也可以作为内核的一部分静态的编译进内核,module_init/module_exit也就有了两个含义:

一、编译成模块

/* 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)));

/* 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)));

module_init有两个含义:

  1. 验证函数的格式

         initcall_t是一个函数指针。定义为:

typedef int (*initcall_t)(void);

         static inline initcall_t __inittest(void) { return initfn; }

         这个函数的作用是定义一个函数__inittest返回值类型为initcall_t如果我们传进来的函数返回值类型不是initcall_t这个类型则会报错,即验证我们定义的函数是否符合规范

         所以我们写加载函数的时候必须是返回值为int参数为void的函数。

2、定义别名

int init_module(void) __attribute__((alias(#initfn)));

         这段代码的作用是给我们的加载函数定义一个别名init_module因为insmod命令只能识别函数init_module

         module_exit的作用和module_init一样,同样也是验证函数格式和定义别名。

         例:

static int __init acm_ms_init(void)
{
    return usb_composite_probe(&acm_ms_driver, acm_ms_bind);
}
module_init(acm_ms_init);
展开后为:
static inline initcall_t __inittest(void)
{
    return acm_ms_init;//验证acm_ms_init是否和initcall_t为同一类型
}
int init_module(void) __attribute__((alias(#acm_ms_init)));//定义别名init_module

二、静态编译         

         在静态编译的时候module_init的定义如下:

#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn

#define device_initcall(fn) __define_initcall("6",fn,6)
#define __initcall(fn) device_initcall(fn)
#define module_init(x) __initcall(x);

         关于静态编译的主要函数__define_initcall的分析请参考博客:https://blog.csdn.net/qq_37600027/article/details/90739265

         module_exit在静态编译的时候没有意义,因为静态编译的驱动无法卸载!

         例:

static int __init acm_ms_init(void)
{
    return usb_composite_probe(&acm_ms_driver, acm_ms_bind);
}
module_init(acm_ms_init);

         展开后,其实就是如下内容

static initcall_t __initcall_acm_ms_init6 __used \
    __attribute__((__section__(".initcall6.init"))) = acm_ms_init;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章