Modultils工具源码分析之insmod篇 (完)

回到INSMOD_MAIN函数里。

 

1899       /* Do archdata again, this time we have the final addresses */

1900       if (add_archdata(f, &archdata))

1901              goto out;

1902

1903       /* Do kallsyms again, this time we have the final addresses */

1904       if (add_kallsyms(f, &kallsyms, force_kallsyms))

1905              goto out;

 

2函数在前面都看过了。add_archdata因为__archdata段已经存在,所以什么都没干。add_kallsyms用绝对地址重新生成kallsyms段的内容(现在的__kallsyms段才真正可用)。

 

1907       #ifdef COMPAT_2_0

1908              if (k_new_syscalls)

1909                     init_module(m_name, f, m_size, blob_name, noload, flag_load_map);

1910              else if (!noload)

1911                     old_init_module(m_name, f, m_size);

1912       #else

1913              init_module(m_name, f, m_size, blob_name, noload, flag_load_map);

1914       #endif

1915              if (errors) {

1916                     if (!noload)

1917                            delete_module(m_name);

1918                     goto out;

1919              }

1920              exit_status = 0;

1921

1922             out:

1923              if (dolock)

1924                     flock(fp, LOCK_UN);

1925              close(fp);

1926              if (!noload)

1927                     snap_shot(NULL, 0);

1928

1929              return exit_status;

1930      }

 

假定COMPAT_2.0没有定义。这已经是整个INSMOD_MAIN的最后工作了,不过这个工作也不轻松。其主体是init_module函数,该函数也在insmod.c中。

Insmod——init_module函数

1058       static int init_module(const char *m_name, struct obj_file *f,

1059                            unsigned long m_size, const char *blob_name,

1060                            unsigned int noload, unsigned int flag_load_map)

1061       {

1062              struct module *module;

1063              struct obj_section *sec;

1064              void *image;

1065              int ret = 0;

1066              tgt_long m_addr;

1067

1068              sec = obj_find_section(f, ".this");

1069              module = (struct module *) sec->contents;

1070              m_addr = sec->header.sh_addr;

1071

1072              module->size_of_struct = sizeof(*module);

1073              module->size = m_size;

1074              module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;

1075

1076              sec = obj_find_section(f, "__ksymtab");

1077              if (sec && sec->header.sh_size) {

1078                     module->syms = sec->header.sh_addr;

1079                     module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);

1080              }

1081              if (n_ext_modules_used) {

1082                     sec = obj_find_section(f, ".kmodtab");

1083                     module->deps = sec->header.sh_addr;

1084                     module->ndeps = n_ext_modules_used;

1085              }

1086              module->init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));

1087              module->cleanup = obj_symbol_final_value(f,

1088                     obj_find_symbol(f, "cleanup_module"));

1089      

1090              sec = obj_find_section(f, "__ex_table");

1091              if (sec) {

1092                     module->ex_table_start = sec->header.sh_addr;

1093                     module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;

1094              }

1095              sec = obj_find_section(f, ".text.init");

1096              if (sec) {

1097                     module->runsize = sec->header.sh_addr - m_addr;

1098              }

1099              sec = obj_find_section(f, ".data.init");

1100              if (sec) {

1101                     if (!module->runsize ||

1102                         module->runsize > sec->header.sh_addr - m_addr)

1103                            module->runsize = sec->header.sh_addr - m_addr;

1104              }

1105              sec = obj_find_section(f, ARCHDATA_SEC_NAME);

1106              if (sec && sec->header.sh_size) {

1107                     module->archdata_start = sec->header.sh_addr;

1108                     module->archdata_end = module->archdata_start + sec->header.sh_size;

1109              }

1110              sec = obj_find_section(f, KALLSYMS_SEC_NAME);

1111              if (sec && sec->header.sh_size) {

1112                     module->kallsyms_start = sec->header.sh_addr;

1113                     module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;

1114              }

1115              if (!arch_init_module(f, module))

1116                     return 0;

1117

1118              /*

1119              * Whew!  All of the initialization is complete.

1120              * Collect the final module image and give it to the kernel.

1121              */

1122              image = xmalloc(m_size);

1123              obj_create_image(f, image);

1124

1125              if (flag_load_map)

1126                     print_load_map(f);

1127

1128              if (blob_name) {

1129                     int fd, l;

1130                      fd=open(blob_name,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

1131                     if (fd < 0) {

1132                            error("open %s failed %m", blob_name);

1133                            ret = -1;

1134                     }

1135                     else {

1136                            if ((l = write(fd, image, m_size)) != m_size) {

1137                                   error("write %s failed %m", blob_name);

1138                                   ret = -1;

1139                            }

1140                            close(fd);

1141                     }

1142              }

1143

1144              if (ret == 0 && !noload) {

1145                     fflush(stdout);        /* Flush any debugging output */

1146                     ret = sys_init_module(m_name, (struct module *) image);

1147                     if (ret) {

1148                            error("init_module: %m");

1149                            lprintf("Hint: insmod errors can be caused by incorrect module parameters, "

1150                                   "including invalid IO or IRQ parameters");

1151                     }

1152              }

1153

1154              free(image);

1155

1156              return ret == 0;

1157      }

 

__ksymtab段里保存的是内核和模块导出的符号。这些符号对应于module里的syms。在前面已经看到过moduledeps对象对应于.kmodtab段。

除了runsize外,其他都很到理解。那么runsize是怎么回事呢?在内核里,所有只在系统初始化时使用一次的数据和代码都放入特殊的段里,也就是data.inittext.init段。这些段占用的空间会在系统启动后回收。

