use crate::{
elf::{ElfLayout, ElfSymbol},
image::{SymbolExports, SymbolLookup},
object::CustomHash,
};
use alloc::{string::String, vec::Vec};
pub(crate) struct ObjectExports<L: ElfLayout> {
hashtab: CustomHash<String>,
names: Vec<String>,
symbols: Vec<ElfSymbol<L>>,
}
impl<L: ElfLayout> ObjectExports<L> {
#[inline]
pub(crate) fn empty() -> Self {
Self {
hashtab: CustomHash::with_capacity(0),
names: Vec::new(),
symbols: Vec::new(),
}
}
pub(crate) fn insert(&mut self, name: impl Into<String>, symbol: ElfSymbol<L>) {
let name = name.into();
if let Some(idx) = self.hashtab.find_idx(&name) {
if self.symbols[idx].is_weak() && !symbol.is_weak() {
self.symbols[idx] = symbol;
}
return;
}
let idx = self.symbols.len();
self.names.push(name.clone());
self.symbols.push(symbol);
self.hashtab.insert_unique(name, idx);
}
}
impl<L: ElfLayout> SymbolExports<L> for ObjectExports<L> {
#[inline]
fn symbols(&self) -> &[ElfSymbol<L>] {
&self.symbols
}
#[inline]
fn symbol_name<'exports>(&'exports self, symbol: &ElfSymbol<L>) -> Option<&'exports str> {
self.symbols
.iter()
.position(|entry| core::ptr::eq(entry, symbol))
.map(|idx| self.names[idx].as_str())
}
#[inline]
fn lookup<'exports>(
&'exports self,
lookup: &mut SymbolLookup<'_>,
) -> Option<&'exports ElfSymbol<L>> {
self.hashtab
.lookup_idx(lookup)
.map(|idx| &self.symbols[idx])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::elf::{ElfSectionIndex, ElfSymbolBind, ElfSymbolType, NativeElfLayout};
#[test]
fn strong_export_replaces_weak_export() {
let mut exports = ObjectExports::<NativeElfLayout>::empty();
let weak = ElfSymbol::synthetic(
0,
0x1000,
0,
ElfSymbolBind::WEAK,
ElfSymbolType::FUNC,
0,
ElfSectionIndex::ABS,
);
let strong = ElfSymbol::synthetic(
0,
0x2000,
0,
ElfSymbolBind::GLOBAL,
ElfSymbolType::FUNC,
0,
ElfSectionIndex::ABS,
);
exports.insert("symbol", weak);
exports.insert("symbol", strong);
let mut lookup = SymbolLookup::new("symbol");
let resolved = <ObjectExports<NativeElfLayout> as SymbolExports<NativeElfLayout>>::lookup(
&exports,
&mut lookup,
)
.expect("symbol should resolve");
assert_eq!(resolved.st_value(), 0x2000);
assert_eq!(
<ObjectExports<NativeElfLayout> as SymbolExports<NativeElfLayout>>::symbol_name(
&exports, resolved
),
Some("symbol"),
);
assert_eq!(
<ObjectExports<NativeElfLayout> as SymbolExports<NativeElfLayout>>::symbols(&exports)
.len(),
1
);
}
}