Skip to main content

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                    subtractor: None,
68                    addend,
69                    implicit_addend: true,
70                    flags,
71                },
72            )
73        })
74    }
75}
76
77impl<'data, 'file, Xcoff, R> fmt::Debug for XcoffRelocationIterator<'data, 'file, Xcoff, R>
78where
79    Xcoff: FileHeader,
80    R: ReadRef<'data>,
81{
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        f.debug_struct("XcoffRelocationIterator").finish()
84    }
85}
86
87/// A trait for generic access to [`xcoff::Rel32`] and [`xcoff::Rel64`].
88#[allow(missing_docs)]
89pub trait Rel: Debug + Pod {
90    type Word: Into<u64>;
91    fn r_vaddr(&self) -> Self::Word;
92    fn r_symndx(&self) -> u32;
93    fn r_rsize(&self) -> u8;
94    fn r_rtype(&self) -> u8;
95
96    fn symbol(&self) -> SymbolIndex {
97        SymbolIndex(self.r_symndx() as usize)
98    }
99}
100
101impl Rel for xcoff::Rel32 {
102    type Word = u32;
103
104    fn r_vaddr(&self) -> Self::Word {
105        self.r_vaddr.get(BE)
106    }
107
108    fn r_symndx(&self) -> u32 {
109        self.r_symndx.get(BE)
110    }
111
112    fn r_rsize(&self) -> u8 {
113        self.r_rsize
114    }
115
116    fn r_rtype(&self) -> u8 {
117        self.r_rtype
118    }
119}
120
121impl Rel for xcoff::Rel64 {
122    type Word = u64;
123
124    fn r_vaddr(&self) -> Self::Word {
125        self.r_vaddr.get(BE)
126    }
127
128    fn r_symndx(&self) -> u32 {
129        self.r_symndx.get(BE)
130    }
131
132    fn r_rsize(&self) -> u8 {
133        self.r_rsize
134    }
135
136    fn r_rtype(&self) -> u8 {
137        self.r_rtype
138    }
139}