在先前的例子中,所有的符号地址都来自/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
Freebsd内核模块源码实现以及应用探
0
相关文章