use crate::elf::{
ElfDynamic, ElfDynamicHashTab, ElfLayout, ElfSymbol, NativeElfLayout, SymbolLookup,
SymbolTableView,
};
use crate::{Result, memory::RegionAccess, relocation::RelocationArch, segment::ElfSegments};
use core::fmt::Debug;
use gnu::ElfGnuHash;
use sysv::ElfHash;
mod gnu;
mod sysv;
#[inline]
pub fn sysv_hash(name: &[u8]) -> u32 {
let mut hash = 0u32;
for &byte in name {
hash = (hash << 4) + u32::from(byte);
let high = hash & 0xf0000000;
if high != 0 {
hash ^= high >> 24;
}
hash &= !high;
}
hash
}
pub trait SymbolHash<L: ElfLayout> {
fn lookup<'sym, H>(
&self,
table: SymbolTableView<'sym, L, H>,
lookup: &mut SymbolLookup<'_>,
) -> Option<&'sym ElfSymbol<L>>;
}
pub struct HashTable<L: ElfLayout = NativeElfLayout>(HashTableKind<L>);
enum HashTableKind<L: ElfLayout = NativeElfLayout> {
Gnu(ElfGnuHash<L>),
Sysv(ElfHash),
}
impl<L: ElfLayout> Clone for HashTable<L> {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<L: ElfLayout> Clone for HashTableKind<L> {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Gnu(hashtab) => Self::Gnu(hashtab.clone()),
Self::Sysv(hashtab) => Self::Sysv(hashtab.clone()),
}
}
}
impl<L: ElfLayout> Debug for HashTable<L> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match &self.0 {
HashTableKind::Gnu(_) => write!(f, "GnuHash"),
HashTableKind::Sysv(_) => write!(f, "ElfHash"),
}
}
}
pub(in crate::elf) struct PreCompute {
pub(in crate::elf) gnuhash: u32,
pub(in crate::elf) hash: Option<u32>,
#[cfg(feature = "object")]
pub(in crate::elf) custom: Option<u64>,
}
impl PreCompute {
#[inline]
pub(in crate::elf) fn new(name: &str) -> Self {
let gnuhash = ElfGnuHash::<NativeElfLayout>::hash(name.as_bytes()) as u32;
Self {
gnuhash,
hash: None,
#[cfg(feature = "object")]
custom: None,
}
}
}
impl<L: ElfLayout> HashTable<L> {
pub(crate) fn from_dynamic<Arch, R>(
dynamic: &ElfDynamic<Arch>,
segments: &ElfSegments<R>,
) -> Result<Self>
where
Arch: RelocationArch<Layout = L>,
R: RegionAccess,
{
Ok(Self(match dynamic.hashtab {
ElfDynamicHashTab::Gnu(addr) => HashTableKind::Gnu(ElfGnuHash::parse(segments, addr)?),
ElfDynamicHashTab::Elf(addr) => HashTableKind::Sysv(ElfHash::parse(segments, addr)?),
}))
}
pub(crate) fn for_each<H>(
&self,
table: SymbolTableView<'_, L, H>,
visitor: &mut dyn FnMut(&ElfSymbol<L>),
) {
match &self.0 {
HashTableKind::Gnu(hashtab) => hashtab.for_each(table, visitor),
HashTableKind::Sysv(hashtab) => hashtab.for_each(table, visitor),
}
}
}
impl<L: ElfLayout> SymbolHash<L> for HashTable<L> {
fn lookup<'sym, H>(
&self,
table: SymbolTableView<'sym, L, H>,
lookup: &mut SymbolLookup<'_>,
) -> Option<&'sym ElfSymbol<L>> {
match &self.0 {
HashTableKind::Gnu(hashtab) => hashtab.lookup(table, lookup),
HashTableKind::Sysv(hashtab) => hashtab.lookup(table, lookup),
}
}
}