Linux module(5) - THIS_MODULE

  • 了解THIS_MODULE

1.struct module

  结构体struct module在内核中代表一个内核模块,通过insmod(实际执行init_module系统调用)把自己编写的内核模块插入内核时,模块便与一个struct module 结构体相关联,并成为内核的一部分。结构体如下所示:

</include/linux/module.h>
struct module
{
    enum module_state state;

    /* Member of list of modules */
    struct list_head list;

    /* Unique handle for this module */
    char name[MODULE_NAME_LEN];

    /* Sysfs stuff. */
    struct module_kobject mkobj;
    struct module_attribute *modinfo_attrs;
    const char *version;
    const char *srcversion;
    struct kobject *holders_dir;

    /* Exported symbols */
    const struct kernel_symbol *syms;
    const unsigned long *crcs;
    unsigned int num_syms;

    /* Kernel parameters. */
    struct kernel_param *kp;
    unsigned int num_kp;

    /* GPL-only exported symbols. */
    unsigned int num_gpl_syms;
    const struct kernel_symbol *gpl_syms;
    const unsigned long *gpl_crcs;  
    ....
 }

参数分析:

  • enum module_state state; //state是模块当前的状态。
    它是一个枚举型变量,可取的值为:

    • MODULE_STATE_LIVE,模块当前正常使用中 (存活状态)
    • MODULE_STATE_COMING,模块当前正在被加载
    • MODULE_STATE_GOING ,模块当前正在被卸载
    • MODULE_STATE_UNFORMED, /* Still setting it up. */
  • struct list_head list;
    list是作为一个列表的成员,所有的内核模块都被维护在一个全局链表中,链表头是一个全局变量struct module *modules。任何一个新创建的模块,都会被加入到这个链表的头部,通过modules->next即可引用到。

  • char name[MODULE_NAME_LEN];
    name是模块的名字,一般会使用模块文件的文件名作为模块名。它是这个模块的一个标识。

  • const struct kernel_symbol *syms;
    内核模块导出的符号所在起始地址;

  • const unsigned long *crcs;
    内核模块导出符号的校验码所在起始地址;

2.THIS_MODULE

  THIS_MODULE是一个macro,如下所示:

include/linux/export.h:
 14 #ifdef MODULE
 15 extern struct module __this_module;
 16 #define THIS_MODULE (&__this_module)                                                                     
 17 #else 
 18 #define THIS_MODULE ((struct module *)0)
 19 #endif

  THIS_MODULE即是__this_module这个变量的地址,__this_module会指向这个模块起始的地址空间,恰好是struct module变量定义的位置。__this_module 是内核模块的编译工具链为当前内核模块产生的struct module 类型对象,所以THIS_MODULE实际上是当前内核模块对象的指针。

  module编译生成的*.mod.c文件包含 __this_module定义:

   11 __visible struct module __this_module
   12 __attribute__((section(".gnu.linkonce.this_module"))) = {
   13     .name = KBUILD_MODNAME,
   14     .init = init_module,
   15 #ifdef CONFIG_MODULE_UNLOAD
   16     .exit = cleanup_module,
   17 #endif
   18     .arch = MODULE_ARCH_INIT,
   19 };

   This section contains only one structure–this_module, which is mostly filled with zeroes (as it is used by the LKM loader internally) except three fields:

  • Name of the module
  • A pointer to the initialization procedure–module_init
  • A pointer to the de-initialization procedure–module_cleanup

  You may examine content of that section and find module’s name there:

objdump -s -j .gnu.linkonce.this_module foo.ko

Kbuild modpost:

 Documentation/kbuild/modules.txt :
    When building an external module, the build system needs access to the symbols from the kernel to check if all external symbols
	are defined. This is done in the MODPOST step. modpost obtains
	the symbols by reading Module.symvers from the kernel source
	tree. If a Module.symvers file is present in the directory
	where the external module is being built, this file will be
	read too. During the MODPOST step, a new Module.symvers file
	will be written containing all exported symbols that were not
	defined in the kernel.

  这个文件是调用scripts/mod/modpost.c(scripts/Makefile.modpost)生成的,代码如下:

  2495     for (mod = modules; mod; mod = mod->next) {
  2496         char fname[PATH_MAX];
  2497 
  2498         if (mod->skip)
  2499             continue;
  2500 
  2501         buf.pos = 0;
  2502 
  2503         err |= check_modname_len(mod);
  2504         add_header(&buf, mod);
  2505         add_intree_flag(&buf, !external_module);
  2506         add_retpoline(&buf);
  2507         add_staging_flag(&buf, mod->name);
  2508         err |= add_versions(&buf, mod);
  2509         add_depends(&buf, mod, modules);
  2510         add_moddevtable(&buf, mod);
  2511         add_srcversion(&buf, mod);
  2512 
  2513         sprintf(fname, "%s.mod.c", mod->name);
  2514         write_if_changed(&buf, fname);                                                                
  2515     }

  其中add_header就添加了__this_module 的定义:

  2128 static void add_header(struct buffer *b, struct module *mod)
  2129 {
  2130     buf_printf(b, "#include <linux/build-salt.h>\n");
  2131     buf_printf(b, "#include <linux/module.h>\n");
  2132     buf_printf(b, "#include <linux/vermagic.h>\n");
  2133     buf_printf(b, "#include <linux/compiler.h>\n");
  2134     buf_printf(b, "\n");
  2135     buf_printf(b, "BUILD_SALT;\n");
  2136     buf_printf(b, "\n");
  2137     buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
  2138     buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
  2139     buf_printf(b, "\n");
  2140     buf_printf(b, "__visible struct module __this_module\n");
  2141     buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
  2142     buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
  2143     if (mod->has_init)
  2144         buf_printf(b, "\t.init = init_module,\n");
  2145     if (mod->has_cleanup)
  2146         buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
  2147                   "\t.exit = cleanup_module,\n"
  2148                   "#endif\n");                                                                        
  2149     buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
  2150     buf_printf(b, "};\n");
  2151 }

  其中struct file_operations结构体的第一个成员是struct module类型的指针,定义在<linux/fs.h>中:

struct file_operations {
    struct module *owner;
    ......
}

  struct module *owner is commonly used at some structures and is not an operation at all; it is a pointer to the module that "owns"the structure. This field is used to prevent the module from being unloaded while its operations are in use. Almost all the time, it is simply initialized to THIS_MODULE, a macro defined in < linux/module.h> .

  struct file_operations中的owner成员可以避免当file_operations中的函数正在调用时,其所属的模块被从系统中卸载掉。如果有一个设备驱动程序不是以模块的形式存在,而是被编译进内核,那么THIS_MODULE将被赋值为NULL,没有任何作用。

参考:
https://www.kancloud.cn/yueqian_scut/emlinux/106822

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值