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

/* Not a valid relocation section? */
  /*
  * 如果当前段附加的段的索引大于段的数目,
  * 则info不是一个有效的索引,不做处理。
  */
  if (info >= hdr->e_shnum)
   continue;

/* Don't bother with non-allocated sections */
  /*
  * 如果段在执行过程中不占内存,则
  * 不需要进行处理。
  */
  if (!(sechdrs[info].sh_flags & SHF_ALLOC))
   continue;

/*
  * 如果当前段包含重定向表项,但是没有补齐内容
  * 则调用apply_relocate来处理。(只关心64位系统)。
  */
  if (sechdrs[i].sh_type == SHT_REL)
   err = apply_relocate(sechdrs, strtab, symindex, i,mod);
        /*
  * 如果当前段包含重定向表项,但是可能有补齐内容
  * 则调用apply_relocate_add来处理。
  */
  else if (sechdrs[i].sh_type == SHT_RELA)
   err = apply_relocate_add(sechdrs, strtab, symindex, i,
      mod);
  if (err < 0)
   goto cleanup;
 }

/* Find duplicate symbols */
 /*
  * 检查模块导出的符号在内核导出的或其他模块
  * 导出的符号是否有重复的。
  */
 err = verify_export_symbols(mod);
 if (err < 0)
  goto cleanup;

/* Set up and sort exception table */
      /*
  * 获取__ex_table段的运行时地址,及其存储的
  * 对象的个数。
  */
 mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
        sizeof(*mod->extable), &mod->num_exentries);
 sort_extable(mod->extable, mod->extable + mod->num_exentries);

/* Finally, copy percpu area over. */
 percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
        sechdrs[pcpuindex].sh_size);

/*
  * 初始化模块中字符串表、符号表相关的成员,
        * 初始化core section中的字符串表和符号表。
  */
 add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
      symoffs, stroffs, secstrings, strmap);
 /*
  * 释放用于字符串表名称映射的位图
  */
 kfree(strmap);
 strmap = NULL;

if (!mod->taints) {
  /*
  * 处理用于debug的段,不关注这个。
  */
  struct _ddebug *debug;
  unsigned int num_debug;

debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
        sizeof(*debug), &num_debug);
  if (debug)
   dynamic_debug_setup(debug, num_debug);
 }

err = module_finalize(hdr, sechdrs, mod);
 if (err < 0)
  goto cleanup;

/* flush the icache in correct context */
 /*
  * get_fs是用来获取当前进程的地址限制,当当前的限制是
  * KERNEL_DS时,内核不会检查参数中的地址类型
  */
 old_fs = get_fs();
 set_fs(KERNEL_DS);

/*
  * Flush the instruction cache, since we've played with text.
  * Do it before processing of module parameters, so the module
  * can provide parameter accessor functions of its own.
  */
 /*
  * flush_icache_range函数中没有任何操作,不用考虑。
  */
 if (mod->module_init)
  flush_icache_range((unsigned long)mod->module_init,
      (unsigned long)mod->module_init
      + mod->init_size);
 flush_icache_range((unsigned long)mod->module_core,
      (unsigned long)mod->module_core + mod->core_size);

set_fs(old_fs);

mod->args = args;
 if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
  printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
        mod->name);

/* Now sew it into the lists so we can get lockdep and oops
  * info during argument parsing.  Noone should access us, since
  * strong_try_module_get() will fail.
  * lockdep/oops can run asynchronous, so use the RCU list insertion
  * function to insert in a way safe to concurrent readers.
  * The mutex protects against concurrent writers.
  */
 list_add_rcu(&mod->list, &modules);

/*
  * 解析插入模块时指定的参数。
  */
 err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
 if (err < 0)
  goto unlink;

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

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