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};
pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> =
XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>;
pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> =
XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>;
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, <<Xcoff as FileHeader>::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::Item> {
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()
}
}
#[allow(missing_docs)]
pub trait Rel: Debug + Pod {
type Word: Into<u64>;
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
}
}