3.2-module分析

来源:互联网 发布:cms监控怎么改ip 编辑:程序博客网 时间:2024/05/19 06:15

/* This is where the real work happens */
SYSCALL_DEFINE3(init_module, void __user *, umod,
  unsigned long, len, const char __user *, uargs)
{
 struct module *mod;
 int ret = 0;

 /* Must have permission */
 if (!capable(CAP_SYS_MODULE) || modules_disabled)
  return -EPERM;

 /* Do all the hard work */
 mod = load_module(umod, len, uargs);
 if (IS_ERR(mod))
  return PTR_ERR(mod);

 blocking_notifier_call_chain(&module_notify_list,
   MODULE_STATE_COMING, mod);

 /* Set RO and NX regions for core */
 set_section_ro_nx(mod->module_core,
    mod->core_text_size,
    mod->core_ro_size,
    mod->core_size);

 /* Set RO and NX regions for init */
 set_section_ro_nx(mod->module_init,
    mod->init_text_size,
    mod->init_ro_size,
    mod->init_size);

 do_mod_ctors(mod);
 /* Start the module */
 if (mod->init != NULL)
  ret = do_one_initcall(mod->init);
 if (ret < 0) {
  /* Init routine failed: abort.  Try to protect us from
                   buggy refcounters. */
  mod->state = MODULE_STATE_GOING;
  synchronize_sched();
  module_put(mod);
  blocking_notifier_call_chain(&module_notify_list,
          MODULE_STATE_GOING, mod);
  free_module(mod);
  wake_up(&module_wq);
  return ret;
 }
 if (ret > 0) {
  printk(KERN_WARNING
"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
"%s: loading module anyway...\n",
         __func__, mod->name, ret,
         __func__);
  dump_stack();
 }

 /* Now it's a first class citizen!  Wake up anyone waiting for it. */
 mod->state = MODULE_STATE_LIVE;
 wake_up(&module_wq);
 blocking_notifier_call_chain(&module_notify_list,
         MODULE_STATE_LIVE, mod);

 /* We need to finish all async code before the module init sequence is done */
 async_synchronize_full();

 mutex_lock(&module_mutex);
 /* Drop initial reference. */
 module_put(mod);
 trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
 mod->num_symtab = mod->core_num_syms;
 mod->symtab = mod->core_symtab;
 mod->strtab = mod->core_strtab;
#endif
 unset_module_init_ro_nx(mod);
 module_free(mod, mod->module_init);
 mod->module_init = NULL;
 mod->init_size = 0;
 mod->init_ro_size = 0;
 mod->init_text_size = 0;
 mutex_unlock(&module_mutex);

 return 0;
}


static struct module *load_module(void __user *umod,
      unsigned long len,
      const char __user *uargs)
{
 struct load_info info = { NULL, };
 struct module *mod;
 long err;

 DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
        umod, len, uargs);
拷贝,检查可用性
 /* Copy in the blobs from userspace, check they are vaguely sane. */
 err = copy_and_check(&info, umod, len, uargs);
 if (err)
  return ERR_PTR(err);

 /* Figure out module layout, and allocate all the memory. */
 获取主要的段信息, 第一次重写,module layout CORE INIT生成,
 mod = layout_and_allocate(&info);
 if (IS_ERR(mod)) {
  err = PTR_ERR(mod);
  goto free_copy;
 }

 /* Now module is in final location, initialize linked lists, etc. */
 err = module_unload_init(mod);
 if (err)
  goto free_module;

 /* Now we've got everything in the final locations, we can
  * find optional sections. */
 find_module_sections(mod, &info);

 err = check_module_license_and_versions(mod);
 if (err)
  goto free_unload;

 /* Set up MODINFO_ATTR fields */
 setup_modinfo(mod, &info);

 /* Fix up syms, so that st_value is a pointer to location. */
 err = simplify_symbols(mod, &info);
 if (err < 0)
  goto free_modinfo;

 err = apply_relocations(mod, &info);
 if (err < 0)
  goto free_modinfo;

 err = post_relocation(mod, &info);
 if (err < 0)
  goto free_modinfo;

 flush_module_icache(mod);

 /* Now copy in args */
 mod->args = strndup_user(uargs, ~0UL >> 1);
 if (IS_ERR(mod->args)) {
  err = PTR_ERR(mod->args);
  goto free_arch_cleanup;
 }

 /* Mark state as coming so strong_try_module_get() ignores us. */
 mod->state = MODULE_STATE_COMING;

 /* Now sew it into the lists so we can get lockdep and oops
  * info during argument parsing.  No one should access us, since
  * strong_try_module_get() will fail.
  * lockdep/oops can run asynchronous, so use the RCU list insertion
  * function to insert in a way safe to concurrent readers.
  * The mutex protects against concurrent writers.
  */
 mutex_lock(&module_mutex);
 if (find_module(mod->name)) {
  err = -EEXIST;
  goto unlock;
 }

 /* This has to be done once we're sure module name is unique. */
 dynamic_debug_setup(info.debug, info.num_debug);
