Skip to content

Commit

Permalink
write/object: calculate relocation flags before adjusting addend
Browse files Browse the repository at this point in the history
This simplifies the code because we no longer need to avoid
modifying the addend in the relocation.

Also make the implicit addend handling clearer.
  • Loading branch information
philipc committed Dec 5, 2023
1 parent 7e4bb81 commit fedd590
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 77 deletions.
88 changes: 45 additions & 43 deletions src/write/coff/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,57 +99,59 @@ impl<'a> Object<'a> {

pub(crate) fn coff_relocation_flags(&self, reloc: &Relocation) -> Result<RelocationFlags> {
let typ = match self.architecture {
Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
(RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
(RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
(RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
(RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
(RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
(RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
(RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
(RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
(RelocationKind::Coff(x), _, _) => x,
Architecture::I386 => match (reloc.kind, reloc.size) {
(RelocationKind::Absolute, 16) => coff::IMAGE_REL_I386_DIR16,
(RelocationKind::Relative, 16) => coff::IMAGE_REL_I386_REL16,
(RelocationKind::Absolute, 32) => coff::IMAGE_REL_I386_DIR32,
(RelocationKind::ImageOffset, 32) => coff::IMAGE_REL_I386_DIR32NB,
(RelocationKind::SectionIndex, 16) => coff::IMAGE_REL_I386_SECTION,
(RelocationKind::SectionOffset, 32) => coff::IMAGE_REL_I386_SECREL,
(RelocationKind::SectionOffset, 7) => coff::IMAGE_REL_I386_SECREL7,
(RelocationKind::Relative, 32) => coff::IMAGE_REL_I386_REL32,
(RelocationKind::Coff(x), _) => x,
_ => {
return Err(Error(format!("unimplemented relocation {:?}", reloc)));
}
},
Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
(RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
(RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
(RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
(RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
(RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
(RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
(RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
(RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
(RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
(RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
(RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
(RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
(RelocationKind::Coff(x), _, _) => x,
Architecture::X86_64 => match (reloc.kind, reloc.size) {
(RelocationKind::Absolute, 64) => coff::IMAGE_REL_AMD64_ADDR64,
(RelocationKind::Absolute, 32) => coff::IMAGE_REL_AMD64_ADDR32,
(RelocationKind::ImageOffset, 32) => coff::IMAGE_REL_AMD64_ADDR32NB,
(RelocationKind::Relative, 32) => match reloc.addend {
-5 => coff::IMAGE_REL_AMD64_REL32_1,
-6 => coff::IMAGE_REL_AMD64_REL32_2,
-7 => coff::IMAGE_REL_AMD64_REL32_3,
-8 => coff::IMAGE_REL_AMD64_REL32_4,
-9 => coff::IMAGE_REL_AMD64_REL32_5,
_ => coff::IMAGE_REL_AMD64_REL32,
},
(RelocationKind::SectionIndex, 16) => coff::IMAGE_REL_AMD64_SECTION,
(RelocationKind::SectionOffset, 32) => coff::IMAGE_REL_AMD64_SECREL,
(RelocationKind::SectionOffset, 7) => coff::IMAGE_REL_AMD64_SECREL7,
(RelocationKind::Coff(x), _) => x,
_ => {
return Err(Error(format!("unimplemented relocation {:?}", reloc)));
}
},
Architecture::Arm => match (reloc.kind, reloc.size, reloc.addend) {
(RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM_ADDR32,
(RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM_ADDR32NB,
(RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM_REL32,
(RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM_SECTION,
(RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM_SECREL,
(RelocationKind::Coff(x), _, _) => x,
Architecture::Arm => match (reloc.kind, reloc.size) {
(RelocationKind::Absolute, 32) => coff::IMAGE_REL_ARM_ADDR32,
(RelocationKind::ImageOffset, 32) => coff::IMAGE_REL_ARM_ADDR32NB,
(RelocationKind::Relative, 32) => coff::IMAGE_REL_ARM_REL32,
(RelocationKind::SectionIndex, 16) => coff::IMAGE_REL_ARM_SECTION,
(RelocationKind::SectionOffset, 32) => coff::IMAGE_REL_ARM_SECREL,
(RelocationKind::Coff(x), _) => x,
_ => {
return Err(Error(format!("unimplemented relocation {:?}", reloc)));
}
},
Architecture::Aarch64 => match (reloc.kind, reloc.size, reloc.addend) {
(RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32,
(RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32NB,
(RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM64_SECTION,
(RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM64_SECREL,
(RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_ARM64_ADDR64,
(RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM64_REL32,
(RelocationKind::Coff(x), _, _) => x,
Architecture::Aarch64 => match (reloc.kind, reloc.size) {
(RelocationKind::Absolute, 32) => coff::IMAGE_REL_ARM64_ADDR32,
(RelocationKind::ImageOffset, 32) => coff::IMAGE_REL_ARM64_ADDR32NB,
(RelocationKind::SectionIndex, 16) => coff::IMAGE_REL_ARM64_SECTION,
(RelocationKind::SectionOffset, 32) => coff::IMAGE_REL_ARM64_SECREL,
(RelocationKind::Absolute, 64) => coff::IMAGE_REL_ARM64_ADDR64,
(RelocationKind::Relative, 32) => coff::IMAGE_REL_ARM64_REL32,
(RelocationKind::Coff(x), _) => x,
_ => {
return Err(Error(format!("unimplemented relocation {:?}", reloc)));
}
Expand All @@ -164,8 +166,8 @@ impl<'a> Object<'a> {
Ok(RelocationFlags::Coff { typ })
}

pub(crate) fn coff_adjust_addend(&self, relocation: &mut Relocation) -> i64 {
let constant = match self.architecture {
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 => {
Expand All @@ -187,8 +189,8 @@ impl<'a> Object<'a> {
},
_ => unimplemented!(),
};
relocation.addend -= constant;
constant
relocation.addend = addend;
true
}

pub(crate) fn coff_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result<u8> {
Expand Down
11 changes: 3 additions & 8 deletions src/write/elf/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,15 +459,10 @@ impl<'a> Object<'a> {
Ok(RelocationFlags::Elf { r_type })
}

pub(crate) fn elf_adjust_addend(&mut self, relocation: &mut Relocation) -> Result<i64> {
pub(crate) fn elf_adjust_addend(&mut self, _relocation: &mut Relocation) -> Result<bool> {
// Determine whether the addend is stored in the relocation or the data.
if self.elf_has_relocation_addend()? {
Ok(0)
} else {
let constant = relocation.addend;
relocation.addend = 0;
Ok(constant)
}
let implicit = !self.elf_has_relocation_addend()?;
Ok(implicit)
}

pub(crate) fn elf_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result<u8> {
Expand Down
10 changes: 4 additions & 6 deletions src/write/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ impl<'a> Object<'a> {
})
}

pub(crate) fn macho_adjust_addend(&mut self, relocation: &mut Relocation) -> i64 {
pub(crate) fn macho_adjust_addend(&mut self, relocation: &mut Relocation) -> bool {
let relative = match relocation.kind {
RelocationKind::Relative
| RelocationKind::GotRelative
Expand Down Expand Up @@ -370,21 +370,19 @@ impl<'a> Object<'a> {
// Check for relocations that use an explicit addend.
if self.architecture == Architecture::Aarch64 {
if relocation.encoding == RelocationEncoding::AArch64Call {
return 0;
return false;
}
if let RelocationKind::MachO { value, .. } = relocation.kind {
match value {
macho::ARM64_RELOC_BRANCH26
| macho::ARM64_RELOC_PAGE21
| macho::ARM64_RELOC_PAGEOFF12 => return 0,
| macho::ARM64_RELOC_PAGEOFF12 => return false,
_ => {}
}
}
}
// Signify implicit addend.
let constant = relocation.addend;
relocation.addend = 0;
constant
true
}

pub(crate) fn macho_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result<u8> {
Expand Down
32 changes: 16 additions & 16 deletions src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,36 +530,37 @@ impl<'a> Object<'a> {
BinaryFormat::Xcoff => self.xcoff_translate_relocation(&mut relocation),
_ => unimplemented!(),
}
let addend = match self.format {
let flags = match self.format {
#[cfg(feature = "coff")]
BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation),
BinaryFormat::Coff => self.coff_relocation_flags(&relocation)?,
#[cfg(feature = "elf")]
BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?,
BinaryFormat::Elf => self.elf_relocation_flags(&relocation)?,
#[cfg(feature = "macho")]
BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation),
BinaryFormat::MachO => self.macho_relocation_flags(&relocation)?,
#[cfg(feature = "xcoff")]
BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation),
BinaryFormat::Xcoff => self.xcoff_relocation_flags(&relocation)?,
_ => unimplemented!(),
};
let flags = match self.format {
let implicit = match self.format {
#[cfg(feature = "coff")]
BinaryFormat::Coff => self.coff_relocation_flags(&relocation)?,
BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation),
#[cfg(feature = "elf")]
BinaryFormat::Elf => self.elf_relocation_flags(&relocation)?,
BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?,
#[cfg(feature = "macho")]
BinaryFormat::MachO => self.macho_relocation_flags(&relocation)?,
BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation),
#[cfg(feature = "xcoff")]
BinaryFormat::Xcoff => self.xcoff_relocation_flags(&relocation)?,
BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation),
_ => unimplemented!(),
};
let relocation = RawRelocation {
let mut relocation = RawRelocation {
offset: relocation.offset,
symbol: relocation.symbol,
addend: relocation.addend,
flags,
};
if addend != 0 {
self.write_relocation_addend(section, &relocation, addend)?;
if implicit && relocation.addend != 0 {
self.write_relocation_addend(section, &relocation)?;
relocation.addend = 0;
}
self.sections[section.0].relocations.push(relocation);
Ok(())
Expand All @@ -569,7 +570,6 @@ impl<'a> Object<'a> {
&mut self,
section: SectionId,
relocation: &RawRelocation,
addend: i64,
) -> Result<()> {
let size = match self.format {
#[cfg(feature = "coff")]
Expand All @@ -585,8 +585,8 @@ impl<'a> Object<'a> {
let data = self.sections[section.0].data_mut();
let offset = relocation.offset as usize;
match size {
32 => data.write_at(offset, &U32::new(self.endian, addend as u32)),
64 => data.write_at(offset, &U64::new(self.endian, addend as u64)),
32 => data.write_at(offset, &U32::new(self.endian, relocation.addend as u32)),
64 => data.write_at(offset, &U64::new(self.endian, relocation.addend as u64)),
_ => {
return Err(Error(format!(
"unimplemented relocation addend {:?}",
Expand Down
8 changes: 4 additions & 4 deletions src/write/xcoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ impl<'a> Object<'a> {
Ok(RelocationFlags::Xcoff { r_rtype, r_rsize })
}

pub(crate) fn xcoff_adjust_addend(&mut self, relocation: &mut Relocation) -> i64 {
let constant = match relocation.kind {
pub(crate) fn xcoff_adjust_addend(&mut self, relocation: &mut Relocation) -> bool {
let addend = match relocation.kind {
RelocationKind::Relative => relocation.addend + 4,
_ => relocation.addend,
};
relocation.addend -= constant;
constant
relocation.addend = addend;
true
}

pub(crate) fn xcoff_relocation_size(&self, reloc: &crate::write::RawRelocation) -> Result<u8> {
Expand Down

0 comments on commit fedd590

Please sign in to comment.