use crate::elf::{
ElfDynamic, ElfDynamicHashTab, ElfLayout, ElfSymbol, SymbolLookup, SymbolTableView,
};
use crate::{Result, memory::RegionAccess, segment::ElfSegments};
use core::fmt::Debug;
use gnu::ElfGnuHash;
use sysv::ElfHash;
mod gnu;
mod sysv;
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 = crate::elf::NativeElfLayout>(HashTableKind<L>);
enum HashTableKind<L: ElfLayout = crate::elf::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::<crate::elf::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: crate::relocation::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)?),
}))
}
#[inline]
pub fn count_syms(&self) -> usize {
match &self.0 {
HashTableKind::Gnu(hashtab) => hashtab.count_syms(),
HashTableKind::Sysv(hashtab) => hashtab.count_syms(),
}
}
}
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),
}
}
}