结构体struct module在内核中代表一个内核模块,通过insmod(实际执行init_module系统调用)把自己编写的内核模块插入内核时,模块便与一个 struct module结构体相关联,并成为内核的一部分。下面是结构体struct module的完整定义,接下来会逐个解释:

 struct module{enum module_state state;struct list_head list;char name[MODULE_NAME_LEN];struct module_kobject mkobj;struct module_param_attrs *param_attrs;const char *version;const char *srcversion;const struct kernel_symbol *syms;unsigned int num_syms;const unsigned long *crcs;const struct kernel_symbol *gpl_syms;unsigned int num_gpl_syms;const unsigned long *gpl_crcs;unsigned int num_exentries;const struct exception_table_entry *extable;int (*init)(void);void *module_init;void *module_core;unsigned long init_size, core_size;unsigned long init_text_size, core_text_size;struct mod_arch_specific arch;int unsafe;int license_gplok;#ifdef CONFIG_MODULE_UNLOADstruct module_ref ref[NR_CPUS];struct list_head modules_which_use_me;struct task_struct *waiter;void (*exit)(void);
#endif#ifdef CONFIG_KALLSYMSElf_Sym *symtab;unsigned long num_symtab;char *strtab;struct module_sect_attrs *sect_attrs;
#endifvoid *percpu;char *args;};

我们插入一个内核模块,一般会使用工具insmod,该工具实际上调用了系统调用init_module,在该系统调用函数中,首先调用 load_module,把用户空间传入的整个内核模块文件创建成一个内核模块,返回一个struct module结构体。内核中便以这个结构体代表这个内核模块。

state是模块当前的状态。它是一个枚举型变量,可取的值为:MODULE_STATE_LIVE,MODULE_STATE_COMING,MODULE_STATE_GOING。分别表示模块当前正常使用中(存活状态),模块当前正在被加载,模块当前正在被卸载。load_module函数中完成模块的部分创建工作后,把状态置为MODULE_STATE_COMING,sys_init_module函数中完成模块的全部初始化工作后(包括把模块加入全局的模块列表,调用模块本身的初始化函数),把模块状态置为MODULE_STATE_LIVE,最后,使用rmmod工具卸载模块时,会调用系统调用delete_module,会把模块的状态置为MODULE_STATE_GOING。这是模块内部维护的一个状态。

list是作为一个列表的成员,所有的内核模块都被维护在一个全局链表中,链表头是一个全局变量struct module *modules。任何一个新创建的模块,都会被加入到这个链表的头部,通过modules->next即可引用到。

name是模块的名字,一般会拿模块文件的文件名作为模块名。它是这个模块的一个标识。

另外,还要介绍一下宏THIS_MODULE,它的定义如下是#define THIS_MODULE (&__this_module),__this_module是一个struct module变量,代表当前模块,跟current有几分相似。可以通过THIS_MODULE宏来引用模块的struct module结构,试试下面的模块:

#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");static int hello_init(void)
{unsigned int cpu = get_cpu();struct module *mod;printk(KERN_ALERT "this module: %p==%p/n", &__this_module, THIS_MODULE );printk(KERN_ALERT "module state: %d/n", THIS_MODULE->state );printk(KERN_ALERT "module name: %s/n", THIS_MODULE->name );list_for_each_entry(mod, *(&THIS_MODULE->list.prev), list )printk(KERN_ALERT "module name: %s/n", mod->name );return 0;
}static void hello_exit(void)
{printk(KERN_ALERT "module state: %d/n", THIS_MODULE->state );
}module_init(hello_init);
module_exit(hello_exit);

=========================================

以下均针对于内核2.6.18

在module.h 中 THIS_MODULE的定义如下:

extern struct module __this_module;
#define THIS_MODULE (&__this_module)

即是保存了__this_module这个对象的地址,那这个__this_module在哪里定义呢?这就要从module的编译说起啦,如果编译过模块就会发现,会生成*.mod.c这样的一个文件,打开这个文件,就会发现,类似下面的定义:

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {.name = KBUILD_MODNAME,.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD.exit = cleanup_module,
#endif
};

这个文件是调用modpost生成的,modpost的main中有这样一段代码:

  for (mod = modules; mod; mod = mod->next) {if (mod->skip)continue;buf.pos = 0;add_header(&buf, mod);add_versions(&buf, mod);add_depends(&buf, mod, modules);add_moddevtable(&buf, mod);add_srcversion(&buf, mod);sprintf(fname, "%s.mod.c", mod->name);write_if_changed(&buf, fname);}

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

static void add_header(struct buffer *b, struct module *mod)
{buf_printf(b, "#include <linux/module.h>\n");buf_printf(b, "#include <linux/vermagic.h>\n");buf_printf(b, "#include <linux/compiler.h>\n");buf_printf(b, "\n");buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");buf_printf(b, "\n");buf_printf(b, "struct module __this_module\n");buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");buf_printf(b, " .name = KBUILD_MODNAME,\n");if (mod->has_init)buf_printf(b, " .init = init_module,\n");if (mod->has_cleanup)buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"" .exit = cleanup_module,\n""#endif\n");buf_printf(b, "};\n");
}

