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