diff --git a/src/read/macho/file.rs b/src/read/macho/file.rs index bc6fe258..368c28bb 100644 --- a/src/read/macho/file.rs +++ b/src/read/macho/file.rs @@ -192,6 +192,7 @@ where match self.header.cputype(self.endian) { macho::CPU_TYPE_ARM => Architecture::Arm, macho::CPU_TYPE_ARM64 => Architecture::Aarch64, + macho::CPU_TYPE_ARM64_32 => Architecture::Aarch64_Ilp32, macho::CPU_TYPE_X86 => Architecture::I386, macho::CPU_TYPE_X86_64 => Architecture::X86_64, macho::CPU_TYPE_MIPS => Architecture::Mips, diff --git a/src/read/macho/relocation.rs b/src/read/macho/relocation.rs index 35143f64..18e22ef7 100644 --- a/src/read/macho/relocation.rs +++ b/src/read/macho/relocation.rs @@ -53,13 +53,15 @@ where relative: reloc.r_pcrel, }, }, - macho::CPU_TYPE_ARM64 => match (reloc.r_type, reloc.r_pcrel) { - (macho::ARM64_RELOC_UNSIGNED, false) => RelocationKind::Absolute, - _ => RelocationKind::MachO { - value: reloc.r_type, - relative: reloc.r_pcrel, - }, - }, + macho::CPU_TYPE_ARM64 | macho::CPU_TYPE_ARM64_32 => { + match (reloc.r_type, reloc.r_pcrel) { + (macho::ARM64_RELOC_UNSIGNED, false) => RelocationKind::Absolute, + _ => RelocationKind::MachO { + value: reloc.r_type, + relative: reloc.r_pcrel, + }, + } + } macho::CPU_TYPE_X86 => match (reloc.r_type, reloc.r_pcrel) { (macho::GENERIC_RELOC_VANILLA, false) => RelocationKind::Absolute, _ => RelocationKind::MachO { diff --git a/src/write/macho.rs b/src/write/macho.rs index b50ffae8..0e082b69 100644 --- a/src/write/macho.rs +++ b/src/write/macho.rs @@ -675,39 +675,48 @@ impl<'a> Object<'a> { return Err(Error(format!("unimplemented relocation {:?}", reloc))); } }, - Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.addend) { - (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { - (false, macho::ARM64_RELOC_UNSIGNED) - } - (RelocationKind::Relative, RelocationEncoding::AArch64Call, 0) => { - (true, macho::ARM64_RELOC_BRANCH26) - } - // Non-zero addend, so we have to encode the addend separately - (RelocationKind::Relative, RelocationEncoding::AArch64Call, value) => { - // first emit the BR26 relocation - let reloc_info = macho::RelocationInfo { - r_address: reloc.offset as u32, - r_symbolnum, - r_pcrel: true, - r_length, - r_extern: true, - r_type: macho::ARM64_RELOC_BRANCH26, - }; - buffer.write(&reloc_info.relocation(endian)); - - // set up a separate relocation for the addend - r_symbolnum = value as u32; - (false, macho::ARM64_RELOC_ADDEND) + Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => { + match (reloc.kind, reloc.encoding, reloc.addend) { + (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { + (false, macho::ARM64_RELOC_UNSIGNED) + } + (RelocationKind::Relative, RelocationEncoding::AArch64Call, 0) => { + (true, macho::ARM64_RELOC_BRANCH26) + } + // Non-zero addend, so we have to encode the addend separately + ( + RelocationKind::Relative, + RelocationEncoding::AArch64Call, + value, + ) => { + // first emit the BR26 relocation + let reloc_info = macho::RelocationInfo { + r_address: reloc.offset as u32, + r_symbolnum, + r_pcrel: true, + r_length, + r_extern: true, + r_type: macho::ARM64_RELOC_BRANCH26, + }; + buffer.write(&reloc_info.relocation(endian)); + + // set up a separate relocation for the addend + r_symbolnum = value as u32; + (false, macho::ARM64_RELOC_ADDEND) + } + ( + RelocationKind::MachO { value, relative }, + RelocationEncoding::Generic, + 0, + ) => (relative, value), + _ => { + return Err(Error(format!( + "unimplemented relocation {:?}", + reloc + ))); + } } - ( - RelocationKind::MachO { value, relative }, - RelocationEncoding::Generic, - 0, - ) => (relative, value), - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, + } _ => { if let RelocationKind::MachO { value, relative } = reloc.kind { (relative, value) diff --git a/tests/round_trip/mod.rs b/tests/round_trip/mod.rs index fe33f51d..8f8dd79c 100644 --- a/tests/round_trip/mod.rs +++ b/tests/round_trip/mod.rs @@ -450,6 +450,96 @@ fn macho_x86_64() { assert_eq!(map.get(func1_offset - 1), None); } +#[test] +fn macho_any() { + for (arch, endian) in [ + (Architecture::Aarch64, Endianness::Little), + (Architecture::Aarch64_Ilp32, Endianness::Little), + /* TODO: + (Architecture::Arm, Endianness::Little), + */ + (Architecture::I386, Endianness::Little), + (Architecture::X86_64, Endianness::Little), + /* TODO: + (Architecture::PowerPc, Endianness::Big), + (Architecture::PowerPc64, Endianness::Big), + */ + ] + .iter() + .copied() + { + let mut object = write::Object::new(BinaryFormat::MachO, arch, endian); + + let section = object.section_id(write::StandardSection::Data); + object.append_section_data(section, &[1; 30], 4); + let symbol = object.section_symbol(section); + + object + .add_relocation( + section, + write::Relocation { + offset: 8, + size: 32, + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + symbol, + addend: 0, + }, + ) + .unwrap(); + if arch.address_size().unwrap().bytes() >= 8 { + object + .add_relocation( + section, + write::Relocation { + offset: 16, + size: 64, + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + symbol, + addend: 0, + }, + ) + .unwrap(); + } + + let bytes = object.write().unwrap(); + let object = read::File::parse(&*bytes).unwrap(); + println!("{:?}", object.architecture()); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), arch); + assert_eq!(object.endianness(), endian); + + let mut sections = object.sections(); + + let data = sections.next().unwrap(); + println!("{:?}", data); + assert_eq!(data.segment_name(), Ok(Some("__DATA"))); + assert_eq!(data.name(), Ok("__data")); + assert_eq!(data.kind(), SectionKind::Data); + + let mut relocations = data.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 32); + assert_eq!(relocation.addend(), 0); + + if arch.address_size().unwrap().bytes() >= 8 { + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 16); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!(relocation.addend(), 0); + } + } +} + #[cfg(feature = "xcoff")] #[test] fn xcoff_powerpc() {