-
-
[原创] 较新的SO中根据 GNU_HASH字段 文件函数符号查询方法
-
发表于: 2017-6-16 17:20 3053
-
由于比较新版本的编译生成的 SO 开始使用 .GNU_HASH 代替 .HASH 字段查询 符号表信息,特总结相关函数,希望对需要使用到的同学有所帮助:
static uint32_t gnuhash(const char* name_) { // 根据 需要查询的 符号字符串信息 计算出gnuhash类似 elfhash
uint32_t gnu_hash_ = 0;
int has_gnu_hash_ = 0;
if (!has_gnu_hash_) {
uint32_t h = 5381;
const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);
while (*name != 0) {
h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
}
gnu_hash_ = h;
has_gnu_hash_ = true;
}
return gnu_hash_;
}
static Elf64_Sym* soinfo_gnu_lookup(soinfo* si, uint32_t gnu_hash, const char* name) //使用 gnu_hash在GNU_HASH段中查询出符号偏移信息
{ // si为符号定义实现的so的soinfo信息, name为需要查找符号的字符串信息
Elf64_Sym* symtab_ = si->symtab;
const char* strtab_ = si->strtab;
size_t gnu_nbucket_ = si->gnu_nbucket_;
uint32_t* gnu_bucket_ = si->gnu_bucket_;
uint32_t* gnu_chain_ = si->gnu_chain_;
uint32_t gnu_maskwords_ = si->gnu_maskwords_;
uint32_t gnu_shift2_ = si->gnu_shift2_;
Elf64_Addr* gnu_bloom_filter_ = si->gnu_bloom_filter_;
uint32_t hash = gnu_hash;
uint32_t h2 = hash >> gnu_shift2_;
uint32_t bloom_mask_bits = sizeof(Elf64_Addr)*8;
uint32_t word_num = (hash / bloom_mask_bits) & gnu_maskwords_;
Elf64_Addr bloom_word = gnu_bloom_filter_[word_num];
// test against bloom filter
if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
return NULL;
}
// bloom test says "probably yes"...
uint32_t n = gnu_bucket_[hash % gnu_nbucket_];
if (n == 0) {
return NULL;
}
do {
Elf64_Sym* s = symtab_ + n;
// skip hidden versions when verneed == kVersymNotNeeded (0)
if (((gnu_chain_[n] ^ hash) >> 1) == 0 &&
strcmp(strtab_ + s->st_name, name) == 0) {
return s;
}
} while ((gnu_chain_[n++] & 1) == 0);
return NULL;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!