Linux module(3) -insmod

  • 了解module 加载过程

1.module加载

  调用过程分两步:

  • 用户空间调用insmod命令(busybox)将*.ko文件读取到用户空间的一段内存中;
  • 然后通过系统调用sys_init_module进入内核态,该函数分配内核存储空间(kernel memory)给*.ko模块,将该模块内容拷贝到这块存储空间里。
    在这里插入图片描述

1.1.函数sys_init_module:

该函数包含三个参数,且都是由insmod经用户空间传递过来:

  • umod:指向用户空间*.ko文件映像数据的内存地址;
  • len:该文件的数据大小;
  • uargs:传给模块的参数在用户空间下的内存地址。
  3860 SYSCALL_DEFINE3(init_module, void __user *, umod,
  3861         unsigned long, len, const char __user *, uargs)
  3862 {
  3863     int err;
  3864     struct load_info info = { };
  3865 
  3866     err = may_init_module();
  3869 
  3870     pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
  3871            umod, len, uargs);
  3872 
  3873     err = copy_module_from_user(umod, len, &info);
  3876 
  3877     return load_module(&info, uargs, 0);                                                              
  3878 }
  3879 

1.2.load_module

  3666 static int load_module(struct load_info *info, const char __user *uargs,
  3667                int flags)
  3668 {
  3669     struct module *mod;
  3670     long err = 0;
  3671     char *after_dashes;
  3672 
  3673     err = elf_header_check(info);
  3677     err = setup_load_info(info, flags);
  3686     err = module_sig_check(info, flags);                                                                         
  3673     if (!check_modstruct_version(info, info->mod)) {                                                  
  3674         err = -ENOEXEC;
  3675         goto free_copy;
  3676     }
  3690     err = rewrite_section_headers(info, flags);
  3750     err = simplify_symbols(mod, info);  
  }

分析如下:

  第3673行:err = elf_header_check(info); 负责检查elf文件格式,变量unsigned char e_ident[EI_NIDENT] 保存elf文件头部识别字符,是否匹配#define ELFMAG “\177ELF”。

204 typedef struct elf32_hdr{
205   unsigned char e_ident[EI_NIDENT];
206   Elf32_Half    e_type;
207   Elf32_Half    e_machine;
208   Elf32_Word    e_version;
209   Elf32_Addr    e_entry;  /* Entry point */
210   Elf32_Off      e_phoff;
211   Elf32_Off       e_shoff;
212   Elf32_Word    e_flags;
213   Elf32_Half    e_ehsize;
214   Elf32_Half    e_phentsize;
215   Elf32_Half    e_phnum;
216   Elf32_Half    e_shentsize;
217   Elf32_Half    e_shnum;
218   Elf32_Half    e_shstrndx;
219 } Elf32_Ehdr;

  第3677行:setup_load_info,ELF文件一般包含两个字符串表:

  • 保存各section名称的字符串
  • 保存符号表中各个符号名称的字符串

该函数实现功能:获取两个字符串表的基地址。

 2935 static int setup_load_info(struct load_info *info, int flags)
  2936 {
  2937     unsigned int i;
  2938 
  2939     /* Set up the convenience variables */
  2940     info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
  2941     info->secstrings = (void *)info->hdr
  2942         + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
  2943
  2944     /* Try to find a name early so we can log errors with a module name */
  2945     info->index.info = find_sec(info, ".modinfo");
  2946     if (!info->index.info)
  2947         info->name = "(missing .modinfo section)";
  2948     else
  2949         info->name = get_modinfo(info, "name");
  2950 
  2951     /* Find internal symbols and strings. */
  2952     for (i = 1; i < info->hdr->e_shnum; i++) {
  2953         if (info->sechdrs[i].sh_type == SHT_SYMTAB) {
  2954             info->index.sym = i;
  2955             info->index.str = info->sechdrs[i].sh_link;
  2956             info->strtab = (char *)info->hdr
  2957                 + info->sechdrs[info->index.str].sh_offset;
  2958             break;
  2959         }
    2960     }
  2961 
  2967     info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
  2973     /* This is temporary: point mod into copy of data. */
  2974     info->mod = (void *)info->hdr + info->sechdrs[info->index.mod].sh_offset;
  2975 
  2980     if (!info->name)
  2981         info->name = info->mod->name;                                                                 
  2982 
  2983     if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
  2984         info->index.vers = 0; /* Pretend no __versions section! */
  2985     else
  2986         info->index.vers = find_sec(info, "__versions");
  2988     info->index.pcpu = find_pcpusec(info);
  2990     return 0;
  2991 }

  第3673行:check_modstruct_version,检查struct_module符号的CRC校验码若校验码不相等,则提示“disagrees about version of symbol struct_module”。

  第3690行:第一次遍历section header table中所有entry,将每个entry中的sh_addr改写为:shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;

1.3.模块之间的依赖关系:

  系统运行中不只加载一个模块,模块可以随时添加进系统,也可以随时被卸载。这些内核模块之间并不是完全相对独立的,比如当一个模块引用到另一个模块中导出的符号时,这两个模块间就建立了依赖关系。因此,依赖关系只存在于模块与模块之间,模块与内核之间不构成依赖关系。内核必须能跟踪模块间的依赖关系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值