/* 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;