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