服务器 频道

Freebsd内核模块源码实现以及应用探

    在先前的例子中,所有的符号地址都来自/dev/kmem,但是它确切的出处在哪里呢?它在内核中经常变化。这些符号存储在elf hash 表里面,每个连入内核的文件(object)都有它自己的符号表,在exp/symtable.c 有个例子 它在linker_files队列中查找第一个
  命名为kernel的条目,函数名被hash了,并被重新获得,符号找到之后它的value就可以改变了。
  
  int
  set_symbol(struct proc *p, struct set_symbol_args *uap)
  {
  
    linker_file_t lf;
    elf_file_t ef;
    unsigned long symnum;
    const Elf_Sym* symp = NULL;
    Elf_Sym new_symp;
    const char *strp;
    unsigned long hash;
    caddr_t address;
    int error = 0;
  
    mod_debug("Set symbol %s address 0x%x\n",uap->name,uap->address);
  
    lf = TAILQ_FIRST(&linker_files);
    ef = lf->priv;
  
    /* First, search hashed global symbols */参见elf鉴别
    hash = elf_hash(uap->name);     //通过对名字hash可以加快寻找速度,
    symnum = ef->buckets[hash % ef->nbuckets];//
  
    while (symnum != STN_UNDEF) {
      if (symnum >= ef->nchains) {
        printf("link_elf_lookup_symbol: corrupt symbol table\n");
        return ENOENT;
      }
  
      symp = ef->symtab + symnum;   //symtab节是静态符号节
      if (symp->st_name == 0) { //符号名字索引
        printf("link_elf_lookup_symbol: corrupt symbol table\n");
        return ENOENT;
      }
  
      strp = ef->strtab + symp->st_name; //符号名节
  
      if (!strcmp(uap->name, strp)) {
  
        /* found the symbol with the given name */
        if (symp->st_shndx != SHN_UNDEF || //关联的索引
          (symp->st_value != 0 && ELF_ST_TYPE(symp->st_info) == STT_FUNC )) { //符号类型,关联一个函数
  
          /* give some debug info */
          address = (caddr_t) ef->address + symp->st_value;
      //符号的地址 =模块的地址+st_value st_value表示文件偏移
          mod_debug("found %s at 0x%x!\n",uap->name,(uintptr_t)address);
  
          bcopy(symp,&new_symp,sizeof(Elf_Sym));
          new_symp.st_value = uap->address; //改变成新的地址
  
          address = (caddr_t) ef->address + new_symp.st_value;
          mod_debug("new address is 0x%x\n",(uintptr_t)address);
  
          /* set the address */
          bcopy(&new_symp,(ef->symtab + symnum),sizeof(Elf_Sym));
  
          break;
  
          break;
  
        } else
          return(ENOENT);
      }
  
      symnum = ef->chains[symnum];
    }
  
    /* for now this only looks at the global symbol table */
  
    return(error);
  }
  symtable是一个单独的模块,它将加载上面用过的所有系统调用,你可以通过set_sym工具来测试,它将击败tool/checkcall
0
相关文章