处理完命令行参数,INSMOD_MAIN接下来调用arch_create_got。这个函数在./modutils-2.4.0/obj/obj_i386.c中。
Insmod——arch_create_got函数
158 int
159 arch_create_got (struct obj_file *f)
160 {
161 struct i386_file *ifile = (struct i386_file *)f;
162 int i, n, offset = 0, gotneeded = 0;
163
164 n = ifile->root.header.e_shnum;
165 for (i = 0; i < n; ++i)
166 {
167 struct obj_section *relsec, *symsec, *strsec;
168 Elf32_Rel *rel, *relend;
169 Elf32_Sym *symtab;
170 const char *strtab;
171
172 relsec = ifile->root.sections[i];
173 if (relsec->header.sh_type != SHT_REL)
174 continue;
175
176 symsec = ifile->root.sections[relsec->header.sh_link];
177 strsec = ifile->root.sections[symsec->header.sh_link];
178
179 rel = (Elf32_Rel *)relsec->contents;
180 relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
181 symtab = (Elf32_Sym *)symsec->contents;
182 strtab = (const char *)strsec->contents;
183
184 for (; rel < relend; ++rel)
185 {
186 Elf32_Sym *extsym;
187 struct i386_symbol *intsym;
188 const char *name;
189
190 switch (ELF32_R_TYPE(rel->r_info))
191 {
192 case R_386_GOTPC:
193 case R_386_GOTOFF:
194 gotneeded = 1;
195 default:
196 continue;
197
198 case R_386_GOT32:
199 break;
200 }
201
202 extsym = &symtab[ELF32_R_SYM(rel->r_info)];
203 if (extsym->st_name)
204 name = strtab + extsym->st_name;
205 else
206 name = f->sections[extsym->st_shndx]->name;
207 intsym = (struct i386_symbol *)obj_find_symbol(&ifile->root, name);
208
209 if (!intsym->gotent.offset_done)
210 {
211 intsym->gotent.offset_done = 1;
212 intsym->gotent.offset = offset;
213 offset += 4;
214 }
215 }
216 }
217
218 if (offset > 0 || gotneeded)
219 ifile->got = obj_create_alloced_section(&ifile->root, ".got", 4, offset);
220
221 return 1;
222 }
这个函数的作用是创建文件的.GOT段。这是怎么回事呢?.GOT的全称是global offset table。在这个段里保存的是绝对地址,这些地址不受重定位的影响。如果程序需要直接引用符号的绝对地址,这些符号就必须在.GOT段中出现(原文:that symbol will have a global offset table entry)。什么情况下程序需要引用符号的绝对地址呢?这跟重定位操作的类型有关。重定位操作为类型R_386_GOTOFF、R_386_GOTPC及R_386_GOT32的符号,会使用.GOT段。
函数里使用了i386_file和i386_symbol结构,这2个结构定义在同一文件里。
34 struct i386_got_entry
35 {
36 int offset;
37 unsigned offset_done : 1;
38 unsigned reloc_done : 1;
39 };
40
41 struct i386_file
42 {
43 struct obj_file root;
44 struct obj_section *got;
45 };
46
47 struct i386_symbol
48 {
49 struct obj_symbol root;
50 struct i386_got_entry gotent;
51 };
这些结构都很简单,只是添加了些辅助控制位。
接下来,INSMOD_MAIN通过hide_special_symbols将符号“cleanup_module”,“init_module”,“kernel_version”的属性改为local,从而使其外部不可见。这个函数也在insmod.c里。
Insmod——hide_special_symbols函数
283 static void hide_special_symbols(struct obj_file *f)
284 {
285 struct obj_symbol *sym;
286 const char *const *p;
287 static const char *const specials[] =
288 {
289 "cleanup_module",
290 "init_module",
291 "kernel_version",
292 NULL
293 };
294
295 for (p = specials; *p; ++p)
296 if ((sym = obj_find_symbol(f, *p)) != NULL)
297 sym->info = ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
298 }
接下来,如果命令行参数来自文件,将文件名保存好,下面要从那里读出参数值。
1700 if (persist_parms && persist_name && *persist_name) {
1701 f->persist = persist_name;
1702 persist_name = NULL;
1703 }
1704
1705 if (persist_parms &&
1706 persist_name && !*persist_name) {
1707 /* -e "". This is ugly. Take the filename, compare it against
1708 * each of the module paths until we find a match on the start
1709 * of the filename, assume the rest is the relative path. Have
1710 * to do it this way because modprobe uses absolute filenames
1711 * for module names in modules.dep and the format of modules.dep
1712 * does not allow for any backwards compatible changes, so there
1713 * is nowhere to store the relative filename. The only way this
1714 * should fail to calculate a relative path is "insmod ./xxx", for
1715 * that case the user has to specify -e filename.
1716 */
1717 int j, l = strlen(filename);
1718 char *relative = NULL;
1719 char *p;
1720 for (i = 0; i < nmodpath; ++i) {
1721 p = modpath[i].path;
1722 j = strlen(p);
1723 while (j && p[j] == '/')
1724 --j;
1725 if (j < l && strncmp(filename, p, j) == 0 && filename[j] == '/') {