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 loop {
42 let reloc = self.relocations.next()?;
43 let endian = self.file.endian;
44 let cputype = self.file.header.cputype(endian);
45 if reloc.r_scattered(endian, cputype) {
46 continue;
49 }
50 let reloc = reloc.info(self.file.endian);
51 let flags = RelocationFlags::MachO {
52 r_type: reloc.r_type,
53 r_pcrel: reloc.r_pcrel,
54 r_length: reloc.r_length,
55 };
56 let g = E::Generic;
57 let unknown = (K::Unknown, E::Generic);
58 let (kind, encoding) = match cputype {
59 macho::CPU_TYPE_ARM => match (reloc.r_type, reloc.r_pcrel) {
60 (macho::ARM_RELOC_VANILLA, false) => (K::Absolute, g),
61 _ => unknown,
62 },
63 macho::CPU_TYPE_ARM64 | macho::CPU_TYPE_ARM64_32 => {
64 match (reloc.r_type, reloc.r_pcrel) {
65 (macho::ARM64_RELOC_UNSIGNED, false) => (K::Absolute, g),
66 (macho::ARM64_RELOC_ADDEND, _) => {
67 paired_addend = i64::from(reloc.r_symbolnum)
68 .wrapping_shl(64 - 24)
69 .wrapping_shr(64 - 24);
70 continue;
71 }
72 _ => unknown,
73 }
74 }
75 macho::CPU_TYPE_X86 => match (reloc.r_type, reloc.r_pcrel) {
76 (macho::GENERIC_RELOC_VANILLA, false) => (K::Absolute, g),
77 _ => unknown,
78 },
79 macho::CPU_TYPE_X86_64 => match (reloc.r_type, reloc.r_pcrel) {
80 (macho::X86_64_RELOC_UNSIGNED, false) => (K::Absolute, g),
81 (macho::X86_64_RELOC_SIGNED, true) => (K::Relative, E::X86RipRelative),
82 (macho::X86_64_RELOC_BRANCH, true) => (K::Relative, E::X86Branch),
83 (macho::X86_64_RELOC_GOT, true) => (K::GotRelative, g),
84 (macho::X86_64_RELOC_GOT_LOAD, true) => (K::GotRelative, E::X86RipRelativeMovq),
85 _ => unknown,
86 },
87 _ => unknown,
88 };
89 let size = 8 << reloc.r_length;
90 let target = if reloc.r_extern {
91 RelocationTarget::Symbol(SymbolIndex(reloc.r_symbolnum as usize))
92 } else {
93 RelocationTarget::Section(SectionIndex(reloc.r_symbolnum as usize))
94 };
95 let implicit_addend = paired_addend == 0;
96 let mut addend = paired_addend;
97 if reloc.r_pcrel {
98 match cputype {
104 macho::CPU_TYPE_X86 => {
105 addend -= 1 << reloc.r_length;
106 }
107 macho::CPU_TYPE_X86_64 => {
108 addend -= 1 << reloc.r_length;
109 match reloc.r_type {
110 macho::X86_64_RELOC_SIGNED_1 => addend -= 1,
111 macho::X86_64_RELOC_SIGNED_2 => addend -= 2,
112 macho::X86_64_RELOC_SIGNED_4 => addend -= 4,
113 _ => {}
114 }
115 }
116 _ => {}
118 }
119 }
120 return Some((
121 reloc.r_address as u64,
122 Relocation {
123 kind,
124 encoding,
125 size,
126 target,
127 addend,
128 implicit_addend,
129 flags,
130 },
131 ));
132 }
133 }
134}
135
136impl<'data, 'file, Mach, R> fmt::Debug for MachORelocationIterator<'data, 'file, Mach, R>
137where
138 Mach: MachHeader,
139 R: ReadRef<'data>,
140{
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 f.debug_struct("MachORelocationIterator").finish()
143 }
144}