frob section contents and sizes. */
/*
* err总是为0
*/
err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
if (err < 0)
goto free_mod;
/*
* 如果存在.data.percpu段,则为该段在内存中分配空间。
* 分配成功后,移除SHF_ALLOC标志,并且初始化module实例
* 的percpu成员。
*/
if (pcpuindex) {
/* We have a special allocation for this section. */
percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,
sechdrs[pcpuindex].sh_addralign,
mod->name);
if (!percpu) {
err = -ENOMEM;
goto free_mod;
}
sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
mod->percpu = percpu;
}
/* Determine total sizes, and put offsets in sh_entsize. For now
this is done generically; there doesn't appear to be any
special cases for the architectures. */
/*
* 对core section和init section中的大小及代码段的信息进行
* 统计
*/
layout_sections(mod, hdr, sechdrs, secstrings);
/*
* 处理符号表中的符号,返回值是core section尾部的
* 符号表的偏移。
*/
symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
secstrings, &stroffs, strmap);
/* Do the allocs. */
/*
* 为core section分配内存,初始化后存储在module实例
* 的module_core成员中。
*/
ptr = module_alloc_update_bounds(mod->core_size);
/*
* The pointer to this block is stored in the module structure
* which is inside the block. Just mark it as not being a
* leak.
*/
kmemleak_not_leak(ptr);
if (!ptr) {
err = -ENOMEM;
goto free_percpu;
}
memset(ptr, 0, mod->core_size);
mod->module_core = ptr;
/*
* 为init section分配内存,初始化后存储在module实例
* 的module_init成员中。
*/
ptr = module_alloc_update_bounds(mod->init_size);
/*
* The pointer to this block is stored in the module structure
* which is inside the block. This block doesn't need to be
* scanned as it contains data and code that will be freed
* after the module is initialized.
*/
kmemleak_ignore(ptr);
if (!ptr && mod->init_size) {
err = -ENOMEM;
goto free_core;
}
memset(ptr, 0, mod->init_size);
mod->module_init = ptr;
/* 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