#![deny(clippy::arithmetic_side_effects)]
use crate::error::Result;
use crate::macho::read::consts::{N_ABS, N_INDR, N_SECT, N_UNDF};
use crate::macho::read::{AtomRelocation, Atomization, ObjectFile, Symbol, SymbolKind};
use crate::symbols::{DefinitionKind, SymbolName, SymbolUse};
pub const NOT_GLOBAL: u32 = u32::MAX;
#[derive(Debug)]
pub struct LinkObject<'a> {
pub file: ObjectFile<'a>,
pub atoms: Atomization,
pub names: Vec<SymbolName<'a>>,
pub uses: Vec<SymbolUse>,
pub global_symbols: Vec<u32>,
pub global_of_symbol: Vec<u32>,
pub relocations: Vec<Vec<AtomRelocation>>,
}
pub const AUX_PRIVATE_EXTERN: u64 = 1;
impl<'a> LinkObject<'a> {
pub fn new(file: ObjectFile<'a>) -> Result<Self> {
let atoms = Atomization::new(&file)?;
let symtab = file.symbols();
let mut names = Vec::new();
let mut uses = Vec::new();
let mut global_symbols = Vec::new();
let mut global_of_symbol = vec![NOT_GLOBAL; symtab.len()];
for symbol in symtab.iter() {
let symbol = symbol?;
if !symbol.is_external() {
continue;
}
let use_ = symbol_use(&symbol);
let index = u32::try_from(names.len()).unwrap_or(NOT_GLOBAL);
if let Some(slot) = usize::try_from(symbol.index)
.ok()
.and_then(|i| global_of_symbol.get_mut(i))
{
*slot = index;
}
names.push(SymbolName::new(symbol.name));
uses.push(use_);
global_symbols.push(symbol.index);
}
Ok(Self {
file,
atoms,
names,
uses,
global_symbols,
global_of_symbol,
relocations: Vec::new(),
})
}
pub fn load_relocations(&mut self) -> Result<()> {
let mut all = Vec::with_capacity(self.file.sections().len());
for index in 0..self.file.sections().len() {
all.push(self.atoms.relocations(&self.file, index)?);
}
self.relocations = all;
Ok(())
}
pub fn defined_names(file: &ObjectFile<'a>) -> Result<Vec<SymbolName<'a>>> {
let mut out = Vec::new();
for symbol in file.symbols().iter() {
let symbol = symbol?;
if symbol.is_external() && (symbol.is_defined() || symbol.is_common()) {
out.push(SymbolName::new(symbol.name));
}
}
Ok(out)
}
}
#[must_use]
pub fn symbol_use(symbol: &Symbol<'_>) -> SymbolUse {
let aux = u64::from(symbol.is_private_external());
match symbol.n_type & 0x0e {
N_SECT | N_ABS => SymbolUse::Definition {
kind: if symbol.is_weak_def() {
DefinitionKind::Weak
} else {
DefinitionKind::Regular
},
aux,
},
N_UNDF if symbol.n_value != 0 => SymbolUse::Definition {
kind: DefinitionKind::Common,
aux: symbol.n_value,
},
N_UNDF => SymbolUse::Reference {
weak: symbol.is_weak_ref(),
},
N_INDR => SymbolUse::Definition {
kind: DefinitionKind::Regular,
aux,
},
_ => match symbol.kind() {
SymbolKind::PreboundUndefined => SymbolUse::Reference { weak: false },
_ => SymbolUse::Ignore,
},
}
}