Updates & initial MIPS support

This commit is contained in:
2022-09-11 13:52:55 -04:00
parent 7bbdba5566
commit b55c919f4d
13 changed files with 874 additions and 239 deletions

74
src/obj/mips.rs Normal file
View File

@@ -0,0 +1,74 @@
use anyhow::Result;
use rabbitizer::{config_set_register_fpr_abi_names, Abi, Instruction, SimpleOperandType};
use crate::obj::{ObjIns, ObjInsArg, ObjReloc};
pub fn process_code(
data: &[u8],
start_address: u64,
end_address: u64,
relocs: &[ObjReloc],
) -> Result<(Vec<u8>, Vec<ObjIns>)> {
config_set_register_fpr_abi_names(Abi::RABBITIZER_ABI_O32);
let ins_count = data.len() / 4;
let mut ops = Vec::<u8>::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 = u32::from_be_bytes(chunk.try_into()?);
let mut instruction = Instruction::new(code, cur_addr);
let op = instruction.instr_id() as u8;
ops.push(op);
let mnemonic = instruction.instr_id().get_opcode_name().unwrap_or_default().to_string();
let is_branch = instruction.is_branch();
let branch_offset = instruction.branch_offset();
let branch_dest =
if is_branch { Some((cur_addr as i32 + branch_offset) as u32) } else { None };
let args = instruction
.simple_operands()
.iter()
.map(|op| match op.kind {
SimpleOperandType::Imm | SimpleOperandType::Label => {
if is_branch {
ObjInsArg::BranchOffset(branch_offset)
} 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
{
// Inter-function reloc, convert to branch offset
ObjInsArg::BranchOffset(reloc.target.address as i32 - cur_addr as i32)
} else {
ObjInsArg::Reloc
}
} else {
ObjInsArg::MipsArg(op.disassembled.clone())
}
}
SimpleOperandType::ImmBase => {
if reloc.is_some() {
ObjInsArg::RelocWithBase
} else {
ObjInsArg::MipsArg(op.disassembled.clone())
}
}
_ => ObjInsArg::MipsArg(op.disassembled.clone()),
})
.collect();
insts.push(ObjIns {
address: cur_addr,
code,
op,
mnemonic,
args,
reloc: reloc.cloned(),
branch_dest,
});
cur_addr += 4;
}
Ok((ops, insts))
}

89
src/obj/ppc.rs Normal file
View File

@@ -0,0 +1,89 @@
use anyhow::Result;
use ppc750cl::{disasm_iter, Argument};
use crate::obj::{ObjIns, ObjInsArg, ObjReloc, ObjRelocKind};
// Relative relocation, can be Simm or BranchOffset
fn is_relative_arg(arg: &ObjInsArg) -> bool {
matches!(arg, ObjInsArg::PpcArg(Argument::Simm(_)) | ObjInsArg::BranchOffset(_))
}
// Relative or absolute relocation, can be Uimm, Simm or Offset
fn is_rel_abs_arg(arg: &ObjInsArg) -> bool {
matches!(arg, ObjInsArg::PpcArg(arg) if matches!(arg, Argument::Uimm(_) | Argument::Simm(_) | Argument::Offset(_)))
}
fn is_offset_arg(arg: &ObjInsArg) -> bool { matches!(arg, ObjInsArg::PpcArg(Argument::Offset(_))) }
pub fn process_code(
data: &[u8],
address: u64,
relocs: &[ObjReloc],
) -> Result<(Vec<u8>, Vec<ObjIns>)> {
let ins_count = data.len() / 4;
let mut ops = Vec::<u8>::with_capacity(ins_count);
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
for mut ins in disasm_iter(data, address as u32) {
let reloc = relocs.iter().find(|r| (r.address as u32 & !3) == ins.addr);
if let Some(reloc) = reloc {
// Zero out relocations
ins.code = match reloc.kind {
ObjRelocKind::PpcEmbSda21 => ins.code & !0x1FFFFF,
ObjRelocKind::PpcRel24 => ins.code & !0x3FFFFFC,
ObjRelocKind::PpcRel14 => ins.code & !0xFFFC,
ObjRelocKind::PpcAddr16Hi
| ObjRelocKind::PpcAddr16Ha
| ObjRelocKind::PpcAddr16Lo => ins.code & !0xFFFF,
_ => ins.code,
};
}
let simplified = ins.simplified();
let mut args: Vec<ObjInsArg> = simplified
.args
.iter()
.map(|a| match a {
Argument::BranchDest(dest) => ObjInsArg::BranchOffset(dest.0),
_ => ObjInsArg::PpcArg(a.clone()),
})
.collect();
if let Some(reloc) = reloc {
match reloc.kind {
ObjRelocKind::PpcEmbSda21 => {
args = vec![args[0].clone(), ObjInsArg::Reloc];
}
ObjRelocKind::PpcRel24 | ObjRelocKind::PpcRel14 => {
let arg = args
.iter_mut()
.rfind(|a| is_relative_arg(a))
.ok_or_else(|| anyhow::Error::msg("Failed to locate rel arg for reloc"))?;
*arg = ObjInsArg::Reloc;
}
ObjRelocKind::PpcAddr16Hi
| ObjRelocKind::PpcAddr16Ha
| ObjRelocKind::PpcAddr16Lo => {
let arg = args.iter_mut().rfind(|a| is_rel_abs_arg(a)).ok_or_else(|| {
anyhow::Error::msg("Failed to locate rel/abs arg for reloc")
})?;
*arg = if is_offset_arg(arg) {
ObjInsArg::RelocWithBase
} else {
ObjInsArg::Reloc
};
}
_ => {}
}
}
ops.push(simplified.ins.op as u8);
let suffix = simplified.ins.suffix();
insts.push(ObjIns {
address: simplified.ins.addr,
code: simplified.ins.code,
mnemonic: format!("{}{}", simplified.mnemonic, suffix),
args,
reloc: reloc.cloned(),
op: 0,
branch_dest: None,
});
}
Ok((ops, insts))
}