mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-17 00:47:12 +00:00
Move all architecture-specific code into modules
No more scattered relocation handling and feature checks. Everything will go through the ObjArch trait, which makes it easier to add new architectures going forward.
This commit is contained in:
207
objdiff-core/src/arch/mips.rs
Normal file
207
objdiff-core/src/arch/mips.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
use std::{borrow::Cow, collections::BTreeMap};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags};
|
||||
use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType};
|
||||
|
||||
use crate::{
|
||||
arch::ObjArch,
|
||||
diff::{DiffObjConfig, ProcessCodeResult},
|
||||
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
||||
};
|
||||
|
||||
fn configure_rabbitizer() {
|
||||
unsafe {
|
||||
config::RabbitizerConfig_Cfg.reg_names.fpr_abi_names = Abi::O32;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ObjArchMips {
|
||||
pub endianness: Endianness,
|
||||
}
|
||||
|
||||
impl ObjArchMips {
|
||||
pub fn new(object: &File) -> Result<Self> { Ok(Self { endianness: object.endianness() }) }
|
||||
}
|
||||
|
||||
impl ObjArch for ObjArchMips {
|
||||
fn process_code(
|
||||
&self,
|
||||
config: &DiffObjConfig,
|
||||
data: &[u8],
|
||||
start_address: u64,
|
||||
relocs: &[ObjReloc],
|
||||
line_info: &Option<BTreeMap<u64, u64>>,
|
||||
) -> Result<ProcessCodeResult> {
|
||||
configure_rabbitizer();
|
||||
|
||||
let end_address = start_address + data.len() as u64;
|
||||
let ins_count = data.len() / 4;
|
||||
let mut ops = Vec::<u16>::with_capacity(ins_count);
|
||||
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
|
||||
let mut cur_addr = start_address as u32;
|
||||
for chunk in data.chunks_exact(4) {
|
||||
let reloc = relocs.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
||||
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
||||
let instruction = Instruction::new(code, cur_addr, InstrCategory::CPU);
|
||||
|
||||
let op = instruction.unique_id as u16;
|
||||
ops.push(op);
|
||||
|
||||
let mnemonic = instruction.opcode_name().to_string();
|
||||
let is_branch = instruction.is_branch();
|
||||
let branch_offset = instruction.branch_offset();
|
||||
let branch_dest = if is_branch {
|
||||
cur_addr.checked_add_signed(branch_offset).map(|a| a as u64)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let operands = instruction.get_operands_slice();
|
||||
let mut args = Vec::with_capacity(operands.len() + 1);
|
||||
for (idx, op) in operands.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
if config.space_between_args {
|
||||
args.push(ObjInsArg::PlainText(", ".to_string()));
|
||||
} else {
|
||||
args.push(ObjInsArg::PlainText(",".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
match op {
|
||||
OperandType::cpu_immediate
|
||||
| OperandType::cpu_label
|
||||
| OperandType::cpu_branch_target_label => {
|
||||
if let Some(branch_dest) = branch_dest {
|
||||
args.push(ObjInsArg::BranchDest(branch_dest));
|
||||
} else if let Some(reloc) = reloc {
|
||||
if matches!(&reloc.target_section, Some(s) if s == ".text")
|
||||
&& reloc.target.address > start_address
|
||||
&& reloc.target.address < end_address
|
||||
{
|
||||
args.push(ObjInsArg::BranchDest(reloc.target.address));
|
||||
} else {
|
||||
push_reloc(&mut args, reloc)?;
|
||||
}
|
||||
} else {
|
||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||
op.disassemble(&instruction, None),
|
||||
)));
|
||||
}
|
||||
}
|
||||
OperandType::cpu_immediate_base => {
|
||||
if let Some(reloc) = reloc {
|
||||
push_reloc(&mut args, reloc)?;
|
||||
} else {
|
||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||
OperandType::cpu_immediate.disassemble(&instruction, None),
|
||||
)));
|
||||
}
|
||||
args.push(ObjInsArg::PlainText("(".to_string()));
|
||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||
OperandType::cpu_rs.disassemble(&instruction, None),
|
||||
)));
|
||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
||||
}
|
||||
_ => {
|
||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||
op.disassemble(&instruction, None),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
let line = line_info
|
||||
.as_ref()
|
||||
.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b));
|
||||
insts.push(ObjIns {
|
||||
address: cur_addr as u64,
|
||||
size: 4,
|
||||
op,
|
||||
mnemonic,
|
||||
args,
|
||||
reloc: reloc.cloned(),
|
||||
branch_dest,
|
||||
line,
|
||||
orig: None,
|
||||
});
|
||||
cur_addr += 4;
|
||||
}
|
||||
Ok(ProcessCodeResult { ops, insts })
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
section: &ObjSection,
|
||||
address: u64,
|
||||
reloc: &Relocation,
|
||||
) -> Result<i64> {
|
||||
let data = section.data[address as usize..address as usize + 4].try_into()?;
|
||||
let addend = self.endianness.read_u32_bytes(data);
|
||||
Ok(match reloc.flags() {
|
||||
RelocationFlags::Elf { r_type: elf::R_MIPS_32 } => addend as i64,
|
||||
RelocationFlags::Elf { r_type: elf::R_MIPS_HI16 } => {
|
||||
((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,
|
||||
} => (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:?}"),
|
||||
})
|
||||
}
|
||||
|
||||
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str> {
|
||||
match flags {
|
||||
RelocationFlags::Elf { r_type } => match r_type {
|
||||
elf::R_MIPS_HI16 => Cow::Borrowed("R_MIPS_HI16"),
|
||||
elf::R_MIPS_LO16 => Cow::Borrowed("R_MIPS_LO16"),
|
||||
elf::R_MIPS_GOT16 => Cow::Borrowed("R_MIPS_GOT16"),
|
||||
elf::R_MIPS_CALL16 => Cow::Borrowed("R_MIPS_CALL16"),
|
||||
elf::R_MIPS_GPREL16 => Cow::Borrowed("R_MIPS_GPREL16"),
|
||||
elf::R_MIPS_32 => Cow::Borrowed("R_MIPS_32"),
|
||||
elf::R_MIPS_26 => Cow::Borrowed("R_MIPS_26"),
|
||||
_ => Cow::Owned(format!("<Elf {r_type:?}>")),
|
||||
},
|
||||
flags => Cow::Owned(format!("<{flags:?}>")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
||||
match reloc.flags {
|
||||
RelocationFlags::Elf { r_type } => match r_type {
|
||||
elf::R_MIPS_HI16 => {
|
||||
args.push(ObjInsArg::PlainText("%hi(".to_string()));
|
||||
args.push(ObjInsArg::Reloc);
|
||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
||||
}
|
||||
elf::R_MIPS_LO16 => {
|
||||
args.push(ObjInsArg::PlainText("%lo(".to_string()));
|
||||
args.push(ObjInsArg::Reloc);
|
||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
||||
}
|
||||
elf::R_MIPS_GOT16 => {
|
||||
args.push(ObjInsArg::PlainText("%got(".to_string()));
|
||||
args.push(ObjInsArg::Reloc);
|
||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
||||
}
|
||||
elf::R_MIPS_CALL16 => {
|
||||
args.push(ObjInsArg::PlainText("%call16(".to_string()));
|
||||
args.push(ObjInsArg::Reloc);
|
||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
||||
}
|
||||
elf::R_MIPS_GPREL16 => {
|
||||
args.push(ObjInsArg::PlainText("%gp_rel(".to_string()));
|
||||
args.push(ObjInsArg::Reloc);
|
||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
||||
}
|
||||
elf::R_MIPS_32 | elf::R_MIPS_26 => {
|
||||
args.push(ObjInsArg::Reloc);
|
||||
}
|
||||
_ => bail!("Unsupported ELF MIPS relocation type {r_type}"),
|
||||
},
|
||||
flags => panic!("Unsupported MIPS relocation flags {flags:?}"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user