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