Modultils工具源码分析之insmod篇 (12)
来源:互联网 发布:数据的逻辑结构包括 编辑:程序博客网 时间:2024/05/17 22:55
回到INSMOD_MAIN里。
1893 if (!obj_relocate(f, m_addr)) { /* DEPMOD */
1894 if (!noload)
1895 delete_module(m_name);
1896 goto out;
1897 }
函数obj_relocate在./modutils-2.4.0/obj/obj_reloc.c中。
Insmod——obj_relocate函数
269 int
270 obj_relocate (struct obj_file *f, ElfW(Addr) base)
271 {
272 int i, n = f->header.e_shnum;
273 int ret = 1;
274
275 /* Finalize the addresses of the sections. */
276
278 arch_finalize_section_address(f, base);
279
280 /* And iterate over all of the relocations. */
281
282 for (i = 0; i < n; ++i)
283 {
284 struct obj_section *relsec, *symsec, *targsec, *strsec;
285 ElfW(RelM) *rel, *relend;
286 ElfW(Sym) *symtab;
287 const char *strtab;
288
289 relsec = f->sections[i];
290 if (relsec->header.sh_type != SHT_RELM)
291 continue;
292
293 symsec = f->sections[relsec->header.sh_link];
294 targsec = f->sections[relsec->header.sh_info];
295 strsec = f->sections[symsec->header.sh_link];
296
297 rel = (ElfW(RelM) *)relsec->contents;
298 relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
299 symtab = (ElfW(Sym) *)symsec->contents;
300 strtab = (const char *)strsec->contents;
301
302 for (; rel < relend; ++rel)
303 {
304 ElfW(Addr) value = 0;
305 struct obj_symbol *intsym = NULL;
306 unsigned long symndx;
307 ElfW(Sym) *extsym = 0;
308 const char *errmsg;
309
310 /* Attempt to find a value to use for this relocation. */
311
312 symndx = ELFW(R_SYM)(rel->r_info);
313 if (symndx)
314 {
315 /* Note we've already checked for undefined symbols. */
316
317 extsym = &symtab[symndx];
318 if (ELFW(ST_BIND)(extsym->st_info) == STB_LOCAL)
319 {
320 /* Local symbols we look up in the local table to be sure
321 we get the one that is really intended. */
322 intsym = f->local_symtab[symndx];
323 }
324 else
325 {
326 /* Others we look up in the hash table. */
327 const char *name;
328 if (extsym->st_name)
329 name = strtab + extsym->st_name;
330 else
331 name = f->sections[extsym->st_shndx]->name;
332 intsym = obj_find_symbol(f, name);
333 }
334
335 value = obj_symbol_final_value(f, intsym);
336 }
337
338 #if SHT_RELM == SHT_RELA
339 #if defined(__alpha__) && defined(AXP_BROKEN_GAS)
340 /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
341 if (!extsym || !extsym->st_name ||
342 ELFW(ST_BIND)(extsym->st_info) != STB_LOCAL)
343 #endif
344 value += rel->r_addend;
345 #endif
346
347 /* Do it! */
348 switch (arch_apply_relocation(f,targsec,symsec,intsym,rel,value))
349 {
350 case obj_reloc_ok:
351 break;
352
353 case obj_reloc_overflow:
354 errmsg = "Relocation overflow";
355 goto bad_reloc;
356 case obj_reloc_dangerous:
357 errmsg = "Dangerous relocation";
358 goto bad_reloc;
359 case obj_reloc_unhandled:
360 errmsg = "Unhandled relocation";
361 goto bad_reloc;
362 case obj_reloc_constant_gp:
363 errmsg = "Modules compiled with -mconstant-gp cannot be loaded";
364 goto bad_reloc;
365 bad_reloc:
366 if (extsym)
367 {
368 error("%s of type %ld for %s", errmsg,
369 (long)ELFW(R_TYPE)(rel->r_info),
370 strtab + extsym->st_name);
371 }
372 else
373 {
374 error("%s of type %ld", errmsg,
375 (long)ELFW(R_TYPE)(rel->r_info));
376 }
377 ret = 0;
378 break;
379 }
380 }
381 }
382
383 /* Finally, take care of the patches. */
384
385 if (f->string_patches)
386 {
387 struct obj_string_patch_struct *p;
388 struct obj_section *strsec;
389 ElfW(Addr) strsec_base;
390 strsec = obj_find_section(f, ".kstrtab");
391 strsec_base = strsec->header.sh_addr;
392
393 for (p = f->string_patches; p ; p = p->next)
394 {
395 struct obj_section *targsec = f->sections[p->reloc_secidx];
396 *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
397 = strsec_base + p->string_offset;
398 }
399 }
400
401 if (f->symbol_patches)
402 {
403 struct obj_symbol_patch_struct *p;
404
405 for (p = f->symbol_patches; p; p = p->next)
406 {
407 struct obj_section *targsec = f->sections[p->reloc_secidx];
408 *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
409 = obj_symbol_final_value(f, p->sym);
410 }
411 }
412
413 return ret;
414 }
这个函数的逻辑也不复杂。首先,参数base在这里是m_addr——模块在内核的地址。而在模块elf文件里,段在内存的位置是假设文件从0地址加载而得出的,现在就要根据base值调整,函数arch_finalize_section_address在./modultils-2.4-/obj/obj_i386.c中。
Insmod——arch_finalize_section_address函数
230 int
231 arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
232 {
233 int i, n = f->header.e_shnum;
234
235 f->baseaddr = base;
236 for (i = 0; i < n; ++i)
237 f->sections[i]->header.sh_addr += base;
238 return 1;
239 }
接下来,开始处理重定位符号了。需要重定位的符号都可以从重定位段中找到(也只能从那里去找),需要重定位的符号一般都涉及指针、地址、外部符号这类在链接时才能确定的东西。因此,表示它们的Elf32_Sym结构中的st_value应该就是地址(实际上st_value只代表2种情况,在符号的段序号为SHN_COMMON时,这个值代表边界对齐值。而其他情况下代表被重定位符号相对保存它的段起始的偏移。还记得吗?段序号为SHN_COMMON的符号,如果对应文件内的外部符号——比如B文件引用了A文件里定义的变量,在前面已经被obj_allocate_commons函数处理了,符号的段序号都指向了.bss段的序号。而如果符号对应内核或已加载模块导出的符号,则被前面的add_kernel_symbols处理了,序号为SHN_HIRESERVE以上。)。
在elf文件里,段序号大于SHN_LORESERVE的符号,是没有对应的段的。因此,符号里的值就认为是绝对地址(见209行)。内核和已加载模块导出符号就处在这个区段。
前面已经看到,local属性的符号都存放在local_symtab中,外部符号和全局符号则存放在symtab的hash表里。找到存放符号的结构体后,计算符号的绝对地址,函数obj_symbol_final_value在./modutils-2.4.0/obj/obj_common.c中。
Insmod——obj_symbol_final_value函数
203 ElfW(Addr)
204 obj_symbol_final_value (struct obj_file *f, struct obj_symbol *sym)
205 {
206 if (sym)
207 {
208 if (sym->secidx >= SHN_LORESERVE)
209 return sym->value;
210
211 return sym->value + f->sections[sym->secidx]->header.sh_addr;
212 }
213 else
214 {
215 /* As a special case, a NULL sym has value zero. */
216 return 0;
217 }
218 }
对于类型是rela的重定位符号,因为有显式指定的偏移值r_addend,所以还要加上它。获得了绝对地址后,可已开始重定位操作了。函数arch_apply_relocation在obj_i386.c中。所涉及的重定位操作,参见elf文档,这里不多说了。
Insmod——arch_apply_relocation函数
90 enum obj_reloc
91 arch_apply_relocation (struct obj_file *f,
92 struct obj_section *targsec,
93 struct obj_section *symsec,
94 struct obj_symbol *sym,
95 Elf32_Rel *rel,
96 Elf32_Addr v)
97 {
98 struct i386_file *ifile = (struct i386_file *)f;
99 struct i386_symbol *isym = (struct i386_symbol *)sym;
100
101 Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
102 Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
103 Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0;
104
105 enum obj_reloc ret = obj_reloc_ok;
106
107 switch (ELF32_R_TYPE(rel->r_info))
108 {
109 case R_386_NONE:
110 break;
111
112 case R_386_32:
113 *loc += v;
114 break;
115
116 case R_386_PLT32:
117 case R_386_PC32:
118 *loc += v - dot;
119 break;
120
121 case R_386_GLOB_DAT:
122 case R_386_JMP_SLOT:
123 *loc = v;
124 break;
125
126 case R_386_RELATIVE:
127 *loc += f->baseaddr;
128 break;
129
130 case R_386_GOTPC:
131 assert(got != 0);
132 *loc += got - dot;
133 break;
134
135 case R_386_GOT32:
136 assert(isym != NULL);
137 if (!isym->gotent.reloc_done)
138 {
139 isym->gotent.reloc_done = 1;
140 *(Elf32_Addr *)(ifile->got->contents + isym->gotent.offset) = v;
141 }
142 *loc += isym->gotent.offset;
143 break;
144
145 case R_386_GOTOFF:
146 assert(got != 0);
147 *loc += v - got;
148 break;
149
150 default:
151 ret = obj_reloc_unhandled;
152 break;
153 }
154
155 return ret;
156 }
这个函数返回后,就剩下在加载文件的过程中额外生成的符号了。这些符号都通过链表保存在obj_file中。他们的重定位过程相当简单。
- Modultils工具源码分析之insmod篇 (12)
- Modultils工具源码分析之insmod篇 (1)
- Modultils工具源码分析之insmod篇 (2)
- Modultils工具源码分析之insmod篇 (3)
- Modultils工具源码分析之insmod篇 (3续)
- Modultils工具源码分析之insmod篇 (4)
- Modultils工具源码分析之insmod篇 (4续)
- Modultils工具源码分析之insmod篇 (5)
- Modultils工具源码分析之insmod篇 (6)
- Modultils工具源码分析之insmod篇 (7)
- Modultils工具源码分析之insmod篇 (8)
- Modultils工具源码分析之insmod篇 (9)
- Modultils工具源码分析之insmod篇 (10)
- Modultils工具源码分析之insmod篇 (11)
- Modultils工具源码分析之insmod篇 (完)
- Modultils工具源码分析之ksyms篇
- insmod源码分析
- insmod源码分析
- 在ubuntu 8.10下使用kermit
- Color命名空间
- DBOperation的缺省实现
- Static 的简介
- SQL函数调用
- Modultils工具源码分析之insmod篇 (12)
- [转]抽象数据类型
- 向表格中动态添加行
- [转]关于Activity和Task的设计思路和方法
- 如何设置Tomcat为后台服务启动
- 基于spring框架,以bean形式配置实例,用于获取oracle上已存在sequence的递增值。
- 返回单列的RowMapper实现
- 领导负责制
- 如何有效率地学习并精通一项技术