判断模块导出的符号是否已经存在
 /* Find duplicate symbols */
 err = verify_export_symbols(mod);
 if (err < 0)
  goto ddebug;

 module_bug_finalize(info.hdr, info.sechdrs, mod);
 list_add_rcu(&mod->list, &modules);
 mutex_unlock(&module_mutex);

 /* Module is ready to execute: parsing args may do that. */
 err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
 if (err < 0)
  goto unlink;

 /* Link in to syfs. */
 err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
 if (err < 0)
  goto unlink;

 /* Get rid of temporary copy and strmap. */
 kfree(info.strmap);
 free_copy(&info);

 /* Done! */
 trace_module_load(mod);
 return mod;

 unlink:
 mutex_lock(&module_mutex);
 /* Unlink carefully: kallsyms could be walking list. */
 list_del_rcu(&mod->list);
 module_bug_cleanup(mod);

 ddebug:
 dynamic_debug_remove(info.debug);
 unlock:
 mutex_unlock(&module_mutex);
 synchronize_sched();
 kfree(mod->args);
 free_arch_cleanup:
 module_arch_cleanup(mod);
 free_modinfo:
 free_modinfo(mod);
 free_unload:
 module_unload_free(mod);
 free_module:
 module_deallocate(mod, &info);
 free_copy:
 free_copy(&info);
 return ERR_PTR(err);
}

/* Call module constructors. */
static void do_mod_ctors(struct module *mod)
{
#ifdef CONFIG_CONSTRUCTORS
 unsigned long i;

 for (i = 0; i < mod->num_ctors; i++)
  mod->ctors[i]();
#endif
}

该函数将所有的设置了AHF_ALLOC的段分为4个类型:code, read-only data, read-write data, small data.
其中函数名字包含有init的放到INIT区域中,没有包含有init的放到CORE区域中,两个区域中的段都是text可执行代码段放在最前面
然后设置这些section header 中的sh_entsize为各自所在区域中的偏移。
该函数只是对section进行分类,并没有复制section。

/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
   might -- code, read-only data, read-write data, small data.  Tally
   sizes, and place the offsets into sh_entsize fields: high bit means it
   belongs in init. */
