mirror of
https://github.com/encounter/objdiff.git
synced 2025-07-26 23:15:48 +00:00
Support PPC64 ELFs (PS3); refactor relocation processing
This commit is contained in:
parent
8fac63c42c
commit
00ad0d8094
@ -19,7 +19,7 @@ Supports:
|
|||||||
- ARM (GBA, DS, 3DS)
|
- ARM (GBA, DS, 3DS)
|
||||||
- ARM64 (Switch)
|
- ARM64 (Switch)
|
||||||
- MIPS (N64, PS1, PS2, PSP)
|
- MIPS (N64, PS1, PS2, PSP)
|
||||||
- PowerPC (GameCube, Wii, Xbox 360)
|
- PowerPC (GameCube, Wii, PS3, Xbox 360)
|
||||||
- SuperH (Saturn, Dreamcast)
|
- SuperH (Saturn, Dreamcast)
|
||||||
- x86, x86_64 (PC)
|
- x86, x86_64 (PC)
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ itertools = { version = "0.14", default-features = false, features = ["use_alloc
|
|||||||
log = { version = "0.4", default-features = false, optional = true }
|
log = { version = "0.4", default-features = false, optional = true }
|
||||||
memmap2 = { version = "0.9", optional = true }
|
memmap2 = { version = "0.9", optional = true }
|
||||||
num-traits = { version = "0.2", default-features = false, optional = true }
|
num-traits = { version = "0.2", default-features = false, optional = true }
|
||||||
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "pe"] }
|
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "coff"] }
|
||||||
pbjson = { version = "0.7", default-features = false, optional = true }
|
pbjson = { version = "0.7", default-features = false, optional = true }
|
||||||
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
|
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
|
||||||
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
||||||
|
@ -11,7 +11,7 @@ use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, el
|
|||||||
use unarm::{args, arm, thumb};
|
use unarm::{args, arm, thumb};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::Arch,
|
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||||
diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig, display::InstructionPart},
|
diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig, display::InstructionPart},
|
||||||
obj::{
|
obj::{
|
||||||
InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation,
|
InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation,
|
||||||
@ -356,21 +356,22 @@ impl Arch for ArchArm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
fn relocation_override(
|
||||||
&self,
|
&self,
|
||||||
_file: &object::File<'_>,
|
_file: &object::File<'_>,
|
||||||
section: &object::Section,
|
section: &object::Section,
|
||||||
address: u64,
|
address: u64,
|
||||||
_relocation: &object::Relocation,
|
relocation: &object::Relocation,
|
||||||
flags: RelocationFlags,
|
) -> Result<Option<RelocationOverride>> {
|
||||||
) -> Result<Option<i64>> {
|
match relocation.flags() {
|
||||||
|
// Handle ELF implicit relocations
|
||||||
|
object::RelocationFlags::Elf { r_type } => {
|
||||||
|
if relocation.has_implicit_addend() {
|
||||||
let section_data = section.data()?;
|
let section_data = section.data()?;
|
||||||
let address = address as usize;
|
let address = address as usize;
|
||||||
Ok(Some(match flags {
|
let addend = match r_type {
|
||||||
// ARM calls
|
// ARM calls
|
||||||
RelocationFlags::Elf(elf::R_ARM_PC24)
|
elf::R_ARM_PC24 | elf::R_ARM_XPC25 | elf::R_ARM_CALL => {
|
||||||
| RelocationFlags::Elf(elf::R_ARM_XPC25)
|
|
||||||
| RelocationFlags::Elf(elf::R_ARM_CALL) => {
|
|
||||||
let data = section_data[address..address + 4].try_into()?;
|
let data = section_data[address..address + 4].try_into()?;
|
||||||
let addend = self.endianness.read_i32_bytes(data);
|
let addend = self.endianness.read_i32_bytes(data);
|
||||||
let imm24 = addend & 0xffffff;
|
let imm24 = addend & 0xffffff;
|
||||||
@ -378,8 +379,7 @@ impl Arch for ArchArm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Thumb calls
|
// Thumb calls
|
||||||
RelocationFlags::Elf(elf::R_ARM_THM_PC22)
|
elf::R_ARM_THM_PC22 | elf::R_ARM_THM_XPC22 => {
|
||||||
| RelocationFlags::Elf(elf::R_ARM_THM_XPC22) => {
|
|
||||||
let data = section_data[address..address + 2].try_into()?;
|
let data = section_data[address..address + 2].try_into()?;
|
||||||
let high = self.endianness.read_i16_bytes(data) as i32;
|
let high = self.endianness.read_i16_bytes(data) as i32;
|
||||||
let data = section_data[address + 2..address + 4].try_into()?;
|
let data = section_data[address + 2..address + 4].try_into()?;
|
||||||
@ -390,13 +390,23 @@ impl Arch for ArchArm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
RelocationFlags::Elf(elf::R_ARM_ABS32) => {
|
elf::R_ARM_ABS32 => {
|
||||||
let data = section_data[address..address + 4].try_into()?;
|
let data = section_data[address..address + 4].try_into()?;
|
||||||
self.endianness.read_i32_bytes(data)
|
self.endianness.read_i32_bytes(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
flags => bail!("Unsupported ARM implicit relocation {flags:?}"),
|
flags => bail!("Unsupported ARM implicit relocation {flags:?}"),
|
||||||
} as i64))
|
};
|
||||||
|
Ok(Some(RelocationOverride {
|
||||||
|
target: RelocationOverrideTarget::Keep,
|
||||||
|
addend: addend as i64,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
|
@ -5,7 +5,7 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::Result;
|
||||||
use object::elf;
|
use object::elf;
|
||||||
use yaxpeax_arch::{Arch as YaxpeaxArch, Decoder, Reader, U8Reader};
|
use yaxpeax_arch::{Arch as YaxpeaxArch, Decoder, Reader, U8Reader};
|
||||||
use yaxpeax_arm::armv8::a64::{
|
use yaxpeax_arm::armv8::a64::{
|
||||||
@ -108,17 +108,6 @@ impl Arch for ArchArm64 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
|
||||||
&self,
|
|
||||||
_file: &object::File<'_>,
|
|
||||||
_section: &object::Section,
|
|
||||||
address: u64,
|
|
||||||
_relocation: &object::Relocation,
|
|
||||||
flags: RelocationFlags,
|
|
||||||
) -> Result<Option<i64>> {
|
|
||||||
bail!("Unsupported ARM64 implicit relocation {:#x}:{:?}", address, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
cpp_demangle::Symbol::new(name)
|
cpp_demangle::Symbol::new(name)
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -14,7 +14,7 @@ use rabbitizer::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::Arch,
|
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||||
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory, display::InstructionPart},
|
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory, display::InstructionPart},
|
||||||
obj::{
|
obj::{
|
||||||
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
|
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
|
||||||
@ -225,37 +225,44 @@ impl Arch for ArchMips {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
fn relocation_override(
|
||||||
&self,
|
&self,
|
||||||
file: &object::File<'_>,
|
file: &object::File<'_>,
|
||||||
section: &object::Section,
|
section: &object::Section,
|
||||||
address: u64,
|
address: u64,
|
||||||
reloc: &object::Relocation,
|
relocation: &object::Relocation,
|
||||||
flags: RelocationFlags,
|
) -> Result<Option<RelocationOverride>> {
|
||||||
) -> Result<Option<i64>> {
|
match relocation.flags() {
|
||||||
|
// Handle ELF implicit relocations
|
||||||
|
object::RelocationFlags::Elf { r_type } => {
|
||||||
|
if relocation.has_implicit_addend() {
|
||||||
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
||||||
if let RelocationFlags::Elf(elf::R_MIPS_HI16 | elf::R_MIPS_LO16) = flags {
|
if let elf::R_MIPS_HI16 | elf::R_MIPS_LO16 = r_type {
|
||||||
if let Some(addend) = self
|
if let Some(addend) = self
|
||||||
.paired_relocations
|
.paired_relocations
|
||||||
.get(section.index().0)
|
.get(section.index().0)
|
||||||
.and_then(|m| m.get(&address).copied())
|
.and_then(|m| m.get(&address).copied())
|
||||||
{
|
{
|
||||||
return Ok(Some(addend));
|
return Ok(Some(RelocationOverride {
|
||||||
|
target: RelocationOverrideTarget::Keep,
|
||||||
|
addend,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = section.data()?;
|
let data = section.data()?;
|
||||||
let code = data[address as usize..address as usize + 4].try_into()?;
|
let code = self
|
||||||
let addend = self.endianness.read_u32_bytes(code);
|
.endianness
|
||||||
Ok(Some(match flags {
|
.read_u32_bytes(data[address as usize..address as usize + 4].try_into()?);
|
||||||
RelocationFlags::Elf(elf::R_MIPS_32) => addend as i64,
|
let addend = match r_type {
|
||||||
RelocationFlags::Elf(elf::R_MIPS_26) => ((addend & 0x03FFFFFF) << 2) as i64,
|
elf::R_MIPS_32 => code as i64,
|
||||||
RelocationFlags::Elf(elf::R_MIPS_HI16) => ((addend & 0x0000FFFF) << 16) as i32 as i64,
|
elf::R_MIPS_26 => ((code & 0x03FFFFFF) << 2) as i64,
|
||||||
RelocationFlags::Elf(elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16) => {
|
elf::R_MIPS_HI16 => ((code & 0x0000FFFF) << 16) as i32 as i64,
|
||||||
(addend & 0x0000FFFF) as i16 as i64
|
elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16 => {
|
||||||
|
(code & 0x0000FFFF) as i16 as i64
|
||||||
}
|
}
|
||||||
RelocationFlags::Elf(elf::R_MIPS_GPREL16 | elf::R_MIPS_LITERAL) => {
|
elf::R_MIPS_GPREL16 | elf::R_MIPS_LITERAL => {
|
||||||
let object::RelocationTarget::Symbol(idx) = reloc.target() else {
|
let object::RelocationTarget::Symbol(idx) = relocation.target() else {
|
||||||
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
||||||
};
|
};
|
||||||
let sym = file.symbol_by_index(idx)?;
|
let sym = file.symbol_by_index(idx)?;
|
||||||
@ -263,15 +270,22 @@ impl Arch for ArchMips {
|
|||||||
// if the symbol we are relocating against is in a local section we need to add
|
// 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.
|
// the ri_gp_value from .reginfo to the addend.
|
||||||
if sym.section().index().is_some() {
|
if sym.section().index().is_some() {
|
||||||
((addend & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
((code & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
||||||
} else {
|
} else {
|
||||||
(addend & 0x0000FFFF) as i16 as i64
|
(code & 0x0000FFFF) as i16 as i64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RelocationFlags::Elf(elf::R_MIPS_PC16) => 0, // PC-relative relocation
|
elf::R_MIPS_PC16 => 0, // PC-relative relocation
|
||||||
RelocationFlags::Elf(R_MIPS15_S3) => ((addend & 0x001FFFC0) >> 3) as i64,
|
R_MIPS15_S3 => ((code & 0x001FFFC0) >> 3) as i64,
|
||||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||||
}))
|
};
|
||||||
|
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
|
@ -357,14 +357,15 @@ pub trait Arch: Send + Sync + Debug {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
fn relocation_override(
|
||||||
&self,
|
&self,
|
||||||
file: &object::File<'_>,
|
_file: &object::File<'_>,
|
||||||
section: &object::Section,
|
_section: &object::Section,
|
||||||
address: u64,
|
_address: u64,
|
||||||
relocation: &object::Relocation,
|
_relocation: &object::Relocation,
|
||||||
flags: RelocationFlags,
|
) -> Result<Option<RelocationOverride>> {
|
||||||
) -> Result<Option<i64>>;
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
fn demangle(&self, _name: &str) -> Option<String> { None }
|
fn demangle(&self, _name: &str) -> Option<String> { None }
|
||||||
|
|
||||||
@ -411,7 +412,9 @@ pub fn new_arch(object: &object::File) -> Result<Box<dyn Arch>> {
|
|||||||
use object::Object as _;
|
use object::Object as _;
|
||||||
Ok(match object.architecture() {
|
Ok(match object.architecture() {
|
||||||
#[cfg(feature = "ppc")]
|
#[cfg(feature = "ppc")]
|
||||||
object::Architecture::PowerPc => Box::new(ppc::ArchPpc::new(object)?),
|
object::Architecture::PowerPc | object::Architecture::PowerPc64 => {
|
||||||
|
Box::new(ppc::ArchPpc::new(object)?)
|
||||||
|
}
|
||||||
#[cfg(feature = "mips")]
|
#[cfg(feature = "mips")]
|
||||||
object::Architecture::Mips => Box::new(mips::ArchMips::new(object)?),
|
object::Architecture::Mips => Box::new(mips::ArchMips::new(object)?),
|
||||||
#[cfg(feature = "x86")]
|
#[cfg(feature = "x86")]
|
||||||
@ -456,16 +459,17 @@ impl Arch for ArchDummy {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
|
||||||
&self,
|
|
||||||
_file: &object::File<'_>,
|
|
||||||
_section: &object::Section,
|
|
||||||
_address: u64,
|
|
||||||
_relocation: &object::Relocation,
|
|
||||||
_flags: RelocationFlags,
|
|
||||||
) -> Result<Option<i64>> {
|
|
||||||
Ok(Some(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn data_reloc_size(&self, _flags: RelocationFlags) -> usize { 0 }
|
fn data_reloc_size(&self, _flags: RelocationFlags) -> usize { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum RelocationOverrideTarget {
|
||||||
|
Keep,
|
||||||
|
Skip,
|
||||||
|
Symbol(object::SymbolIndex),
|
||||||
|
Section(object::SectionIndex),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RelocationOverride {
|
||||||
|
pub target: RelocationOverrideTarget,
|
||||||
|
pub addend: i64,
|
||||||
|
}
|
||||||
|
@ -12,7 +12,7 @@ use flagset::Flags;
|
|||||||
use object::{Object as _, ObjectSection as _, ObjectSymbol as _, elf, pe};
|
use object::{Object as _, ObjectSection as _, ObjectSymbol as _, elf, pe};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{Arch, DataType},
|
arch::{Arch, DataType, RelocationOverride, RelocationOverrideTarget},
|
||||||
diff::{
|
diff::{
|
||||||
DiffObjConfig,
|
DiffObjConfig,
|
||||||
data::resolve_relocation,
|
data::resolve_relocation,
|
||||||
@ -100,6 +100,7 @@ impl ArchPpc {
|
|||||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO) => {
|
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO) => {
|
||||||
ins.args.iter().rposition(is_rel_abs_arg)
|
ins.args.iter().rposition(is_rel_abs_arg)
|
||||||
}
|
}
|
||||||
|
RelocationFlags::Elf(elf::R_PPC64_TOC16) => ins.args.iter().rposition(is_offset_arg),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,18 +209,18 @@ impl Arch for ArchPpc {
|
|||||||
Some(flow_analysis::ppc_data_flow_analysis(obj, symbol, code, relocations, self.extensions))
|
Some(flow_analysis::ppc_data_flow_analysis(obj, symbol, code, relocations, self.extensions))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
fn relocation_override(
|
||||||
&self,
|
&self,
|
||||||
_file: &object::File<'_>,
|
file: &object::File<'_>,
|
||||||
section: &object::Section,
|
section: &object::Section,
|
||||||
address: u64,
|
address: u64,
|
||||||
_relocation: &object::Relocation,
|
relocation: &object::Relocation,
|
||||||
flags: RelocationFlags,
|
) -> Result<Option<RelocationOverride>> {
|
||||||
) -> Result<Option<i64>> {
|
match relocation.flags() {
|
||||||
match flags {
|
|
||||||
// IMAGE_REL_PPC_PAIR contains the REF{HI,LO} displacement instead of a symbol index
|
// IMAGE_REL_PPC_PAIR contains the REF{HI,LO} displacement instead of a symbol index
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI)
|
object::RelocationFlags::Coff {
|
||||||
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFLO) => section
|
typ: pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO,
|
||||||
|
} => section
|
||||||
.relocations()
|
.relocations()
|
||||||
.skip_while(|&(a, _)| a < address)
|
.skip_while(|&(a, _)| a < address)
|
||||||
.take_while(|&(a, _)| a == address)
|
.take_while(|&(a, _)| a == address)
|
||||||
@ -228,23 +229,81 @@ impl Arch for ArchPpc {
|
|||||||
typ: pe::IMAGE_REL_PPC_PAIR
|
typ: pe::IMAGE_REL_PPC_PAIR
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map_or(Ok(Some(0)), |(_, reloc)| match reloc.target() {
|
.map_or(Ok(None), |(_, reloc)| match reloc.target() {
|
||||||
object::RelocationTarget::Symbol(index) => {
|
object::RelocationTarget::Symbol(index) => Ok(Some(RelocationOverride {
|
||||||
Ok(Some(index.0 as u16 as i16 as i64))
|
target: RelocationOverrideTarget::Keep,
|
||||||
}
|
addend: index.0 as u16 as i16 as i64,
|
||||||
|
})),
|
||||||
target => Err(anyhow!("Unsupported IMAGE_REL_PPC_PAIR target {target:?}")),
|
target => Err(anyhow!("Unsupported IMAGE_REL_PPC_PAIR target {target:?}")),
|
||||||
}),
|
}),
|
||||||
// Skip PAIR relocations as they are handled by the previous case
|
// Skip PAIR relocations as they are handled by the previous case
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_PPC_PAIR) => Ok(None),
|
object::RelocationFlags::Coff { typ: pe::IMAGE_REL_PPC_PAIR } => {
|
||||||
RelocationFlags::Coff(_) => Ok(Some(0)),
|
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Skip, addend: 0 }))
|
||||||
flags => Err(anyhow!("Unsupported PPC implicit relocation {flags:?}")),
|
}
|
||||||
|
// Any other COFF relocation has an addend of 0
|
||||||
|
object::RelocationFlags::Coff { .. } => {
|
||||||
|
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend: 0 }))
|
||||||
|
}
|
||||||
|
// Handle ELF implicit relocations
|
||||||
|
flags @ object::RelocationFlags::Elf { r_type } => {
|
||||||
|
ensure!(
|
||||||
|
!relocation.has_implicit_addend(),
|
||||||
|
"Unsupported implicit relocation {:?}",
|
||||||
|
flags
|
||||||
|
);
|
||||||
|
match r_type {
|
||||||
|
elf::R_PPC64_TOC16 => {
|
||||||
|
let offset = u64::try_from(relocation.addend())
|
||||||
|
.map_err(|_| anyhow!("Negative addend for R_PPC64_TOC16 relocation"))?;
|
||||||
|
let Some(toc_section) = file.section_by_name(".toc") else {
|
||||||
|
bail!("Missing .toc section for R_PPC64_TOC16 relocation");
|
||||||
|
};
|
||||||
|
// If TOC target is a relocation, replace it with the target symbol
|
||||||
|
let Some((_, toc_relocation)) =
|
||||||
|
toc_section.relocations().find(|&(a, _)| a == offset)
|
||||||
|
else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
if toc_relocation.has_implicit_addend() {
|
||||||
|
log::warn!(
|
||||||
|
"Unsupported implicit addend for R_PPC64_TOC16 relocation: {toc_relocation:?}"
|
||||||
|
);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let addend = toc_relocation.addend();
|
||||||
|
match toc_relocation.target() {
|
||||||
|
object::RelocationTarget::Symbol(symbol_index) => {
|
||||||
|
Ok(Some(RelocationOverride {
|
||||||
|
target: RelocationOverrideTarget::Symbol(symbol_index),
|
||||||
|
addend,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
object::RelocationTarget::Section(section_index) => {
|
||||||
|
Ok(Some(RelocationOverride {
|
||||||
|
target: RelocationOverrideTarget::Section(section_index),
|
||||||
|
addend,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
target => {
|
||||||
|
log::warn!(
|
||||||
|
"Unsupported R_PPC64_TOC16 relocation target {target:?}"
|
||||||
|
);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, mut name: &str) -> Option<String> {
|
||||||
if name.starts_with('?') {
|
if name.starts_with('?') {
|
||||||
msvc_demangler::demangle(name, msvc_demangler::DemangleFlags::llvm()).ok()
|
msvc_demangler::demangle(name, msvc_demangler::DemangleFlags::llvm()).ok()
|
||||||
} else {
|
} else {
|
||||||
|
name = name.trim_start_matches('.');
|
||||||
cpp_demangle::Symbol::new(name)
|
cpp_demangle::Symbol::new(name)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
|
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
|
||||||
@ -264,6 +323,7 @@ impl Arch for ArchPpc {
|
|||||||
elf::R_PPC_UADDR32 => Some("R_PPC_UADDR32"),
|
elf::R_PPC_UADDR32 => Some("R_PPC_UADDR32"),
|
||||||
elf::R_PPC_REL24 => Some("R_PPC_REL24"),
|
elf::R_PPC_REL24 => Some("R_PPC_REL24"),
|
||||||
elf::R_PPC_REL14 => Some("R_PPC_REL14"),
|
elf::R_PPC_REL14 => Some("R_PPC_REL14"),
|
||||||
|
elf::R_PPC64_TOC16 => Some("R_PPC64_TOC16"),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
RelocationFlags::Coff(r_type) => match r_type {
|
RelocationFlags::Coff(r_type) => match r_type {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use alloc::{collections::BTreeMap, format, string::String, vec, vec::Vec};
|
use alloc::{collections::BTreeMap, format, string::String, vec, vec::Vec};
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::Result;
|
||||||
use object::elf;
|
use object::elf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -132,17 +132,6 @@ impl Arch for ArchSuperH {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
|
||||||
&self,
|
|
||||||
_file: &object::File<'_>,
|
|
||||||
_section: &object::Section,
|
|
||||||
address: u64,
|
|
||||||
_relocation: &object::Relocation,
|
|
||||||
flags: RelocationFlags,
|
|
||||||
) -> Result<Option<i64>> {
|
|
||||||
bail!("Unsupported SuperH implicit relocation {:#x}:{:?}", address, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
cpp_demangle::Symbol::new(name)
|
cpp_demangle::Symbol::new(name)
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -9,7 +9,7 @@ use iced_x86::{
|
|||||||
use object::{Endian as _, Object as _, ObjectSection as _, elf, pe};
|
use object::{Endian as _, Object as _, ObjectSection as _, elf, pe};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::Arch,
|
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||||
diff::{DiffObjConfig, X86Formatter, display::InstructionPart},
|
diff::{DiffObjConfig, X86Formatter, display::InstructionPart},
|
||||||
obj::{InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef},
|
obj::{InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef},
|
||||||
};
|
};
|
||||||
@ -225,40 +225,47 @@ impl Arch for ArchX86 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implcit_addend(
|
fn relocation_override(
|
||||||
&self,
|
&self,
|
||||||
_file: &object::File<'_>,
|
_file: &object::File<'_>,
|
||||||
section: &object::Section,
|
section: &object::Section,
|
||||||
address: u64,
|
address: u64,
|
||||||
_relocation: &object::Relocation,
|
relocation: &object::Relocation,
|
||||||
flags: RelocationFlags,
|
) -> Result<Option<RelocationOverride>> {
|
||||||
) -> Result<Option<i64>> {
|
if !relocation.has_implicit_addend() {
|
||||||
match self.arch {
|
return Ok(None);
|
||||||
Architecture::X86 => match flags {
|
}
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32)
|
let addend = match self.arch {
|
||||||
| RelocationFlags::Elf(elf::R_386_32 | elf::R_386_PC32) => {
|
Architecture::X86 => match relocation.flags() {
|
||||||
|
object::RelocationFlags::Coff {
|
||||||
|
typ: pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32,
|
||||||
|
}
|
||||||
|
| object::RelocationFlags::Elf { r_type: elf::R_386_32 | elf::R_386_PC32 } => {
|
||||||
let data =
|
let data =
|
||||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||||
Ok(Some(self.endianness.read_i32_bytes(data) as i64))
|
self.endianness.read_i32_bytes(data) as i64
|
||||||
}
|
}
|
||||||
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
||||||
},
|
},
|
||||||
Architecture::X86_64 => match flags {
|
Architecture::X86_64 => match relocation.flags() {
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32)
|
object::RelocationFlags::Coff {
|
||||||
| RelocationFlags::Elf(elf::R_X86_64_32 | elf::R_X86_64_PC32) => {
|
typ: pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32,
|
||||||
|
}
|
||||||
|
| object::RelocationFlags::Elf { r_type: elf::R_X86_64_32 | elf::R_X86_64_PC32 } => {
|
||||||
let data =
|
let data =
|
||||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||||
Ok(Some(self.endianness.read_i32_bytes(data) as i64))
|
self.endianness.read_i32_bytes(data) as i64
|
||||||
}
|
}
|
||||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64)
|
object::RelocationFlags::Coff { typ: pe::IMAGE_REL_AMD64_ADDR64 }
|
||||||
| RelocationFlags::Elf(elf::R_X86_64_64) => {
|
| object::RelocationFlags::Elf { r_type: elf::R_X86_64_64 } => {
|
||||||
let data =
|
let data =
|
||||||
section.data()?[address as usize..address as usize + 8].try_into()?;
|
section.data()?[address as usize..address as usize + 8].try_into()?;
|
||||||
Ok(Some(self.endianness.read_i64_bytes(data)))
|
self.endianness.read_i64_bytes(data)
|
||||||
}
|
}
|
||||||
flags => bail!("Unsupported x86-64 implicit relocation {flags:?}"),
|
flags => bail!("Unsupported x86-64 implicit relocation {flags:?}"),
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
|
@ -11,7 +11,7 @@ use anyhow::{Context, Result, anyhow, bail, ensure};
|
|||||||
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
|
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{Arch, new_arch},
|
arch::{Arch, RelocationOverride, RelocationOverrideTarget, new_arch},
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
obj::{
|
obj::{
|
||||||
FlowAnalysisResult, Object, Relocation, RelocationFlags, Section, SectionData, SectionFlag,
|
FlowAnalysisResult, Object, Relocation, RelocationFlags, Section, SectionData, SectionFlag,
|
||||||
@ -24,8 +24,13 @@ use crate::{
|
|||||||
fn map_section_kind(section: &object::Section) -> SectionKind {
|
fn map_section_kind(section: &object::Section) -> SectionKind {
|
||||||
match section.kind() {
|
match section.kind() {
|
||||||
object::SectionKind::Text => SectionKind::Code,
|
object::SectionKind::Text => SectionKind::Code,
|
||||||
object::SectionKind::Data | object::SectionKind::ReadOnlyData => SectionKind::Data,
|
object::SectionKind::Data
|
||||||
object::SectionKind::UninitializedData => SectionKind::Bss,
|
| object::SectionKind::ReadOnlyData
|
||||||
|
| object::SectionKind::ReadOnlyString
|
||||||
|
| object::SectionKind::Tls => SectionKind::Data,
|
||||||
|
object::SectionKind::UninitializedData
|
||||||
|
| object::SectionKind::UninitializedTls
|
||||||
|
| object::SectionKind::Common => SectionKind::Bss,
|
||||||
_ => SectionKind::Unknown,
|
_ => SectionKind::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,63 +334,125 @@ fn map_section_relocations(
|
|||||||
) -> Result<Vec<Relocation>> {
|
) -> Result<Vec<Relocation>> {
|
||||||
let mut relocations = Vec::<Relocation>::with_capacity(obj_section.relocations().count());
|
let mut relocations = Vec::<Relocation>::with_capacity(obj_section.relocations().count());
|
||||||
for (address, reloc) in obj_section.relocations() {
|
for (address, reloc) in obj_section.relocations() {
|
||||||
let flags = match reloc.flags() {
|
let mut target_reloc = RelocationOverride {
|
||||||
object::RelocationFlags::Elf { r_type } => RelocationFlags::Elf(r_type),
|
target: match reloc.target() {
|
||||||
object::RelocationFlags::Coff { typ } => RelocationFlags::Coff(typ),
|
object::RelocationTarget::Symbol(symbol) => {
|
||||||
flags => {
|
RelocationOverrideTarget::Symbol(symbol)
|
||||||
bail!("Unhandled relocation flags: {:?}", flags);
|
|
||||||
}
|
}
|
||||||
};
|
object::RelocationTarget::Section(section) => {
|
||||||
// TODO validate reloc here?
|
RelocationOverrideTarget::Section(section)
|
||||||
let mut addend = if reloc.has_implicit_addend() {
|
|
||||||
match arch.implcit_addend(obj_file, obj_section, address, &reloc, flags)? {
|
|
||||||
Some(addend) => addend,
|
|
||||||
None => continue, // Skip relocation (e.g. COFF PAIR relocations)
|
|
||||||
}
|
}
|
||||||
} else {
|
_ => RelocationOverrideTarget::Skip,
|
||||||
reloc.addend()
|
},
|
||||||
|
addend: reloc.addend(),
|
||||||
};
|
};
|
||||||
let target_symbol = match reloc.target() {
|
|
||||||
object::RelocationTarget::Symbol(idx) => {
|
// Allow the architecture to override the relocation target and addend
|
||||||
if idx.0 == u32::MAX as usize {
|
match arch.relocation_override(obj_file, obj_section, address, &reloc)? {
|
||||||
// ???
|
Some(reloc_override) => {
|
||||||
|
match reloc_override.target {
|
||||||
|
RelocationOverrideTarget::Keep => {}
|
||||||
|
target => {
|
||||||
|
target_reloc.target = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target_reloc.addend = reloc_override.addend;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
ensure!(
|
||||||
|
!reloc.has_implicit_addend(),
|
||||||
|
"Unsupported implicit relocation {:?}",
|
||||||
|
reloc.flags()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the relocation target symbol
|
||||||
|
let (symbol_index, addend) = match target_reloc.target {
|
||||||
|
RelocationOverrideTarget::Keep => unreachable!(),
|
||||||
|
RelocationOverrideTarget::Skip => continue,
|
||||||
|
RelocationOverrideTarget::Symbol(symbol_index) => {
|
||||||
|
// Sometimes used to indicate "absolute"
|
||||||
|
if symbol_index.0 == u32::MAX as usize {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the target is a section symbol, try to resolve a better symbol as the target
|
// If the target is a section symbol, try to resolve a better symbol as the target
|
||||||
let idx = if let Some(section_symbol) = obj_file
|
if let Some(section_symbol) = obj_file
|
||||||
.symbol_by_index(idx)
|
.symbol_by_index(symbol_index)
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|s| s.kind() == object::SymbolKind::Section)
|
.filter(|s| s.kind() == object::SymbolKind::Section)
|
||||||
{
|
{
|
||||||
let section_index =
|
let section_index =
|
||||||
section_symbol.section_index().context("Section symbol without section")?;
|
section_symbol.section_index().context("Section symbol without section")?;
|
||||||
let target_address = section_symbol.address().wrapping_add_signed(addend);
|
let target_address =
|
||||||
|
section_symbol.address().wrapping_add_signed(target_reloc.addend);
|
||||||
if let Some((new_idx, addr)) = ordered_symbols
|
if let Some((new_idx, addr)) = ordered_symbols
|
||||||
.get(section_index.0)
|
.get(section_index.0)
|
||||||
.and_then(|symbols| best_symbol(symbols, target_address))
|
.and_then(|symbols| best_symbol(symbols, target_address))
|
||||||
{
|
{
|
||||||
addend = target_address.wrapping_sub(addr) as i64;
|
(new_idx, target_address.wrapping_sub(addr) as i64)
|
||||||
new_idx
|
|
||||||
} else {
|
} else {
|
||||||
idx
|
(symbol_index, target_reloc.addend)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
idx
|
(symbol_index, target_reloc.addend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RelocationOverrideTarget::Section(section_index) => {
|
||||||
|
let section = match obj_file.section_by_index(section_index) {
|
||||||
|
Ok(section) => section,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Invalid relocation section: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
match symbol_indices.get(idx.0).copied() {
|
let Ok(target_address) = u64::try_from(target_reloc.addend) else {
|
||||||
|
log::warn!(
|
||||||
|
"Negative section relocation addend: {}{}",
|
||||||
|
section.name()?,
|
||||||
|
target_reloc.addend
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(symbols) = ordered_symbols.get(section_index.0) else {
|
||||||
|
log::warn!(
|
||||||
|
"Couldn't resolve relocation target symbol for section {} (no symbols)",
|
||||||
|
section.name()?
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
// Attempt to resolve a target symbol for the relocation
|
||||||
|
if let Some((new_idx, addr)) = best_symbol(symbols, target_address) {
|
||||||
|
(new_idx, target_address.wrapping_sub(addr) as i64)
|
||||||
|
} else if let Some(section_symbol) =
|
||||||
|
symbols.iter().find(|s| s.kind() == object::SymbolKind::Section)
|
||||||
|
{
|
||||||
|
(
|
||||||
|
section_symbol.index(),
|
||||||
|
target_address.wrapping_sub(section_symbol.address()) as i64,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log::warn!(
|
||||||
|
"Couldn't resolve relocation target symbol for section {}",
|
||||||
|
section.name()?
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let flags = match reloc.flags() {
|
||||||
|
object::RelocationFlags::Elf { r_type } => RelocationFlags::Elf(r_type),
|
||||||
|
object::RelocationFlags::Coff { typ } => RelocationFlags::Coff(typ),
|
||||||
|
flags => bail!("Unhandled relocation flags: {:?}", flags),
|
||||||
|
};
|
||||||
|
let target_symbol = match symbol_indices.get(symbol_index.0).copied() {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
None => {
|
None => {
|
||||||
log::warn!("Invalid symbol index {}", idx.0);
|
log::warn!("Invalid symbol index {}", symbol_index.0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
object::RelocationTarget::Absolute => {
|
|
||||||
let section_name = obj_section.name()?;
|
|
||||||
log::warn!("Ignoring absolute relocation @ {section_name}:{address:#x}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => bail!("Unhandled relocation target: {:?}", reloc.target()),
|
|
||||||
};
|
};
|
||||||
relocations.push(Relocation { address, flags, target_symbol, addend });
|
relocations.push(Relocation { address, flags, target_symbol, addend });
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user