Linux内核模块的加载过程(4)

/* Transfer each section which specifies SHF_ALLOC */
 DEBUGP("final section addresses:\n");
 /*
  * 遍历段首部表,拷贝需要占用内存的段到
  * init section 或core section,并且调整各个段的运行
  * 时地址。
  */
 for (i = 0; i < hdr->e_shnum; i++) {
  void *dest;

/*
  * 如果当前段执行时不占用内存,
  * 则不处理
  */
  if (!(sechdrs[i].sh_flags & SHF_ALLOC))
   continue;

/*
  * 如果段首部的sh_entsize的最高位设置的话,
  * 表示该段属于init section,则从module_init开始的内存中获取
  * 当前段应该存储的地址,否则从module_core开始的内存
  * 中获取当前段应该存储的地址。
  */
  if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK)
   dest = mod->module_init
    + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK);
  else
   dest = mod->module_core + sechdrs[i].sh_entsize;

/*
  * 将当前段的内容从ELF文件头拷贝到指定的
  * 段(init section或core section)中
  */
  if (sechdrs[i].sh_type != SHT_NOBITS)
   memcpy(dest, (void *)sechdrs[i].sh_addr,
          sechdrs[i].sh_size);
  /* Update sh_addr to point to copy in image. */
  /*
  * 更改段的运行时地址,sh_addr原先存储的地址是
  * 相对于ELF文件头的地址
  */
  sechdrs[i].sh_addr = (unsigned long)dest;
  DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
 }
 /* Module has been moved. */
 mod = (void *)sechdrs[modindex].sh_addr;
 kmemleak_load_module(mod, hdr, sechdrs, secstrings);

#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
 /*
  * 初始化多处理下用于引用计数的refptr成员
  */
 mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t),
          mod->name);
 if (!mod->refptr) {
  err = -ENOMEM;
  goto free_init;
 }
#endif
 /* Now we've moved module, initialize linked lists, etc. */
 /*
  * 初始化卸载模块时的处理
  */
 module_unload_init(mod);

/* add kobject, so we can reference it. */
 /*
  * 在sysfs中创建模块对应的对象,可以在通过/sys/module/module_name
  * 查看。
  */
 err = mod_sysfs_init(mod);
 if (err)
  goto free_unload;

/* Set up license info based on the info section */
 /*
  * 从.modinfo段获取license对应的值,检查是否兼容
  */
 set_license(mod, get_modinfo(sechdrs, infoindex, "license"));

/*
  * ndiswrapper is under GPL by itself, but loads proprietary modules.
  * Don't use add_taint_module(), as it would prevent ndiswrapper from
  * using GPL-only symbols it needs.
  */
 if (strcmp(mod->name, "ndiswrapper") == 0)
  add_taint(TAINT_PROPRIETARY_MODULE);

/* driverloader was caught wrongly pretending to be under GPL */
 if (strcmp(mod->name, "driverloader") == 0)
  add_taint_module(mod, TAINT_PROPRIETARY_MODULE);

/* Set up MODINFO_ATTR fields */
 /*
  * 根据.modinfo段设置模块信息。
  */
 setup_modinfo(mod, sechdrs, infoindex);

/* Fix up syms, so that st_value is a pointer to location. */
 /*
  * 解决当前模块对其他模块的符号引用问题,
  * 并找到符号对应的值的地址
  */
 err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
          mod);
 if (err < 0)
  goto cleanup;

/* Now we've got everything in the final locations, we can
  * find optional sections. */
 /*
  * 获取__param段的运行时地址,及其存储的
  * 对象的个数。
  */
 mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
          sizeof(*mod->kp), &mod->num_kp);
 /*
  * 获取__ksymtab段的运行时地址,及其存储的
  * 对象的个数。
  */
 mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
    sizeof(*mod->syms), &mod->num_syms);
 /*
  * 获取__kcrctab段的运行时地址。
  */
 mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
 /*
  * 获取__ksymtab_gpl段的运行时地址,及其存储的
  * 对象的个数。
  */
 mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl",
        sizeof(*mod->gpl_syms),
        &mod->num_gpl_syms);
 /*
  * 获取__kcrctab_gpl段的运行时地址。
  */     
 mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl");
 /*
  * 获取__ksymtab_gpl_future段的运行时地址,及其存储的
  * 对象的个数。
  */
 mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings,
        "__ksymtab_gpl_future",
        sizeof(*mod->gpl_future_syms),
        &mod->num_gpl_future_syms);
 /*
  * 获取__kcrctab_gpl_future段的运行时地址。
  */
 mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings,
        "__kcrctab_gpl_future");

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/bf168a7a8c38771e643a5f406db5752c.html