use alloc::fmt; use core::fmt::Debug; use core::slice; use crate::pod::Pod; use crate::{xcoff, BigEndian as BE, Relocation}; use crate::read::{ReadRef, RelocationEncoding, RelocationKind, RelocationTarget, SymbolIndex}; use super::{FileHeader, SectionHeader, XcoffFile}; /// An iterator over the relocations in a `XcoffSection32`. pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> = XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>; /// An iterator over the relocations in a `XcoffSection64`. pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> = XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>; /// An iterator over the relocations in a `XcoffSection`. pub struct XcoffRelocationIterator<'data, 'file, Xcoff, R = &'data [u8]> where Xcoff: FileHeader, R: ReadRef<'data>, { #[allow(unused)] pub(super) file: &'file XcoffFile<'data, Xcoff, R>, pub(super) relocations: slice::Iter<'data, <::SectionHeader as SectionHeader>::Rel>, } impl<'data, 'file, Xcoff, R> Iterator for XcoffRelocationIterator<'data, 'file, Xcoff, R> where Xcoff: FileHeader, R: ReadRef<'data>, { type Item = (u64, Relocation); fn next(&mut self) -> Option { self.relocations.next().map(|relocation| { let encoding = RelocationEncoding::Generic; let (kind, addend) = match relocation.r_rtype() { xcoff::R_POS | xcoff::R_RL | xcoff::R_RLA | xcoff::R_BA | xcoff::R_RBA | xcoff::R_TLS => (RelocationKind::Absolute, 0), xcoff::R_REL | xcoff::R_BR | xcoff::R_RBR => (RelocationKind::Relative, -4), xcoff::R_TOC | xcoff::R_TOCL | xcoff::R_TOCU => (RelocationKind::Got, 0), r_type => (RelocationKind::Xcoff(r_type), 0), }; let size = (relocation.r_rsize() & 0x3F) + 1; let target = RelocationTarget::Symbol(SymbolIndex(relocation.r_symndx() as usize)); ( relocation.r_vaddr().into(), Relocation { kind, encoding, size, target, addend, implicit_addend: true, }, ) }) } } impl<'data, 'file, Xcoff, R> fmt::Debug for XcoffRelocationIterator<'data, 'file, Xcoff, R> where Xcoff: FileHeader, R: ReadRef<'data>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("XcoffRelocationIterator").finish() } } /// A trait for generic access to `Rel32` and `Rel64`. #[allow(missing_docs)] pub trait Rel: Debug + Pod { type Word: Into; fn r_vaddr(&self) -> Self::Word; fn r_symndx(&self) -> u32; fn r_rsize(&self) -> u8; fn r_rtype(&self) -> u8; } impl Rel for xcoff::Rel32 { type Word = u32; fn r_vaddr(&self) -> Self::Word { self.r_vaddr.get(BE) } fn r_symndx(&self) -> u32 { self.r_symndx.get(BE) } fn r_rsize(&self) -> u8 { self.r_rsize } fn r_rtype(&self) -> u8 { self.r_rtype } } impl Rel for xcoff::Rel64 { type Word = u64; fn r_vaddr(&self) -> Self::Word { self.r_vaddr.get(BE) } fn r_symndx(&self) -> u32 { self.r_symndx.get(BE) } fn r_rsize(&self) -> u8 { self.r_rsize } fn r_rtype(&self) -> u8 { self.r_rtype } }