第7章 模块(2)

目录

7.3 插入和删除模块

7.3.1 模块的表示

7.3.2 依赖关系和引用

7.3.3 模块的二进制结构

7.3.4 插入模块

7.3.5 移除模块


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

7.3 插入和删除模块

两个系统调用:

        init_module:插入模块。

        delete_module:删除模块。

request_module 函数:非系统调用

作用:

        1. 内核中加载一个模块。

        2. 实现热插拔。

7.3.1 模块的表示

每个模块都有一个 struct module 实例:

struct    module {

        enum module_state         state;         //模块的装载状态

        struct list_head                 list;           //连接内核所有模块

        struct kernel_symbol      *syms;      //该模块导出的符号及其内存地址。

        unsigned int                      num_syms;

        struct module_ref              ref;

                //该模块的引用计数。

                        module_put 时减1。

                        try_module_get 加1。

        unsigned int                      init_size, core_size;

                // 模块中__init 类型的符号大小,其余符号大小。

        unsigned int                      init_text_size, core_text_size;

        void                                   (*init)(void);         // 模块初始化时调用。

        void                                   (*exit)(void);

}

struct         kernel_symbol {

        unsigned long         value;         // 内存地址。

        const char               *name;       // 符号。

}

# cat  /proc/kallsyms:

        查看导出的所有符号。

当模块污染内核,原因:

        许可证问题。

7.3.2 依赖关系和引用

为管理模块间的依赖关系,引入如下结构体。

struct    module_use {

        struct list_head         source_list;         // 依赖本模块的模块。

        struct list_head         target_list;          // 本模块所依赖的模块。

        struct module            *source,  *target;

};

如果模块 A 依赖了模块 B 中函数,则调用:

int    add_module_usage(struct module   *a,    struct module   *b)

{

        struct module_use    *use;

        use   =   kmalloc(sizeof(*use),   GFP_ATOMIC);

        use->source   =   a;

        use->target   =   b;

        list_add(&use->source_list,   &b->source_list);

        list_add(&use->target_list,     &a->target_list);

}

already_uses:判断模块A是否使用了模块B。

int   already_uses(struct module   *a,   struct module   *b)

{

        struct module_use   *use;

        list_for_each_entry(use,   &b->source_list,   source_list)

        {

                if (use->source   ==   a) {

                        return 1;

                }

        }

}

7.3.3 模块的二进制结构

一个模块文件的格式是ELF,其特有的段有:

        1. __ksymtab段:保存内核符号表。

        2. __kcrctab段:保存导出函数的校验和。

        3. __param段:保存模块参数。

        4. __ex_table段:保存新增内核异常表。

        5. .modinfo段:保存依赖模块名称、author、描述、许可证、参数列表等。

                (modinfo命令:读取该段)

        6. .init.data,.exit.data段:

                保存__init和__exit类型的数据。

        7. .init.text,.exit_text段:

                保存__init和__exit类型的函数。

1. 初始化和清理函数

module_init(nat_init_module);

module_exit(nat_cleanup_module);

即在.init.data,.init.text,.exit.data段中定义模块的init,exit函数。

2. 导出符号

两个宏:

        EXPORT_SYMBOL:导出一般符号。

        EXPORT_SYMBOL_GPL:导出GPL兼容代码的符号。

EXPORT_SYMBOL

        原理:将相应符号放置在模块二进制文件的一个段中。

举例:将变量 a 导出到文件的 .my_test.data 段中。

        static   int   a __attribute__((section(".my_test.data")));

EXPORT_SYMBOL_PREFIX

        作用:给导出符号分配一个前缀。

        使用场景:某些特定体系架构需要。

3. 模块的信息

MODULE_INFO(tag,    info):

        作用:生成一个模块的相关信息。

        原理:使用__attribute__((section(".modinfo"))),将模块的信息保存在 .modinfo 段中。

#define     MODULE_LICENSE(_license)     MODULE_INFO(license,     _license)

#define     MODULE_ALIAS(_alias)              MODULE_INFO(alias,     _alias)

#define     MODULE_AUTHOR(_author)      MODULE_INFO(author,     _author)

宏VERMAGIC_STRING:

定义了安装模块时,需要检查的信息,若和内核不一致,则不可安装模块。

        1. SMP配置。

        2. 内核抢占配置

        3. 模块版本。

        4. 特定于体系架构的常数。

#define    VERMAGIC_STRING   \

        MODULE_VERMAGIC_SMP   \

        MODULE_VERMAGIC_PREEMPT   \

        MODULE_VERMAGIC_MODVERSIONS   \

        MODULE_ARCH_VERMAGIC   \

7.3.4 插入模块

对应系统调用:

        init_module

load_module 内容:

        1. 使用copy_from_user,将模块加载到内核空间。

        2. 重写函数和变量的地址。

        3. 在内存中组织数据。

                使用 layout_sections,判断模块的段加载到内存哪个位置。

                模块的段分为两类:

                        core 和 init。

        4. 分配内存,传输模块到内存。

        5. 检查模块许可证。

        6. 通过reslove_symbol,解决引用重定位。

7.3.5 移除模块

对应系统调用:

        delete_module

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山下小童

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值