From 09cc9952dfcca3a10bbd5acba02bb18aba8aab6e Mon Sep 17 00:00:00 2001 From: Steven Casper Date: Thu, 8 Aug 2024 22:20:41 -0400 Subject: [PATCH] Support R_MIPS_GPREL16 relocations correctly (#88) * Support R_MIPS_GPREL16 relocations correctly symbols defined in the same file require adding a special ri_gp_value from the .reginfo section to their relocation calculations. * Run nightly rustfmt * Prevent potential panic when slicing .reginfo --- objdiff-core/src/arch/arm.rs | 1 + objdiff-core/src/arch/mips.rs | 38 +++++++++++++++++++++++++++++++---- objdiff-core/src/arch/mod.rs | 11 +++++++--- objdiff-core/src/arch/ppc.rs | 1 + objdiff-core/src/arch/x86.rs | 1 + objdiff-core/src/obj/read.rs | 2 +- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/objdiff-core/src/arch/arm.rs b/objdiff-core/src/arch/arm.rs index 9aabf43..cf52378 100644 --- a/objdiff-core/src/arch/arm.rs +++ b/objdiff-core/src/arch/arm.rs @@ -227,6 +227,7 @@ impl ObjArch for ObjArchArm { fn implcit_addend( &self, + _file: &File<'_>, section: &ObjSection, address: u64, reloc: &Relocation, diff --git a/objdiff-core/src/arch/mips.rs b/objdiff-core/src/arch/mips.rs index 6c54f77..53ddb60 100644 --- a/objdiff-core/src/arch/mips.rs +++ b/objdiff-core/src/arch/mips.rs @@ -1,7 +1,10 @@ use std::{borrow::Cow, collections::BTreeMap, sync::Mutex}; use anyhow::{anyhow, bail, Result}; -use object::{elf, Endian, Endianness, File, FileFlags, Object, Relocation, RelocationFlags}; +use object::{ + elf, Endian, Endianness, File, FileFlags, Object, ObjectSection, ObjectSymbol, Relocation, + RelocationFlags, RelocationTarget, +}; use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType}; use crate::{ @@ -22,6 +25,7 @@ pub struct ObjArchMips { pub endianness: Endianness, pub abi: Abi, pub instr_category: InstrCategory, + pub ri_gp_value: i32, } const EF_MIPS_ABI: u32 = 0x0000F000; @@ -56,7 +60,19 @@ impl ObjArchMips { } _ => bail!("Unsupported MIPS file flags"), } - Ok(Self { endianness: object.endianness(), abi, instr_category }) + + // Parse the ri_gp_value stored in .reginfo to be able to correctly + // calculate R_MIPS_GPREL16 relocations later. The value is stored + // 0x14 bytes into .reginfo (on 32 bit platforms) + let ri_gp_value = object + .section_by_name(".reginfo") + .and_then(|section| section.data().ok()) + .and_then(|data| data.get(0x14..0x18)) + .and_then(|s| s.try_into().ok()) + .map(|bytes| object.endianness().read_i32_bytes(bytes)) + .unwrap_or(0); + + Ok(Self { endianness: object.endianness(), abi, instr_category, ri_gp_value }) } } @@ -179,6 +195,7 @@ impl ObjArch for ObjArchMips { fn implcit_addend( &self, + file: &File<'_>, section: &ObjSection, address: u64, reloc: &Relocation, @@ -191,9 +208,22 @@ impl ObjArch for ObjArchMips { ((addend & 0x0000FFFF) << 16) as i32 as i64 } RelocationFlags::Elf { - r_type: - elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16 | elf::R_MIPS_GPREL16, + r_type: elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16, } => (addend & 0x0000FFFF) as i16 as i64, + RelocationFlags::Elf { r_type: elf::R_MIPS_GPREL16 } => { + let RelocationTarget::Symbol(idx) = reloc.target() else { + bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol"); + }; + let sym = file.symbol_by_index(idx)?; + + // if the symbol we are relocating against is in a local section we need to add + // the ri_gp_value from .reginfo to the addend. + if sym.section().index().is_some() { + ((addend & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64 + } else { + (addend & 0x0000FFFF) as i16 as i64 + } + } RelocationFlags::Elf { r_type: elf::R_MIPS_26 } => ((addend & 0x03FFFFFF) << 2) as i64, flags => bail!("Unsupported MIPS implicit relocation {flags:?}"), }) diff --git a/objdiff-core/src/arch/mod.rs b/objdiff-core/src/arch/mod.rs index d3344ed..8f838e5 100644 --- a/objdiff-core/src/arch/mod.rs +++ b/objdiff-core/src/arch/mod.rs @@ -1,7 +1,7 @@ use std::{borrow::Cow, collections::BTreeMap}; use anyhow::{bail, Result}; -use object::{Architecture, Object, ObjectSymbol, Relocation, RelocationFlags, Symbol}; +use object::{Architecture, File, Object, ObjectSymbol, Relocation, RelocationFlags, Symbol}; use crate::{ diff::DiffObjConfig, @@ -28,8 +28,13 @@ pub trait ObjArch: Send + Sync { config: &DiffObjConfig, ) -> Result; - fn implcit_addend(&self, section: &ObjSection, address: u64, reloc: &Relocation) - -> Result; + fn implcit_addend( + &self, + file: &File<'_>, + section: &ObjSection, + address: u64, + reloc: &Relocation, + ) -> Result; fn demangle(&self, _name: &str) -> Option { None } diff --git a/objdiff-core/src/arch/ppc.rs b/objdiff-core/src/arch/ppc.rs index cba31d3..fa252b8 100644 --- a/objdiff-core/src/arch/ppc.rs +++ b/objdiff-core/src/arch/ppc.rs @@ -150,6 +150,7 @@ impl ObjArch for ObjArchPpc { fn implcit_addend( &self, + _file: &File<'_>, _section: &ObjSection, address: u64, reloc: &Relocation, diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index f50c544..a35c987 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -128,6 +128,7 @@ impl ObjArch for ObjArchX86 { fn implcit_addend( &self, + _file: &File<'_>, section: &ObjSection, address: u64, reloc: &Relocation, diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index ab14314..750e1d9 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -364,7 +364,7 @@ fn relocations_by_section( _ => None, }; let addend = if reloc.has_implicit_addend() { - arch.implcit_addend(section, address, &reloc)? + arch.implcit_addend(obj_file, section, address, &reloc)? } else { reloc.addend() };