chdrs[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);
}
/* Now copy in args */
/*
* 将插入模块时指定的参数从用于空间拷贝到args中。
*/
args = strndup_user(uargs, ~0UL >> 1);
if (IS_ERR(args)) {
err = PTR_ERR(args);
goto free_hdr;
}
/*
* 为与符号表相关的字符串表段在内存中分配用于映射的空间。
* sechdrs[strindex].sh_size是与符号表相关的字符串表段的大小。
* 这里分配的是一个位图,用于符号表中的符号名称的
* 映射。
*/
strmap = kzalloc(BITS_TO_LONGS(sechdrs[strindex].sh_size)
* sizeof(long), GFP_KERNEL);
if (!strmap) {
err = -ENOMEM;
goto free_mod;
}
/*
* 查找当前要加载的模块是否已经存在,如果存在,则
* 跳转到free_mod标签处。
*/
if (find_module(mod->name)) {
err = -EEXIST;
goto free_mod;
}
mod->state = MODULE_STATE_COMING;
/* Allow arches to