From e4b4113f15ddab7038635363cdf8d5fab0168218 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 3 Jun 2021 15:40:12 +1000 Subject: [PATCH 1/2] write: fix has_relocation_addend for most architectures Some were missing, some had it wrong. --- src/write/elf.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/write/elf.rs b/src/write/elf.rs index 0e96c9e6..cbe36c61 100644 --- a/src/write/elf.rs +++ b/src/write/elf.rs @@ -72,17 +72,22 @@ impl Object { fn elf_has_relocation_addend(&self) -> Result { Ok(match self.architecture { - Architecture::Arm => false, Architecture::Aarch64 => true, + Architecture::Arm => false, + Architecture::Avr => true, + Architecture::Bpf => false, Architecture::I386 => false, Architecture::X86_64 => true, - Architecture::S390x => true, + Architecture::Hexagon => true, Architecture::Mips => false, - Architecture::Mips64 => false, - Architecture::PowerPc => false, - Architecture::PowerPc64 => false, - Architecture::Riscv64 => false, - Architecture::Riscv32 => false, + Architecture::Mips64 => true, + Architecture::Msp430 => true, + Architecture::PowerPc => true, + Architecture::PowerPc64 => true, + Architecture::Riscv64 => true, + Architecture::Riscv32 => true, + Architecture::S390x => true, + Architecture::Sparc64 => true, _ => { return Err(Error(format!( "unimplemented architecture {:?}", From f0d6821c70b370d4d9f4865ab514ce1e433d378c Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Thu, 3 Jun 2021 15:42:25 +1000 Subject: [PATCH 2/2] write: fix mips64el relocation writing And test it. --- src/elf.rs | 15 ++++++ src/write/elf.rs | 50 +++++++++++++++----- tests/round_trip/mod.rs | 101 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 12 deletions(-) diff --git a/src/elf.rs b/src/elf.rs index 249ce8da..710f0ec8 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -1151,11 +1151,26 @@ impl Rela64 { } /// Calculate the `r_info` field given the `r_sym` and `r_type` components. + // TODO: add is_mips64el parameter pub fn r_info(endian: E, r_sym: u32, r_type: u32) -> U64 { U64::new(endian, (u64::from(r_sym) << 32) | u64::from(r_type)) } + #[allow(dead_code)] + pub(crate) fn r_info2(endian: E, is_mips64el: bool, r_sym: u32, r_type: u32) -> U64 { + let mut t = (u64::from(r_sym) << 32) | u64::from(r_type); + if is_mips64el { + t = (t >> 32) + | ((t & 0xff000000) << 8) + | ((t & 0x00ff0000) << 24) + | ((t & 0x0000ff00) << 40) + | ((t & 0x000000ff) << 56); + } + U64::new(endian, t) + } + /// Set the `r_info` field given the `r_sym` and `r_type` components. + // TODO: add is_mips64el parameter pub fn set_r_info(&mut self, endian: E, r_sym: u32, r_type: u32) { self.r_info = Self::r_info(endian, r_sym, r_type); } diff --git a/src/write/elf.rs b/src/write/elf.rs index cbe36c61..8ea2f2a1 100644 --- a/src/write/elf.rs +++ b/src/write/elf.rs @@ -162,6 +162,8 @@ impl Object { AddressSize::U64 => &elf64, }; let pointer_align = address_size.bytes() as usize; + let is_mips64el = + self.architecture == Architecture::Mips64 && self.endian == Endianness::Little; // Calculate offsets of everything. let mut offset = 0; @@ -667,15 +669,20 @@ impl Object { return Err(Error(format!("unimplemented relocation {:?}", reloc))); } }, - Architecture::Mips => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 16) => elf::R_MIPS_16, - (RelocationKind::Absolute, _, 32) => elf::R_MIPS_32, - (RelocationKind::Absolute, _, 64) => elf::R_MIPS_64, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); + Architecture::Mips | Architecture::Mips64 => { + match (reloc.kind, reloc.encoding, reloc.size) { + (RelocationKind::Absolute, _, 16) => elf::R_MIPS_16, + (RelocationKind::Absolute, _, 32) => elf::R_MIPS_32, + (RelocationKind::Absolute, _, 64) => elf::R_MIPS_64, + (RelocationKind::Elf(x), _, _) => x, + _ => { + return Err(Error(format!( + "unimplemented relocation {:?}", + reloc + ))); + } } - }, + } Architecture::Msp430 => match (reloc.kind, reloc.encoding, reloc.size) { (RelocationKind::Absolute, _, 32) => elf::R_MSP430_32, (RelocationKind::Absolute, _, 16) => elf::R_MSP430_16_BYTE, @@ -798,6 +805,7 @@ impl Object { let r_sym = symbol_offsets[reloc.symbol.0].index as u32; elf.write_rel( buffer, + is_mips64el, is_rela, Rel { r_offset: reloc.offset, @@ -1081,7 +1089,13 @@ trait Elf { fn write_file_header(&self, buffer: &mut dyn WritableBuffer, section: FileHeader); fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader); fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym); - fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel); + fn write_rel( + &self, + buffer: &mut dyn WritableBuffer, + is_mips64el: bool, + is_rela: bool, + rel: Rel, + ); } struct Elf32 { @@ -1160,7 +1174,13 @@ impl Elf for Elf32 { buffer.extend(bytes_of(&symbol)); } - fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) { + fn write_rel( + &self, + buffer: &mut dyn WritableBuffer, + _is_mips64el: bool, + is_rela: bool, + rel: Rel, + ) { let endian = self.endian; if is_rela { let rel = elf::Rela32 { @@ -1255,12 +1275,18 @@ impl Elf for Elf64 { buffer.extend(bytes_of(&symbol)); } - fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) { + fn write_rel( + &self, + buffer: &mut dyn WritableBuffer, + is_mips64el: bool, + is_rela: bool, + rel: Rel, + ) { let endian = self.endian; if is_rela { let rel = elf::Rela64 { r_offset: U64::new(endian, rel.r_offset), - r_info: elf::Rela64::r_info(endian, rel.r_sym, rel.r_type), + r_info: elf::Rela64::r_info2(endian, is_mips64el, rel.r_sym, rel.r_type), r_addend: I64::new(endian, rel.r_addend), }; buffer.extend(bytes_of(&rel)); diff --git a/tests/round_trip/mod.rs b/tests/round_trip/mod.rs index 57496446..9a887d98 100644 --- a/tests/round_trip/mod.rs +++ b/tests/round_trip/mod.rs @@ -225,6 +225,107 @@ fn elf_x86_64() { assert_eq!(map.get(func1_offset - 1), None); } +#[test] +fn elf_any() { + for (arch, endian) in [ + (Architecture::Aarch64, Endianness::Little), + (Architecture::Arm, Endianness::Little), + (Architecture::Avr, Endianness::Little), + (Architecture::Bpf, Endianness::Little), + (Architecture::I386, Endianness::Little), + (Architecture::X86_64, Endianness::Little), + (Architecture::Hexagon, Endianness::Little), + (Architecture::Mips, Endianness::Little), + (Architecture::Mips64, Endianness::Little), + (Architecture::Msp430, Endianness::Little), + (Architecture::PowerPc, Endianness::Big), + (Architecture::PowerPc64, Endianness::Big), + (Architecture::Riscv32, Endianness::Little), + (Architecture::Riscv64, Endianness::Little), + (Architecture::S390x, Endianness::Big), + (Architecture::Sparc64, Endianness::Big), + ] + .iter() + .copied() + { + let mut object = write::Object::new(BinaryFormat::Elf, 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::Elf); + assert_eq!(object.architecture(), arch); + assert_eq!(object.endianness(), endian); + + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + println!("{:?}", section); + assert_eq!(section.name(), Ok("")); + assert_eq!(section.kind(), SectionKind::Metadata); + assert_eq!(section.address(), 0); + assert_eq!(section.size(), 0); + + let data = sections.next().unwrap(); + println!("{:?}", 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); + } + } +} + #[test] fn macho_x86_64() { let mut object = write::Object::new(