如果模块不是动态安装的,毫无疑问,它的初始化数据和代码都将放入这些段。那么如果模块是动态安装的,在模块编译的时候,它并不知道内核的这些段,必然是在自己文件里生成这2个段。这些段空间的回收就需要模块自己做。很自然,这些段一定是放在模块空间的末尾,这样才能使空间的回收最方便(其实前面的obj_load_order_prio函数已经说得很清楚了)。

因为,这2个段在模块初始化后,就不再使用也不应该使用(不管你释不释放),而且这2个段的先后顺序也不一定。所以,1095~1104行找出这2个段的起始地址到模块起始地址之差的最小值,这就是模块的runsize。不过,这个变量现在还没使用。

如果模块没有初始化的数据和代码,从代码中可以看出,runsize无法求得。

1115行的arch_init_modulex86体系下什么都不干,直接返回11122~1123行分配资源,构建模块影像。函数obj_create_imageobj_reloc.c中。

Insmod——obj_create_image函数

415  int

416  obj_create_image (struct obj_file *f, char *image)

417  {

418    struct obj_section *sec;

419    ElfW(Addr) base = f->baseaddr;

420

421    for (sec = f->load_order; sec ; sec = sec->load_next)

422      {

423        char *secimg;

424

425        if (sec->contents == 0)

426         continue;

427

428        secimg = image + (sec->header.sh_addr - base);

429

430        /* Note that we allocated data for NOBITS sections earlier.  */

431        memcpy(secimg, sec->contents, sec->header.sh_size);

432      }

433

434    return 1;

435          }

 

如果需要打印加载位图,则调用print_load_map函数,它还是在insmod.c中。

Insmod——print_load_map函数

300  static void print_load_map(struct obj_file *f)

301  {

302         struct obj_symbol *sym;

303         struct obj_symbol **all, **p;

304         struct obj_section *sec;

305         int load_map_cmp(const void *a, const void *b) {

306                struct obj_symbol **as = (struct obj_symbol **) a;

307                struct obj_symbol **bs = (struct obj_symbol **) b;

308                unsigned long aa = obj_symbol_final_value(f, *as);

309                unsigned long ba = obj_symbol_final_value(f, *bs);

310                return aa < ba ? -1 : aa > ba ? 1 : 0;

311         }

312         int i, nsyms, *loaded;

313

314         /* Report on the section layout.  */

315

316         lprintf("Sections:       Size      %-*s  Align",

317                (int) (2 * sizeof(void *)), "Address");

318 

319         for (sec = f->load_order; sec; sec = sec->load_next) {

320                int a;

321                unsigned long tmp;

322

323                for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)

324                       tmp >>= 1;

325                if (a == -1)

326                       a = 0;

327

328                lprintf("%-16s%08lx  %0*lx  2**%d",

329                       sec->name,

330                       (long)sec->header.sh_size,

331                       (int) (2 * sizeof(void *)),

332                       (long)sec->header.sh_addr,

333                       a);

334         }

335

336         /* Quick reference which section indicies are loaded.  */

337

338         loaded = alloca(sizeof(int) * (i = f->header.e_shnum));

339         while (--i >= 0)

340                loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;

341 

342         /* Collect the symbols we'll be listing.  */

343 

344         for (nsyms = i = 0; i < HASH_BUCKETS; ++i)

345                for (sym = f->symtab[i]; sym; sym = sym->next)

346                       if (sym->secidx <= SHN_HIRESERVE

347                           && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))

348                              ++nsyms;

349

350         all = alloca(nsyms * sizeof(struct obj_symbol *));

351

352         for (i = 0, p = all; i < HASH_BUCKETS; ++i)

353                for (sym = f->symtab[i]; sym; sym = sym->next)

354                       if (sym->secidx <= SHN_HIRESERVE

355                           && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))

356                              *p++ = sym;

357 

358         /* Sort them by final value.  */

359         qsort(all, nsyms, sizeof(struct obj_file *), load_map_cmp);

360 

361         /* And list them.  */

362         lprintf("/nSymbols:");

363         for (p = all; p < all + nsyms; ++p) {

364                char type = '?';

365                unsigned long value;

366

367                sym = *p;

368                if (sym->secidx == SHN_ABS) {

369                       type = 'A';

370                       value = sym->value;

371                } else if (sym->secidx == SHN_UNDEF) {

372                       type = 'U';

373                       value = 0;

374                } else {

375                       struct obj_section *sec = f->sections[sym->secidx];

376 

377                       if (sec->header.sh_type == SHT_NOBITS)

378                              type = 'B';

379                       else if (sec->header.sh_flags & SHF_ALLOC) {

380                              if (sec->header.sh_flags & SHF_EXECINSTR)

381                                     type = 'T';

382                              else if (sec->header.sh_flags & SHF_WRITE)

383                                     type = 'D';

384                              else

385                                     type = 'R';

386                       }

387                       value = sym->value + sec->header.sh_addr;

388                }

389

390                if (ELFW(ST_BIND) (sym->info) == STB_LOCAL)

391                       type = tolower(type);

392

393                lprintf("%0*lx %c %s", (int) (2 * sizeof(void *)), value,

394                       type, sym->name);

395         }

395          }

 

这个函数不复杂,就不说那么多了。另外,如果指定了要输出生成的模块到blob_name指定的文件,那么也保存它。

最后一步,调用sys_init_moduleimage指向的module内容拷贝到内核的module对象中。有没有注意到,前面的重定位工作都是以模块对象在内核中的地址为起始地址,来进行的(就是前面的m_addr),就是为了这一步的拷贝。经过这一步,我们的模块终于成为内核的一员,发挥它的作用。至此,insmod_main结束了。

你可能感兴趣的:(struct,image,Module,Parameters,工具,initialization)