static void layout_sections(struct module *mod,
       const Elf_Ehdr *hdr,
       Elf_Shdr *sechdrs,
       const char *secstrings)
{
 static unsigned long const masks[][2] = {
  /* NOTE: all executable code must be the first section
   * in this array; otherwise modify the text_size
   * finder in the two loops below */
   四种类型
  { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
  { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
  { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
  { ARCH_SHF_SMALL | SHF_ALLOC, 0 }
 };
 unsigned int m, i;

 for (i = 0; i < hdr->e_shnum; i++)
  sechdrs[i].sh_entsize = ~0UL;

 DEBUGP("Core section allocation order:\n");
 从0开始,也就是先处理设置了SHF_EXECINSTR标识段(可执行的代码段)
 for (m = 0; m < ARRAY_SIZE(masks); ++m) {
  for (i = 0; i < hdr->e_shnum; ++i) {
   Elf_Shdr *s = &sechdrs[i];
         判断是否设置了数组中的标识,否就continue
   if ((s->sh_flags & masks[m][0]) != masks[m][0]
       || (s->sh_flags & masks[m][1])
    不为0
       || s->sh_entsize != ~0UL
       || strstarts(secstrings + s->sh_name, ".init"))
    continue;
   s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
   DEBUGP("\t%s\n", secstrings + s->sh_name);
  }
  设置CORE区域中代码段的长度
  if (m == 0)
   mod->core_text_size = mod->core_size;
 }

 DEBUGP("Init section allocation order:\n");
 for (m = 0; m < ARRAY_SIZE(masks); ++m) {
  for (i = 0; i < hdr->e_shnum; ++i) {
   Elf_Shdr *s = &sechdrs[i];

   if ((s->sh_flags & masks[m][0]) != masks[m][0]
       || (s->sh_flags & masks[m][1])
       || s->sh_entsize != ~0UL
       || !strstarts(secstrings + s->sh_name, ".init"))
    continue;
   s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
      | INIT_OFFSET_MASK);
   DEBUGP("\t%s\n", secstrings + s->sh_name);
  }
  设置INIT区域中代码段的长度
  if (m == 0)
   mod->init_text_size = mod->init_size;
 }
}

如果没有定义CONFIG_KALLSYMS那么该函数是空的,


static void layout_symtab(struct module *mod, struct load_info *info)
{
    符号的section(保存符号相关的信息)
 Elf_Shdr *symsect = info->sechdrs + info->index.sym;
 符号名字的section(保存符号的名字字符)
 Elf_Shdr *strsect = info->sechdrs + info->index.str;
 const Elf_Sym *src;
 unsigned int i, nsrc, ndst;

 /* Put symbol section at end of init part of module. */
 符号section 也加载,分配内存
 symsect->sh_flags |= SHF_ALLOC;
 分配入INIT区域,放在最后
 symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
      info->index.sym) | INIT_OFFSET_MASK;
 DEBUGP("\t%s\n", info->secstrings + symsect->sh_name);
   
 src = (void *)info->hdr + symsect->sh_offset;
 nsrc = symsect->sh_size / sizeof(*src);
 对每个符号进行分析
 for (ndst = i = 1; i < nsrc; ++i, ++src)
 如果符号没有定义,没有名字,没有对应的段,对应的段没有设置SHF_ALLOC, 对应的段不是可执行段,对应的段是INIT段
 那么这个符号是无效的,不需要处理,不属于CORE符号
  if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
   unsigned int j = src->st_name;
   是CORE符号则在strmap中设置对应的一段bit 表示strtab中的字符是属于CORE符号的。
   while (!__test_and_set_bit(j, info->strmap)
          && info->strtab[j])
    ++j;
   ++ndst;
  }
分析出来的CORE符号(不是符号名字)加入CORE区域,在整个模块的生存区域内一直存在
 /* Append room for core symbols at end of core part. */
 info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
 mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);

 /* Put string table section at end of init part of module. */
 strsect->sh_flags |= SHF_ALLOC;
 strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
      info->index.str) | INIT_OFFSET_MASK;
 DEBUGP("\t%s\n", info->secstrings + strsect->sh_name);

 /* Append room for core symbols' strings at end of core part. */
 info->stroffs = mod->core_size;
 __set_bit(0, info->strmap);
 mod->core_size += bitmap_weight(info->strmap, strsect->sh_size);
}


#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
/* Technically wrong, but this avoids compilation errors on some gcc
   versions. */
#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
#else
#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
#endif

#define ADDR    BITOP_ADDR(addr)

#define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "

/**
 * test_and_set_bit - Set a bit and return its old value
 * @nr: Bit to set
 * @addr: Address to count from
 *
 * This operation is atomic and cannot be reordered.
 * It also implies a memory barrier.
 */
static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
{
 int oldbit;

 asm volatile(LOCK_PREFIX "bts %2,%1\n\t"
       "sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");

 return oldbit;
}

原创粉丝点击