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

/* Mark all sections sh_addr with their address in the
    temporary image. */
  /*
  * 将段在执行时的虚拟地址设为他们在临时内存映像中的地址.
  */
  sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;

/* Internal symbols and strings. */
  /*
  * 如果索引为i的段是符号表,则做相应的处理.目前目标文件只能有一个符号表,
  * 这个限制以后可能会有变化,所以下面的语句只会执行一次。
  */
  if (sechdrs[i].sh_type == SHT_SYMTAB) {
   /*
    * 用来保存符号表在段首部表中的索引
    */
   symindex = i;
   /*
    * strindex存储的是与当前段段相关的字符串表段的索引。
    */
   strindex = sechdrs[i].sh_link;
   /*
    * strtab存储的是与当前段相关的字符串表段的地址。
    */
   strtab = (char *)hdr + sechdrs[strindex].sh_offset;
  }
#ifndef CONFIG_MODULE_UNLOAD
  /* Don't load .exit sections */
  /*
  * 如果当前段是".exit"段(前缀是".exit"),则在段的标志中移除SHF_ALLOC
  * 标志,意思是当前段在执行过程中不需要占用内存。
  */
  if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))
   sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
#endif
 }
 /*
  * 查找".gnu.linkonce.this_module"段在段首部表中的索引
  */
 modindex = find_sec(hdr, sechdrs, secstrings,
      ".gnu.linkonce.this_module");
 if (!modindex) {
  printk(KERN_WARNING "No module found in object\n");
  err = -ENOEXEC;
  goto free_hdr;
 }
 /* This is temporary: point mod into copy of data. */
 /*
  * 将模块的地址暂时设为临时映像中段给出的地址。
  */
 mod = (void *)sechdrs[modindex].sh_addr;

/*
  * 如果没有找到符号表段,则跳转到free_hdr处处理
  */
 if (symindex == 0) {
  printk(KERN_WARNING "%s: module has no symbols (stripped?)\n",
        mod->name);
  err = -ENOEXEC;
  goto free_hdr;
 }

/*
  * 查找__versions段在段首部表中的索引
  */
 versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
    /*
  * 查找.modinfo段在段首部表中的索引
  */
 infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
 /*
  * 查找".data.percpu"段在段首部表中的索引
  */
 pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);

/* Don't keep modinfo and version sections. */
 /*
  * "__versions"和".modinfo"段在执行时不需要,因此移除SHF_ALLOC标志。
  */
 sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
 sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;

/* Check module struct version now, before we try to use module. */
 /*
  * 检查模块的版本信息。
  */
  *
 if (!check_modstruct_version(sechdrs, versindex, mod)) {
  err = -ENOEXEC;
  goto free_hdr;
 }

/*
  * 在.modinfo段查找vermagic变量对应的值。
  */
 modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
 /* This is allowed: modprobe --force will invalidate it. */
 if (!modmagic) {
  /*
  * 如果没有找到vermagic变量,则尝试强制加载模块。
  * 但是try_to_force_load()函数的实现依赖于CONFIG_MODULE_FORCE_LOAD
  * 宏是否定义。而该宏默认是没有定义的,所以这里会
  * 返回失败,看来内核并不推荐强制加载模块。
  */
  err = try_to_force_load(mod, "bad vermagic");
  if (err)
   goto free_hdr;
 } else if (!same_magic(modmagic, vermagic, versindex)) {
  printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
        mod->name, modmagic, vermagic);
  err = -ENOEXEC;
  goto free_hdr;
 }

/*
  * 在.modinfo段查找staging变量对应的值。
  */
 staging = get_modinfo(sechdrs, infoindex, "staging");
 if (staging) {
  /*
  * 从2.6.28版本起,内核代码的drivers下增加了一个staging目录,
  * 这个目录也是用来存放驱动程序,只是这里的驱动程序
  * 和上层目录不同,加载的时候内核日志会打印如下的语句:
  * MODULE_NAME: module is from the staging directory, the quality is unknown, you have been warned.
  * Greg KH于2008年6月10号在Linux内核邮件列表里发出一封信,宣布建
  * 立了另外一棵kernel tree,这就是Linux staging tree。Greg解释到,staging tree
  * 建立之目的是用来放置一些未充分测试或者因为一些其他原因
  * 未能进入内核的新增驱动程序和新增文件系统。
  */
  add_taint_module(mod, TAINT_CRAP);
  printk(KERN_WARNING "%s: module is from the staging directory,"
        " the quality is unknown, you have been warned.\n",
        mod->name);
 }

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

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