Skip to content

Commit

Permalink
Merge pull request #318 from philipc/write_addend
Browse files Browse the repository at this point in the history
Relocation writing fixes
  • Loading branch information
philipc committed Jun 3, 2021
2 parents 9620f42 + f0d6821 commit bea8f92
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 19 deletions.
15 changes: 15 additions & 0 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,11 +1151,26 @@ impl<E: Endian> Rela64<E> {
}

/// 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<E> {
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<E> {
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);
}
Expand Down
69 changes: 50 additions & 19 deletions src/write/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,22 @@ impl Object {

fn elf_has_relocation_addend(&self) -> Result<bool> {
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 {:?}",
Expand Down Expand Up @@ -157,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;
Expand Down Expand Up @@ -662,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,
Expand Down Expand Up @@ -793,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,
Expand Down Expand Up @@ -1076,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<E> {
Expand Down Expand Up @@ -1155,7 +1174,13 @@ impl<E: Endian> Elf for Elf32<E> {
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 {
Expand Down Expand Up @@ -1250,12 +1275,18 @@ impl<E: Endian> Elf for Elf64<E> {
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));
Expand Down
101 changes: 101 additions & 0 deletions tests/round_trip/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit bea8f92

Please sign in to comment.