1use core::{fmt, slice};
2
3use crate::endian::Endianness;
4use crate::macho;
5use crate::read::{
6 ReadRef, Relocation, RelocationEncoding, RelocationFlags, RelocationKind, RelocationTarget,
7 SectionIndex, SymbolIndex,
8};
9
10use super::{MachHeader, MachOFile};
11
12pub type MachORelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
14 MachORelocationIterator<'data, 'file, macho::MachHeader32<Endian>, R>;
15pub type MachORelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
17 MachORelocationIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
18
19pub struct MachORelocationIterator<'data, 'file, Mach, R = &'data [u8]>
21where
22 Mach: MachHeader,
23 R: ReadRef<'data>,
24{
25 pub(super) file: &'file MachOFile<'data, Mach, R>,
26 pub(super) relocations: slice::Iter<'data, macho::Relocation<Mach::Endian>>,
27}
28
29impl<'data, 'file, Mach, R> Iterator for MachORelocationIterator<'data, 'file, Mach, R>
30where
31 Mach: MachHeader,
32 R: ReadRef<'data>,
33{
34 type Item = (u64, Relocation);
35
36 fn next(&mut self) -> Option<Self::Item> {
37 use RelocationEncoding as E;
38 use RelocationKind as K;
39
40 let mut paired_addend = 0;
41 let mut subtractor = None;
42 loop {
43 let reloc = self.relocations.next()?;
44 let endian = self.file.endian;
45 let cputype = self.file.header.cputype(endian);
46 if reloc.r_scattered(endian, cputype) {
47 continue;
50 }
51 let reloc = reloc.info(self.file.endian);
52 let flags = RelocationFlags::MachO {
53 r_type: reloc.r_type,
54 r_pcrel: reloc.r_pcrel,
55 r_length: reloc.r_length,
56 };
57 let mut size = 8 << reloc.r_length;
58 let g = E::Generic;
59 let unknown = (K::Unknown, E::Unknown);
60 let (kind, encoding) = match cputype {
61 macho::CPU_TYPE_ARM => match (reloc.r_type, reloc.r_pcrel) {
62 (macho::ARM_RELOC_VANILLA, false) => (K::Absolute, g),
63 _ => unknown,
64 },
65 macho::CPU_TYPE_ARM64 | macho::CPU_TYPE_ARM64_32 => {
66 match (reloc.r_type, reloc.r_pcrel) {
67 (macho::ARM64_RELOC_UNSIGNED, false) => (K::Absolute, g),
68 (macho::ARM64_RELOC_BRANCH26, true) => {
69 size = 26;
70 (K::PltRelative, E::AArch64Call)
71 }
72 (macho::ARM64_RELOC_ADDEND, _) => {
73 paired_addend = i64::from(reloc.r_symbolnum)
74 .wrapping_shl(64 - 24)
75 .wrapping_shr(64 - 24);
76 continue;
77 }
78 (macho::ARM64_RELOC_SUBTRACTOR, _) => {
79 subtractor = Some(SymbolIndex(reloc.r_symbolnum as usize));
80 continue;
81 }
82 _ => unknown,
83 }
84 }
85 macho::CPU_TYPE_X86 => match (reloc.r_type, reloc.r_pcrel) {
86 (macho::GENERIC_RELOC_VANILLA, false) => (K::Absolute, g),
87 _ => unknown,
88 },
89 macho::CPU_TYPE_X86_64 => match (reloc.r_type, reloc.r_pcrel) {
90 (macho::X86_64_RELOC_UNSIGNED, false) => (K::Absolute, g),
91 (macho::X86_64_RELOC_SIGNED, true) => (K::Relative, E::X86RipRelative),
92 (macho::X86_64_RELOC_BRANCH, true) => (K::PltRelative, E::X86Branch),
93 (macho::X86_64_RELOC_GOT, true) => (K::GotRelative, g),
94 (macho::X86_64_RELOC_GOT_LOAD, true) => (K::GotRelative, E::X86RipRelativeMovq),
95 (macho::X86_64_RELOC_SUBTRACTOR, _) => {
96 subtractor = Some(SymbolIndex(reloc.r_symbolnum as usize));
97 continue;
98 }
99 _ => unknown,
100 },
101 macho::CPU_TYPE_POWERPC | macho::CPU_TYPE_POWERPC64 => {
102 match (reloc.r_type, reloc.r_pcrel) {
103 (macho::PPC_RELOC_VANILLA, false) => (K::Absolute, g),
104 _ => unknown,
105 }
106 }
107 _ => unknown,
108 };
109 let target = if reloc.r_extern {
110 RelocationTarget::Symbol(SymbolIndex(reloc.r_symbolnum as usize))
111 } else {
112 RelocationTarget::Section(SectionIndex(reloc.r_symbolnum as usize))
113 };
114 let implicit_addend = paired_addend == 0;
115 let mut addend = paired_addend;
116 if reloc.r_pcrel {
117 match cputype {
123 macho::CPU_TYPE_X86 => {
124 addend -= 1 << reloc.r_length;
125 }
126 macho::CPU_TYPE_X86_64 => {
127 addend -= 1 << reloc.r_length;
128 match reloc.r_type {
129 macho::X86_64_RELOC_SIGNED_1 => addend -= 1,
130 macho::X86_64_RELOC_SIGNED_2 => addend -= 2,
131 macho::X86_64_RELOC_SIGNED_4 => addend -= 4,
132 _ => {}
133 }
134 }
135 _ => {}
137 }
138 }
139 return Some((
140 reloc.r_address as u64,
141 Relocation {
142 kind,
143 encoding,
144 size,
145 target,
146 subtractor,
147 addend,
148 implicit_addend,
149 flags,
150 },
151 ));
152 }
153 }
154}
155
156impl<'data, 'file, Mach, R> fmt::Debug for MachORelocationIterator<'data, 'file, Mach, R>
157where
158 Mach: MachHeader,
159 R: ReadRef<'data>,
160{
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.debug_struct("MachORelocationIterator").finish()
163 }
164}