linux 内核 THIS_MODULE宏定义详解相关推荐

  1. Linux中THIS_MODULE宏定义详解

    一直都在耿耿于怀,这个THIS_MODULE到底是个什么玩意,linux内核中无处不在的东西.今天上网搜了一下,算是基本明白了.网上牛人写的已经比较详细,另外目前暂时没有时间往更深层次分析,所以直接贴 ...

  2. linux内核管道pipe实现详解

    linux内核管道pipe实现详解 (文件系统暂时不是很了解,文件系统部分暂时不做解释,此文仅解释关键流程,系统调用部分请参考前面已经发布的文章,这里不做展开) 1.管道系统调用(SyS_pipe) ...

  3. 转 C++宏定义详解

    来自:传送门 C++宏定义详解 一.#define的基本用法 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往 ...

  4. C++中的宏定义详解

    转载自:C++中的宏定义 和 C++宏定义详解 目录 一.#define解析 1 #define命令剖析 1.1   #define的概念 1.2 宏替换发生的时机 1.3 ANSI标准说明了五个预定 ...

  5. Linux内核中sk_buff结构详解

    目录 1.sk_buff结构体 1.1 sk_buff在内核中的结构 1.2 重要的长度len的解析 2. sk_buff数据区 2.1 线性数据区 2.2 非线性数据区 -------------- ...

  6. linux内核 sin头文件,Linux内核中中断request_irq详解--中断共享问题解决

    .函数原型如下: 2.4 内核 int request_irq (unsignedintirq,void (*handler)(int,void*,structpt_regs*),unsignedlo ...

  7. Linux内核代码宏定义,Linux Kernel源代码中与段有关的重要宏定义

    __init, __initdata等属性标志,是要把这种属性的代码放入目标文件的.init.text节,数据放入.init.data节──这一过程是通过编译内核时为相关目标平台提供了xxx.lds链 ...

  8. 【GCC系列】深入理解Linux内核 -- __no_sanitize_address宏定义

    本文使用的Linux源码内核版本:Linux 5.10.0 __no_sanitize_address宏定义: 在Linux的内核源码里,尤其是一些关键的内核函数,会包含__no_sanitize_a ...

  9. Linux 内核0.11 系统调用详解(下)

    备注:上讲中,博猪讲到了操作系统是如何让用户程序调用系统函数的,这讲继续接上讲的话题,从一个系统内核系统函数创建的小实验来学习系统内核具体做了些什么.理清下系统调用的整体过程. 实验:在Linux 0 ...

最新文章

  1. 大S变汪太!与汪小菲注册结婚
  2. python中文件分类_Python中的类是否在不同的文件中?
  3. php mysql_connect 不支持_php mysql_connect不支持的解决方法
  4. [vue] SPA首屏加载速度慢的怎么解决?
  5. Video在网页和移动端无法自动播放问题??
  6. java offsetdatetime_Java OffsetDateTime withHour()用法及代码示例
  7. linxuwindows下JBOSS服务端口号及默认根应用修改
  8. jira状态评审未通过后 不能修改_去年职称申报未通过,今年再报名的,这些变化需要注意了...
  9. 乐源机器人没电提醒吗_云迹讲解机器人,你的专属机器人服务专家
  10. C# 注册Dll文件
  11. 怎么将wmv格式转换成mp4
  12. sublime 中文配置
  13. 通过SQL注入获得网站后台用户密码
  14. 开课吧java广告,开课吧Java面试题:虚引用与软引用和弱引用的区别
  15. C/C++教程 第一章 —— 初识C/C++
  16. 【最优化方法】1-最优化方法介绍
  17. 互联网日报 | 携程实现疫情以来首季度盈利;360安全浏览器辟谣收费传闻;滴滴再推123全民拼车日...
  18. Rasterino 2.3.0版for AI 2020 (Illustrator裁切图片一键PS修图插件)
  19. Tomato学习笔记-Vscode配置Makefile(使用task.jason和launch.jason)
  20. 圆刚采集卡测试软件,RECentral(圆刚视频采集卡管理助手)V4.3.0.35 正式版

热门文章

  1. 位置式PID与增量式PID的介绍和代码实现
  2. 两个蓝牙模块配对的方法
  3. SpringBoot 实战 (八) | 使用 Spring Data JPA 访问 Mysql 数据库
  4. Android 存储路径选择
  5. 微软提供支持Windows 10预览版和EdgeHTML 14的预配置虚拟主机
  6. ubuntu中pycharm配置opencv2环境
  7. glance系列二:glance部署及操作
  8. React Native填坑之旅--动画篇
  9. VC++程序中用PlaySound函数加入自定义声音
  10. [日志]保证让你一天不困的方法