macro_rules! elf_gnu_hash_impl {
() => {
use core::slice;
use core::mem;
use elf::strtab::Strtab;
use super::sym;
pub fn hash(symbol: &str) -> u32 {
let bytes = symbol.as_bytes();
const HASH_SEED: u32 = 5381;
let mut hash = HASH_SEED;
for b in bytes {
hash = hash.wrapping_mul(32).wrapping_add(*b as u32).wrapping_add(hash);
}
hash
}
pub struct GnuHash<'process> {
nbuckets: u32,
symindex: usize,
shift2: u32,
maskbits: u32,
bloomwords: &'process [usize], maskwords_bitmask: u32,
buckets: &'process [u32],
hashvalues: &'process [u32],
symtab: &'process [sym::Sym],
}
impl<'process> GnuHash<'process> {
pub unsafe fn new(hashtab: *const u32, total_dynsyms: usize, symtab: &'process [sym::Sym]) -> GnuHash<'process> {
let nbuckets = *hashtab;
let symindex = *hashtab.offset(1) as usize;
let maskwords = *hashtab.offset(2) as usize; let shift2 = *hashtab.offset(3);
let bloomwords_ptr = hashtab.offset(4) as *const usize;
let buckets_ptr = bloomwords_ptr.offset(maskwords as isize) as *const u32;
let buckets = slice::from_raw_parts(buckets_ptr, nbuckets as usize);
let hashvalues_ptr = buckets_ptr.offset(nbuckets as isize);
let hashvalues = slice::from_raw_parts(hashvalues_ptr, total_dynsyms - symindex);
let bloomwords = slice::from_raw_parts(bloomwords_ptr, maskwords);
GnuHash {
nbuckets: nbuckets,
symindex: symindex,
shift2: shift2,
maskbits: mem::size_of::<usize>() as u32,
bloomwords: bloomwords,
hashvalues: hashvalues,
buckets: buckets,
maskwords_bitmask: ((maskwords as i32) - 1) as u32,
symtab: symtab,
}
}
#[inline(always)]
fn lookup(&self,
symbol: &str,
hash: u32,
strtab: &Strtab)
-> Option<&sym::Sym> {
let mut idx = self.buckets[(hash % self.nbuckets) as usize] as usize;
if idx == 0 {
return None;
}
let mut hash_idx = idx - self.symindex;
let hash = hash & !1;
loop {
let symbol_ = &self.symtab[idx];
let h2 = self.hashvalues[hash_idx];
idx += 1;
hash_idx += 1;
let name = &strtab[symbol_.st_name as usize];
if hash == (h2 & !1) && name == symbol {
return Some(symbol_);
}
if h2 & 1 == 1 {
break;
} }
None
}
#[inline(always)]
fn filter(&self, hash: u32) -> bool {
let bloom_idx = (hash / self.maskbits) & self.maskwords_bitmask;
let h2 = hash >> self.shift2;
let bitmask = (1u64 << (hash % self.maskbits)) | (1u64 << (h2 % self.maskbits));
let filter = self.bloomwords[bloom_idx as usize];
filter & (bitmask as usize) != (bitmask as usize) }
pub fn find(&self,
name: &str,
hash: u32,
strtab: &Strtab)
-> Option<&sym::Sym> {
if self.filter(hash) {
None
} else {
self.lookup(name, hash, strtab)
}
}
}
}}