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