object/read/xcoff/
relocation.rs

1use alloc::fmt;
2use core::fmt::Debug;
3use core::slice;
4
5use crate::endian::BigEndian as BE;
6use crate::pod::Pod;
7use crate::read::{
8    ReadRef, Relocation, RelocationEncoding, RelocationFlags, RelocationKind, RelocationTarget,
9    SymbolIndex,
10};
11use crate::xcoff;
12
13use super::{FileHeader, SectionHeader, XcoffFile};
14
15/// An iterator for the relocations in an [`XcoffSection32`](super::XcoffSection32).
16pub type XcoffRelocationIterator32<'data, 'file, R = &'data [u8]> =
17    XcoffRelocationIterator<'data, 'file, xcoff::FileHeader32, R>;
18/// An iterator for the relocations in an [`XcoffSection64`](super::XcoffSection64).
19pub type XcoffRelocationIterator64<'data, 'file, R = &'data [u8]> =
20    XcoffRelocationIterator<'data, 'file, xcoff::FileHeader64, R>;
21
22/// An iterator for the relocations in an [`XcoffSection`](super::XcoffSection).
23pub struct XcoffRelocationIterator<'data, 'file, Xcoff, R = &'data [u8]>
24where
25    Xcoff: FileHeader,
26    R: ReadRef<'data>,
27{
28    #[allow(unused)]
29    pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
30    pub(super) relocations:
31        slice::Iter<'data, <<Xcoff as FileHeader>::SectionHeader as SectionHeader>::Rel>,
32}
33
34impl<'data, 'file, Xcoff, R> Iterator for XcoffRelocationIterator<'data, 'file, Xcoff, R>
35where
36    Xcoff: FileHeader,
37    R: ReadRef<'data>,
38{
39    type Item = (u64, Relocation);
40
41    fn next(&mut self) -> Option<Self::Item> {
42        self.relocations.next().map(|relocation| {
43            let r_rtype = relocation.r_rtype();
44            let r_rsize = relocation.r_rsize();
45            let flags = RelocationFlags::Xcoff { r_rtype, r_rsize };
46            let encoding = RelocationEncoding::Generic;
47            let (kind, addend) = match r_rtype {
48                xcoff::R_POS
49                | xcoff::R_RL
50                | xcoff::R_RLA
51                | xcoff::R_BA
52                | xcoff::R_RBA
53                | xcoff::R_TLS => (RelocationKind::Absolute, 0),
54                xcoff::R_REL | xcoff::R_BR | xcoff::R_RBR => (RelocationKind::Relative, -4),
55                xcoff::R_TOC | xcoff::R_TOCL | xcoff::R_TOCU => (RelocationKind::Got, 0),
56                _ => (RelocationKind::Unknown, 0),
57            };
58            let size = (r_rsize & 0x3F) + 1;
59            let target = RelocationTarget::Symbol(relocation.symbol());
60            (
61                relocation.r_vaddr().into(),
62                Relocation {
63                    kind,
64                    encoding,
65                    size,
66                    target,
67                    addend,
68                    implicit_addend: true,
69                    flags,
70                },
71            )
72        })
73    }
74}
75
76impl<'data, 'file, Xcoff, R> fmt::Debug for XcoffRelocationIterator<'data, 'file, Xcoff, R>
77where
78    Xcoff: FileHeader,
79    R: ReadRef<'data>,
80{
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        f.debug_struct("XcoffRelocationIterator").finish()
83    }
84}
85
86/// A trait for generic access to [`xcoff::Rel32`] and [`xcoff::Rel64`].
87#[allow(missing_docs)]
88pub trait Rel: Debug + Pod {
89    type Word: Into<u64>;
90    fn r_vaddr(&self) -> Self::Word;
91    fn r_symndx(&self) -> u32;
92    fn r_rsize(&self) -> u8;
93    fn r_rtype(&self) -> u8;
94
95    fn symbol(&self) -> SymbolIndex {
96        SymbolIndex(self.r_symndx() as usize)
97    }
98}
99
100impl Rel for xcoff::Rel32 {
101    type Word = u32;
102
103    fn r_vaddr(&self) -> Self::Word {
104        self.r_vaddr.get(BE)
105    }
106
107    fn r_symndx(&self) -> u32 {
108        self.r_symndx.get(BE)
109    }
110
111    fn r_rsize(&self) -> u8 {
112        self.r_rsize
113    }
114
115    fn r_rtype(&self) -> u8 {
116        self.r_rtype
117    }
118}
119
120impl Rel for xcoff::Rel64 {
121    type Word = u64;
122
123    fn r_vaddr(&self) -> Self::Word {
124        self.r_vaddr.get(BE)
125    }
126
127    fn r_symndx(&self) -> u32 {
128        self.r_symndx.get(BE)
129    }
130
131    fn r_rsize(&self) -> u8 {
132        self.r_rsize
133    }
134
135    fn r_rtype(&self) -> u8 {
136        self.r_rtype
137    }
138}