From 6dea0d591a38acc11d833f1aff2da711e55edc59 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 10 Nov 2023 14:56:26 +1000 Subject: [PATCH] write/object: adjust addend using relocation flags Previously we adjusted the addend based on the relocation kind. For cases where the flags are derived from the relocation kind, this should not change the behaviour. For cases where the user supplies the flags, this ensures the adjustment is consistent with the flags that are actually used (since previously the kind and flags did not need to agree). This is preparation for removing the relocation kind field when the user supplies the flags. --- src/write/coff/object.rs | 61 ++++++++++++++++++++++++-------------- src/write/elf/object.rs | 5 +++- src/write/macho.rs | 63 +++++++++++++++++----------------------- src/write/mod.rs | 18 ++++++------ src/write/xcoff.rs | 18 ++++++++---- 5 files changed, 92 insertions(+), 73 deletions(-) diff --git a/src/write/coff/object.rs b/src/write/coff/object.rs index 8c5e5ed2..5fb8a7e0 100644 --- a/src/write/coff/object.rs +++ b/src/write/coff/object.rs @@ -166,31 +166,50 @@ impl<'a> Object<'a> { Ok(RelocationFlags::Coff { typ }) } - pub(crate) fn coff_adjust_addend(&self, relocation: &mut Relocation) -> bool { - let addend = match self.architecture { - Architecture::I386 | Architecture::Arm | Architecture::Aarch64 => match relocation.kind - { - RelocationKind::Relative => { - // IMAGE_REL_I386_REL32, IMAGE_REL_ARM_REL32, IMAGE_REL_ARM64_REL32 - relocation.addend + 4 + pub(crate) fn coff_adjust_addend( + &self, + relocation: &mut crate::write::RawRelocation, + ) -> Result { + let typ = if let RelocationFlags::Coff { typ } = relocation.flags { + typ + } else { + return Err(Error(format!("invalid relocation flags {:?}", relocation))); + }; + let offset = match self.architecture { + Architecture::Arm => { + if typ == coff::IMAGE_REL_ARM_REL32 { + 4 + } else { + 0 } - _ => relocation.addend, - }, - Architecture::X86_64 => match relocation.kind { - RelocationKind::Relative => { - // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5 - if relocation.addend <= -4 && relocation.addend >= -9 { - 0 - } else { - relocation.addend + 4 - } + } + Architecture::Aarch64 => { + if typ == coff::IMAGE_REL_ARM64_REL32 { + 4 + } else { + 0 + } + } + Architecture::I386 => { + if typ == coff::IMAGE_REL_I386_REL32 { + 4 + } else { + 0 } - _ => relocation.addend, + } + Architecture::X86_64 => match typ { + coff::IMAGE_REL_AMD64_REL32 => 4, + coff::IMAGE_REL_AMD64_REL32_1 => 5, + coff::IMAGE_REL_AMD64_REL32_2 => 6, + coff::IMAGE_REL_AMD64_REL32_3 => 7, + coff::IMAGE_REL_AMD64_REL32_4 => 8, + coff::IMAGE_REL_AMD64_REL32_5 => 9, + _ => 0, }, - _ => unimplemented!(), + _ => return Err(Error(format!("unimplemented relocation {:?}", relocation))), }; - relocation.addend = addend; - true + relocation.addend += offset; + Ok(true) } pub(crate) fn coff_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result { diff --git a/src/write/elf/object.rs b/src/write/elf/object.rs index d07820a7..4f34f670 100644 --- a/src/write/elf/object.rs +++ b/src/write/elf/object.rs @@ -459,7 +459,10 @@ impl<'a> Object<'a> { Ok(RelocationFlags::Elf { r_type }) } - pub(crate) fn elf_adjust_addend(&mut self, _relocation: &mut Relocation) -> Result { + pub(crate) fn elf_adjust_addend( + &mut self, + _relocation: &mut crate::write::RawRelocation, + ) -> Result { // Determine whether the addend is stored in the relocation or the data. let implicit = !self.elf_has_relocation_addend()?; Ok(implicit) diff --git a/src/write/macho.rs b/src/write/macho.rs index 03643e14..594c6f50 100644 --- a/src/write/macho.rs +++ b/src/write/macho.rs @@ -331,15 +331,19 @@ impl<'a> Object<'a> { }) } - pub(crate) fn macho_adjust_addend(&mut self, relocation: &mut Relocation) -> bool { - let relative = match relocation.kind { - RelocationKind::Relative - | RelocationKind::GotRelative - | RelocationKind::PltRelative - | RelocationKind::MachO { relative: true, .. } => true, - _ => false, + pub(crate) fn macho_adjust_addend( + &mut self, + relocation: &mut crate::write::RawRelocation, + ) -> Result { + let (r_type, r_pcrel) = if let RelocationFlags::MachO { + r_type, r_pcrel, .. + } = relocation.flags + { + (r_type, r_pcrel) + } else { + return Err(Error(format!("invalid relocation flags {:?}", relocation))); }; - if relative { + if r_pcrel { // For PC relative relocations on some architectures, the // addend does not include the offset required due to the // PC being different from the place of the relocation. @@ -347,19 +351,10 @@ impl<'a> Object<'a> { // addend here to account for this. let pcrel_offset = match self.architecture { Architecture::I386 => 4, - Architecture::X86_64 => match relocation.kind { - RelocationKind::MachO { - value: macho::X86_64_RELOC_SIGNED_1, - .. - } => 5, - RelocationKind::MachO { - value: macho::X86_64_RELOC_SIGNED_2, - .. - } => 6, - RelocationKind::MachO { - value: macho::X86_64_RELOC_SIGNED_4, - .. - } => 8, + Architecture::X86_64 => match r_type { + macho::X86_64_RELOC_SIGNED_1 => 5, + macho::X86_64_RELOC_SIGNED_2 => 6, + macho::X86_64_RELOC_SIGNED_4 => 8, _ => 4, }, // TODO: maybe missing support for some architectures and relocations @@ -367,22 +362,18 @@ impl<'a> Object<'a> { }; relocation.addend += pcrel_offset; } - // Check for relocations that use an explicit addend. - if self.architecture == Architecture::Aarch64 { - if relocation.encoding == RelocationEncoding::AArch64Call { - return false; - } - if let RelocationKind::MachO { value, .. } = relocation.kind { - match value { - macho::ARM64_RELOC_BRANCH26 - | macho::ARM64_RELOC_PAGE21 - | macho::ARM64_RELOC_PAGEOFF12 => return false, - _ => {} - } + // Determine if addend is implicit. + let implicit = if self.architecture == Architecture::Aarch64 { + match r_type { + macho::ARM64_RELOC_BRANCH26 + | macho::ARM64_RELOC_PAGE21 + | macho::ARM64_RELOC_PAGEOFF12 => false, + _ => true, } - } - // Signify implicit addend. - true + } else { + true + }; + Ok(implicit) } pub(crate) fn macho_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result { diff --git a/src/write/mod.rs b/src/write/mod.rs index 5548ed5c..7b1ad7ae 100644 --- a/src/write/mod.rs +++ b/src/write/mod.rs @@ -555,23 +555,23 @@ impl<'a> Object<'a> { BinaryFormat::Xcoff => self.xcoff_relocation_flags(&relocation)?, _ => unimplemented!(), }; + let mut relocation = RawRelocation { + offset: relocation.offset, + symbol: relocation.symbol, + addend: relocation.addend, + flags, + }; let implicit = match self.format { #[cfg(feature = "coff")] - BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation), + BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation)?, #[cfg(feature = "elf")] BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?, #[cfg(feature = "macho")] - BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation), + BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation)?, #[cfg(feature = "xcoff")] - BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation), + BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation)?, _ => unimplemented!(), }; - let mut relocation = RawRelocation { - offset: relocation.offset, - symbol: relocation.symbol, - addend: relocation.addend, - flags, - }; if implicit && relocation.addend != 0 { self.write_relocation_addend(section, &relocation)?; relocation.addend = 0; diff --git a/src/write/xcoff.rs b/src/write/xcoff.rs index 5f269494..4faa734b 100644 --- a/src/write/xcoff.rs +++ b/src/write/xcoff.rs @@ -82,13 +82,19 @@ impl<'a> Object<'a> { Ok(RelocationFlags::Xcoff { r_rtype, r_rsize }) } - pub(crate) fn xcoff_adjust_addend(&mut self, relocation: &mut Relocation) -> bool { - let addend = match relocation.kind { - RelocationKind::Relative => relocation.addend + 4, - _ => relocation.addend, + pub(crate) fn xcoff_adjust_addend( + &mut self, + relocation: &mut crate::write::RawRelocation, + ) -> Result { + let r_rtype = if let RelocationFlags::Xcoff { r_rtype, .. } = relocation.flags { + r_rtype + } else { + return Err(Error(format!("invalid relocation flags {:?}", relocation))); }; - relocation.addend = addend; - true + if r_rtype == xcoff::R_REL { + relocation.addend += 4; + } + Ok(true) } pub(crate) fn xcoff_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result {