linux 模块的初始化函数module_init

         linux中,模块的初始化都利用module_init()函数来完成,下面主要对以build in 方式编译的模块的初始化的实现进行简介。

例如:

module_init(init_ext2_fs)


static int __init init_ext2_fs(void)
{
    int err = init_ext2_xattr();
    if (err)
        return err;
    err = init_inodecache();
    if (err)
        goto out1;
        err = register_filesystem(&ext2_fs_type);
    if (err)
        goto out;
    return 0;
out:
    destroy_inodecache();
out1:
    exit_ext2_xattr();
    return err;
}


         开始一直对初始化函数前面的 __init不理解,gcc又一扩展?直到看了内核中init.h和内核的ld script后才略明白,其实现在对内核的编译流程以及内核镜像的制作依然不太懂,慢慢来,每天进步一点点^_^

       在include/linux目录下有一个init.h,这个头文件中的很多内容说明了模块的初始化函数如何被编译,即指明 初始化函数和section的对应关系,如果对elf文件、编译、链接知识不太懂的同学可以先查看相关资料。

       /* These macros are used to mark some functions or
 * initialized data (doesn't apply to uninitialized data)
 * as `initialization' functions. The kernel can take this
 * as hint that the function is used only during the initialization
 * phase and free up used memory resources after
 *这些所谓的初始化函数会在系统初始化阶段使用,使用后即从内存中free up。如何和为什么free up,还不太了解^_^
 * Usage:
 * For functions:
 *
 * You should add __init immediately before the function name, like:
 *你必须在函数名前加上 __init,表面这个函数是一个初始化函数
 * static void __init initme(int x, int y)
 * {
 *    extern int z; z = x * y;
 * }
 *

那么到底module_init是什么呢

/**
 * module_init() - driver initialization entry point
 * @x: function to be run at kernel boot time or module insertion
 *
 * module_init() will either be called during do_initcalls() (if
 * builtin) or at module insertion time (if a module).  There can only
 * be one per module.
 */
#define module_init(x)    __initcall(x);

这个module_init宏定义,是内核模块按照build in方式编译,而不是module方式,module方式在这个头文件中也有说明,不介绍了。


#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


typedef int (*initcall_t)(void); //initcall_t是一个函数指针int (*)(void)

这里碰到一个 __attribute__,它和__section__一起告诉编译器,凡是被他们修饰的函数或者变量应该放在特殊的section里面。

上面这个宏就定义了一个“变量”,不过这个变量是一个函数指针,并且这个函数会被编译器放在.initcall" level ".init section里面。继续回到module_init(),将所有宏展开后,

module_init(fn)  -----> __define_initcall("6",fn,6)  ------>  __initcall_##fn##6 = fn  将函数fn 放在.initcal6.init section里面,这个section会在后续ld scrips中用到。

对于ext2文件系统的初始化函数

module_init(init_ext2_fs),即定义了一个 __initcall_init_ext2_fs_6的函数,这个函数其实和init_ext2_fs是一个函数


在arch/x86/kernel中的vmlinux_32.lds.S即为x86 32架构下的内核ld scrips,其中

 /*
   add by lyf
   #define INITCALLS                            \
      *(.initcall0.init)                        \
      *(.initcall0s.init)                        \
      *(.initcall1.init)                        \
      *(.initcall1s.init)                        \
      *(.initcall2.init)                        \
      *(.initcall2s.init)                        \
      *(.initcall3.init)                        \
      *(.initcall3s.init)                        \
      *(.initcall4.init)                        \
      *(.initcall4s.init)                        \
      *(.initcall5.init)                        \
      *(.initcall5s.init)                        \
    *(.initcallrootfs.init)                        \
      *(.initcall6.init)                        \
      *(.initcall6s.init)                        \
      *(.initcall7.init)                        \
      *(.initcall7s.init)

   */
  .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
      __initcall_start = .;
    INITCALLS
      __initcall_end = .;
  }

上述命令即说明了将这些初始化函数装载位置,在__initcall_start和 __initcall_end之间,而上面提到的.initcal6.init当然也在其中。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值