macho_core/format/
relocations.rs1use crate::error::{Error, Result};
2use crate::format::constants::R_SCATTERED;
3use crate::format::io::pod::{self, RawRelocationInfo};
4use crate::model::macho_file::MachoFile;
5use crate::model::relocation::{Relocation, ScatteredRelocation, StandardRelocation};
6use crate::model::section::Section;
7
8const MAX_RELOCS_PER_SECTION: usize = 1_000_000;
9
10pub fn relocations_for_section(
12 macho: &MachoFile<'_>,
13 section: &Section,
14) -> Result<Vec<Relocation>> {
15 let nreloc = section.nreloc as usize;
16 if nreloc == 0 {
17 return Ok(Vec::new());
18 }
19 if nreloc > MAX_RELOCS_PER_SECTION {
20 return Err(Error::format(format!(
21 "section {},{} claims {nreloc} relocations, exceeding limit of {MAX_RELOCS_PER_SECTION}",
22 section.segment_name, section.section_name
23 )));
24 }
25
26 let data = macho.bytes();
27 let endian = macho.endian();
28 let entry_size = size_of::<RawRelocationInfo>();
29 let offset = section.reloff.as_usize();
30
31 let max_cap = data.len().saturating_sub(offset) / entry_size;
32 let mut relocs = Vec::with_capacity(nreloc.min(max_cap));
33
34 for i in 0..nreloc {
35 let raw: RawRelocationInfo = pod::read_pod(data, offset + i * entry_size)?;
36 let r_address = endian.interpret_i32(raw.r_address);
37 let r_info = endian.interpret_u32(raw.r_symbolnum_and_flags);
38
39 let first_word = endian.interpret_u32(raw.r_address as u32);
43 if first_word & R_SCATTERED != 0 {
44 let address = first_word & 0x00FF_FFFF;
55 let reloc_type = ((first_word >> 24) & 0xF) as u8;
56 let length = ((first_word >> 28) & 0x3) as u8;
57 let pc_relative = (first_word >> 30) & 1 != 0;
58
59 relocs.push(Relocation::Scattered(ScatteredRelocation {
60 reloc_type,
61 length,
62 pc_relative,
63 address,
64 value: r_info as i32,
65 }));
66 } else {
67 let symbol_num = r_info & 0x00FF_FFFF;
74 let pc_relative = (r_info >> 24) & 1 != 0;
75 let length = ((r_info >> 25) & 0x3) as u8;
76 let is_extern = (r_info >> 27) & 1 != 0;
77 let reloc_type = ((r_info >> 28) & 0xF) as u8;
78
79 relocs.push(Relocation::Standard(StandardRelocation {
80 address: r_address as u32,
81 symbol_num,
82 pc_relative,
83 length,
84 is_extern,
85 reloc_type,
86 }));
87 }
88 }
89
90 Ok(relocs)
91}