Support PowerPC COFF (Xenon, Xbox 360)

ppc750cl is superseded by the powerpc crate, which
supports PPC64, AltiVec and VMX128 extensions.
This commit is contained in:
2025-07-17 13:32:50 -06:00
parent 127ae5ae44
commit 60b227f45e
13 changed files with 636 additions and 547 deletions

View File

@@ -55,16 +55,16 @@ pub enum DataType {
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DataType::Int8 => f.write_str("Int8"),
DataType::Int16 => f.write_str("Int16"),
DataType::Int32 => f.write_str("Int32"),
DataType::Int64 => f.write_str("Int64"),
DataType::Float => f.write_str("Float"),
DataType::Double => f.write_str("Double"),
DataType::Bytes => f.write_str("Bytes"),
DataType::String => f.write_str("String"),
}
f.write_str(match self {
DataType::Int8 => "Int8",
DataType::Int16 => "Int16",
DataType::Int32 => "Int32",
DataType::Int64 => "Int64",
DataType::Float => "Float",
DataType::Double => "Double",
DataType::Bytes => "Bytes",
DataType::String => "String",
})
}
}

View File

@@ -11,7 +11,7 @@ use core::{
};
use itertools::Itertools;
use ppc750cl::Simm;
use powerpc::{Extensions, Simm};
use crate::{
arch::DataType,
@@ -19,8 +19,8 @@ use crate::{
util::{RawDouble, RawFloat},
};
fn is_store_instruction(op: ppc750cl::Opcode) -> bool {
use ppc750cl::Opcode;
fn is_store_instruction(op: powerpc::Opcode) -> bool {
use powerpc::Opcode;
matches!(
op,
Opcode::Stbux
@@ -52,8 +52,8 @@ fn is_store_instruction(op: ppc750cl::Opcode) -> bool {
)
}
pub fn guess_data_type_from_load_store_inst_op(inst_op: ppc750cl::Opcode) -> Option<DataType> {
use ppc750cl::Opcode;
pub fn guess_data_type_from_load_store_inst_op(inst_op: powerpc::Opcode) -> Option<DataType> {
use powerpc::Opcode;
match inst_op {
Opcode::Lbz | Opcode::Lbzu | Opcode::Lbzux | Opcode::Lbzx => Some(DataType::Int8),
Opcode::Lhz | Opcode::Lhzu | Opcode::Lhzux | Opcode::Lhzx => Some(DataType::Int16),
@@ -118,12 +118,12 @@ impl RegisterState {
// During a function call, these registers must be assumed trashed.
fn clear_volatile(&mut self) {
self[ppc750cl::GPR(0)] = RegisterContent::Unknown;
self[powerpc::GPR(0)] = RegisterContent::Unknown;
for i in 0..=13 {
self[ppc750cl::GPR(i)] = RegisterContent::Unknown;
self[powerpc::GPR(i)] = RegisterContent::Unknown;
}
for i in 0..=13 {
self[ppc750cl::FPR(i)] = RegisterContent::Unknown;
self[powerpc::FPR(i)] = RegisterContent::Unknown;
}
}
@@ -132,10 +132,10 @@ impl RegisterState {
// they get overwritten with another value before getting read.
fn set_potential_inputs(&mut self) {
for g_reg in 3..=13 {
self[ppc750cl::GPR(g_reg)] = RegisterContent::InputRegister(g_reg);
self[powerpc::GPR(g_reg)] = RegisterContent::InputRegister(g_reg);
}
for f_reg in 1..=13 {
self[ppc750cl::FPR(f_reg)] = RegisterContent::InputRegister(f_reg);
self[powerpc::FPR(f_reg)] = RegisterContent::InputRegister(f_reg);
}
}
@@ -172,34 +172,34 @@ impl RegisterState {
}
}
impl Index<ppc750cl::GPR> for RegisterState {
impl Index<powerpc::GPR> for RegisterState {
type Output = RegisterContent;
fn index(&self, gpr: ppc750cl::GPR) -> &Self::Output { &self.gpr[gpr.0 as usize] }
fn index(&self, gpr: powerpc::GPR) -> &Self::Output { &self.gpr[gpr.0 as usize] }
}
impl IndexMut<ppc750cl::GPR> for RegisterState {
fn index_mut(&mut self, gpr: ppc750cl::GPR) -> &mut Self::Output {
impl IndexMut<powerpc::GPR> for RegisterState {
fn index_mut(&mut self, gpr: powerpc::GPR) -> &mut Self::Output {
&mut self.gpr[gpr.0 as usize]
}
}
impl Index<ppc750cl::FPR> for RegisterState {
impl Index<powerpc::FPR> for RegisterState {
type Output = RegisterContent;
fn index(&self, fpr: ppc750cl::FPR) -> &Self::Output { &self.fpr[fpr.0 as usize] }
fn index(&self, fpr: powerpc::FPR) -> &Self::Output { &self.fpr[fpr.0 as usize] }
}
impl IndexMut<ppc750cl::FPR> for RegisterState {
fn index_mut(&mut self, fpr: ppc750cl::FPR) -> &mut Self::Output {
impl IndexMut<powerpc::FPR> for RegisterState {
fn index_mut(&mut self, fpr: powerpc::FPR) -> &mut Self::Output {
&mut self.fpr[fpr.0 as usize]
}
}
fn execute_instruction(
registers: &mut RegisterState,
op: &ppc750cl::Opcode,
args: &ppc750cl::Arguments,
op: &powerpc::Opcode,
args: &powerpc::Arguments,
) {
use ppc750cl::{Argument, GPR, Opcode};
use powerpc::{Argument, GPR, Opcode};
match (op, args[0], args[1], args[2]) {
(Opcode::Or, Argument::GPR(a), Argument::GPR(b), Argument::GPR(c)) => {
// Move is implemented as or with self for ints
@@ -270,11 +270,11 @@ fn execute_instruction(
}
}
fn get_branch_offset(args: &ppc750cl::Arguments) -> i32 {
fn get_branch_offset(args: &powerpc::Arguments) -> i32 {
for arg in args.iter() {
match arg {
ppc750cl::Argument::BranchDest(dest) => return dest.0 / 4,
ppc750cl::Argument::None => break,
powerpc::Argument::BranchDest(dest) => return dest.0 / 4,
powerpc::Argument::None => break,
_ => {}
}
}
@@ -316,7 +316,7 @@ fn clamp_text_length(s: String, max: usize) -> String {
fn get_register_content_from_reloc(
reloc: &Relocation,
obj: &Object,
op: ppc750cl::Opcode,
op: powerpc::Opcode,
) -> RegisterContent {
if let Some(bytes) = obj.symbol_data(reloc.target_symbol) {
match guess_data_type_from_load_store_inst_op(op) {
@@ -354,18 +354,18 @@ fn fill_registers_from_relocation(
reloc: &Relocation,
current_state: &mut RegisterState,
obj: &Object,
op: ppc750cl::Opcode,
args: &ppc750cl::Arguments,
op: powerpc::Opcode,
args: &powerpc::Arguments,
) {
// Only update the register state for loads. We may store to a reloc
// address but that doesn't update register contents.
if !is_store_instruction(op) {
match (op, args[0]) {
// Everything else is a load of some sort
(_, ppc750cl::Argument::GPR(gpr)) => {
(_, powerpc::Argument::GPR(gpr)) => {
current_state[gpr] = get_register_content_from_reloc(reloc, obj, op);
}
(_, ppc750cl::Argument::FPR(fpr)) => {
(_, powerpc::Argument::FPR(fpr)) => {
current_state[fpr] = get_register_content_from_reloc(reloc, obj, op);
}
_ => {}
@@ -384,11 +384,12 @@ pub fn ppc_data_flow_analysis(
func_symbol: &Symbol,
code: &[u8],
relocations: &[Relocation],
extensions: Extensions,
) -> Box<dyn FlowAnalysisResult> {
use alloc::collections::VecDeque;
use ppc750cl::InsIter;
let instructions = InsIter::new(code, func_symbol.address as u32)
use powerpc::InsIter;
let instructions = InsIter::new(code, func_symbol.address as u32, extensions)
.map(|(_addr, ins)| (ins.op, ins.basic().args))
.collect_vec();
@@ -449,7 +450,7 @@ pub fn ppc_data_flow_analysis(
// Only take a given (address, register state) combination once. If
// the known register state is different we have to take the branch
// again to stabilize the known values for backwards branches.
if op == &ppc750cl::Opcode::Bc {
if op == &powerpc::Opcode::Bc {
let branch_state = (index, current_state.clone());
if !taken_branches.contains(&branch_state) {
let offset = get_branch_offset(args);
@@ -468,7 +469,7 @@ pub fn ppc_data_flow_analysis(
}
// Update index
if op == &ppc750cl::Opcode::B {
if op == &powerpc::Opcode::B {
// Unconditional branch
let offset = get_branch_offset(args);
if offset > 0 {
@@ -502,7 +503,14 @@ pub fn ppc_data_flow_analysis(
}
// Store the relevant data flow values for simplified instructions
generate_flow_analysis_result(obj, func_address, code, register_state_at, relocations)
generate_flow_analysis_result(
obj,
func_address,
code,
register_state_at,
relocations,
extensions,
)
}
fn get_string_data(obj: &Object, symbol_index: usize, offset: Simm) -> Option<&str> {
@@ -530,14 +538,15 @@ fn generate_flow_analysis_result(
code: &[u8],
register_state_at: Vec<RegisterState>,
relocations: &[Relocation],
extensions: Extensions,
) -> Box<PPCFlowAnalysisResult> {
use ppc750cl::{Argument, InsIter};
use powerpc::{Argument, InsIter};
let mut analysis_result = PPCFlowAnalysisResult::new();
let default_register_state = RegisterState::new();
for (addr, ins) in InsIter::new(code, 0) {
for (addr, ins) in InsIter::new(code, 0, extensions) {
let ins_address = base_address + (addr as u64);
let index = addr / 4;
let ppc750cl::ParsedIns { mnemonic: _, args } = ins.simplified();
let powerpc::ParsedIns { mnemonic: _, args } = ins.simplified();
// If we're already showing relocations on a line don't also show data flow
let reloc = relocations.iter().find(|r| (r.address & !3) == ins_address);
@@ -546,7 +555,7 @@ fn generate_flow_analysis_result(
// they are being loaded.
// We need to do this before we break out on showing relocations in the
// subsequent if statement.
if let (ppc750cl::Opcode::Lfs | ppc750cl::Opcode::Lfd, Some(reloc)) = (ins.op, reloc) {
if let (powerpc::Opcode::Lfs | powerpc::Opcode::Lfd, Some(reloc)) = (ins.op, reloc) {
let content = get_register_content_from_reloc(reloc, obj, ins.op);
if matches!(
content,
@@ -566,7 +575,7 @@ fn generate_flow_analysis_result(
// Special case to show string constants on the line where they are
// being indexed to. This will typically be "addi t, stringbase, offset"
let registers = register_state_at.get(index as usize).unwrap_or(&default_register_state);
if let (ppc750cl::Opcode::Addi, Argument::GPR(rel), Argument::Simm(offset)) =
if let (powerpc::Opcode::Addi, Argument::GPR(rel), Argument::Simm(offset)) =
(ins.op, args[1], args[2])
{
if let RegisterContent::Symbol(sym_index) = registers[rel] {

View File

@@ -9,7 +9,7 @@ use alloc::{
use anyhow::{Result, bail, ensure};
use cwextab::{ExceptionTableData, decode_extab};
use flagset::Flags;
use object::{Object as _, ObjectSection as _, ObjectSymbol as _, elf};
use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, elf, pe};
use crate::{
arch::{Arch, DataType},
@@ -27,58 +27,79 @@ use crate::{
mod flow_analysis;
// Relative relocation, can be Simm, Offset or BranchDest
fn is_relative_arg(arg: &ppc750cl::Argument) -> bool {
fn is_relative_arg(arg: &powerpc::Argument) -> bool {
matches!(
arg,
ppc750cl::Argument::Simm(_)
| ppc750cl::Argument::Offset(_)
| ppc750cl::Argument::BranchDest(_)
powerpc::Argument::Simm(_)
| powerpc::Argument::Offset(_)
| powerpc::Argument::BranchDest(_)
)
}
// Relative or absolute relocation, can be Uimm, Simm or Offset
fn is_rel_abs_arg(arg: &ppc750cl::Argument) -> bool {
fn is_rel_abs_arg(arg: &powerpc::Argument) -> bool {
matches!(
arg,
ppc750cl::Argument::Uimm(_) | ppc750cl::Argument::Simm(_) | ppc750cl::Argument::Offset(_)
powerpc::Argument::Uimm(_) | powerpc::Argument::Simm(_) | powerpc::Argument::Offset(_)
)
}
fn is_offset_arg(arg: &ppc750cl::Argument) -> bool { matches!(arg, ppc750cl::Argument::Offset(_)) }
fn is_offset_arg(arg: &powerpc::Argument) -> bool { matches!(arg, powerpc::Argument::Offset(_)) }
#[derive(Debug)]
pub struct ArchPpc {
pub extensions: powerpc::Extensions,
/// Exception info
pub extab: Option<BTreeMap<usize, ExceptionInfo>>,
}
impl ArchPpc {
pub fn new(file: &object::File) -> Result<Self> {
Ok(Self { extab: decode_exception_info(file)? })
let extensions = match file.flags() {
object::FileFlags::Coff { .. } => powerpc::Extensions::xenon(),
object::FileFlags::Elf { e_flags, .. }
if (e_flags & elf::EF_PPC_EMB) == elf::EF_PPC_EMB =>
{
powerpc::Extensions::gekko_broadway()
}
_ => {
if file.is_64() {
powerpc::Extension::Ppc64 | powerpc::Extension::AltiVec
} else {
powerpc::Extension::AltiVec.into()
}
}
};
let extab = decode_exception_info(file)?;
Ok(Self { extensions, extab })
}
fn parse_ins_ref(&self, resolved: ResolvedInstructionRef) -> Result<ppc750cl::Ins> {
fn parse_ins_ref(&self, resolved: ResolvedInstructionRef) -> Result<powerpc::Ins> {
let mut code = u32::from_be_bytes(resolved.code.try_into()?);
if let Some(reloc) = resolved.relocation {
code = zero_reloc(code, reloc.relocation);
}
let op = ppc750cl::Opcode::from(resolved.ins_ref.opcode as u8);
Ok(ppc750cl::Ins { code, op })
let op = powerpc::Opcode::from(resolved.ins_ref.opcode);
Ok(powerpc::Ins { code, op })
}
fn find_reloc_arg(
&self,
ins: &ppc750cl::ParsedIns,
ins: &powerpc::ParsedIns,
resolved: Option<ResolvedRelocation>,
) -> Option<usize> {
match resolved?.relocation.flags {
RelocationFlags::Elf(elf::R_PPC_EMB_SDA21) => Some(1),
RelocationFlags::Elf(elf::R_PPC_REL24 | elf::R_PPC_REL14) => {
RelocationFlags::Elf(elf::R_PPC_REL24 | elf::R_PPC_REL14)
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL24 | pe::IMAGE_REL_PPC_REL14) => {
ins.args.iter().rposition(is_relative_arg)
}
RelocationFlags::Elf(
elf::R_PPC_ADDR16_HI | elf::R_PPC_ADDR16_HA | elf::R_PPC_ADDR16_LO,
) => ins.args.iter().rposition(is_rel_abs_arg),
)
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO) => {
ins.args.iter().rposition(is_rel_abs_arg)
}
_ => None,
}
}
@@ -96,11 +117,11 @@ impl Arch for ArchPpc {
ensure!(code.len() & 3 == 0, "Code length must be a multiple of 4");
let ins_count = code.len() / 4;
let mut insts = Vec::<InstructionRef>::with_capacity(ins_count);
for (cur_addr, ins) in ppc750cl::InsIter::new(code, address as u32) {
for (cur_addr, ins) in powerpc::InsIter::new(code, address as u32, self.extensions) {
insts.push(InstructionRef {
address: cur_addr as u64,
size: 4,
opcode: u8::from(ins.op) as u16,
opcode: u16::from(ins.op),
branch_dest: ins.branch_dest(cur_addr).map(u64::from),
});
}
@@ -131,16 +152,16 @@ impl Arch for ArchPpc {
// For @sda21, we can omit the register argument
if matches!(reloc.relocation.flags, RelocationFlags::Elf(elf::R_PPC_EMB_SDA21))
// Sanity check: the next argument should be r0
&& matches!(ins.args.get(idx + 1), Some(ppc750cl::Argument::GPR(ppc750cl::GPR(0))))
&& matches!(ins.args.get(idx + 1), Some(powerpc::Argument::GPR(powerpc::GPR(0))))
{
break;
}
} else {
match arg {
ppc750cl::Argument::Simm(simm) => cb(InstructionPart::signed(simm.0)),
ppc750cl::Argument::Uimm(uimm) => cb(InstructionPart::unsigned(uimm.0)),
ppc750cl::Argument::Offset(offset) => cb(InstructionPart::signed(offset.0)),
ppc750cl::Argument::BranchDest(dest) => cb(InstructionPart::branch_dest(
powerpc::Argument::Simm(simm) => cb(InstructionPart::signed(simm.0)),
powerpc::Argument::Uimm(uimm) => cb(InstructionPart::unsigned(uimm.0)),
powerpc::Argument::Offset(offset) => cb(InstructionPart::signed(offset.0)),
powerpc::Argument::BranchDest(dest) => cb(InstructionPart::branch_dest(
(resolved.ins_ref.address as u32).wrapping_add_signed(dest.0),
)),
_ => cb(InstructionPart::opaque(arg.to_string())),
@@ -168,7 +189,13 @@ impl Arch for ArchPpc {
relocations: &[Relocation],
symbols: &[Symbol],
) -> Vec<Relocation> {
generate_fake_pool_relocations_for_function(address, code, relocations, symbols)
generate_fake_pool_relocations_for_function(
address,
code,
relocations,
symbols,
self.extensions,
)
}
fn data_flow_analysis(
@@ -178,22 +205,48 @@ impl Arch for ArchPpc {
code: &[u8],
relocations: &[Relocation],
) -> Option<Box<dyn FlowAnalysisResult>> {
Some(flow_analysis::ppc_data_flow_analysis(obj, symbol, code, relocations))
Some(flow_analysis::ppc_data_flow_analysis(obj, symbol, code, relocations, self.extensions))
}
fn implcit_addend(
&self,
_file: &object::File<'_>,
_section: &object::Section,
file: &object::File<'_>,
section: &object::Section,
address: u64,
_relocation: &object::Relocation,
flags: RelocationFlags,
) -> Result<i64> {
bail!("Unsupported PPC implicit relocation {:#x}:{:?}", address, flags)
let section_data = section.data()?;
let address = address as usize;
let data = section_data
.get(address..address + 4)
.ok_or_else(|| anyhow::anyhow!("Invalid address {address} for section data"))?
.try_into()?;
let code = file.endianness().read_u32_bytes(data);
Ok(match flags {
RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI)
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFLO) => (code & 0xffff) as i16 as i32,
RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL24) => {
// let addend = (((code & 0x3fffffc) << 6) as i32) >> 6;
// println!("PPC_REL24 addend: {data:?} => {addend}");
// addend
0
}
RelocationFlags::Coff(pe::IMAGE_REL_PPC_ADDR32) => code as i32,
RelocationFlags::Coff(pe::IMAGE_REL_PPC_PAIR) => 0,
flags => bail!("Unsupported PPC implicit relocation {flags:?}"),
} as i64)
}
fn demangle(&self, name: &str) -> Option<String> {
cwdemangle::demangle(name, &cwdemangle::DemangleOptions::default())
if name.starts_with('?') {
msvc_demangler::demangle(name, msvc_demangler::DemangleFlags::llvm()).ok()
} else {
cpp_demangle::Symbol::new(name)
.ok()
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
.or_else(|| cwdemangle::demangle(name, &cwdemangle::DemangleOptions::default()))
}
}
fn reloc_name(&self, flags: RelocationFlags) -> Option<&'static str> {
@@ -238,7 +291,7 @@ impl Arch for ArchPpc {
// Pooled string.
return Some(DataType::String);
}
let opcode = ppc750cl::Opcode::from(resolved.ins_ref.opcode as u8);
let opcode = powerpc::Opcode::from(resolved.ins_ref.opcode);
if let Some(ty) = flow_analysis::guess_data_type_from_load_store_inst_op(opcode) {
// Numeric type.
return Some(ty);
@@ -336,11 +389,18 @@ impl ArchPpc {
fn zero_reloc(code: u32, reloc: &Relocation) -> u32 {
match reloc.flags {
RelocationFlags::Elf(elf::R_PPC_EMB_SDA21) => code & !0x1FFFFF,
RelocationFlags::Elf(elf::R_PPC_REL24) => code & !0x3FFFFFC,
RelocationFlags::Elf(elf::R_PPC_REL14) => code & !0xFFFC,
RelocationFlags::Elf(elf::R_PPC_REL24) | RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL24) => {
code & !0x3FFFFFC
}
RelocationFlags::Elf(elf::R_PPC_REL14) | RelocationFlags::Coff(pe::IMAGE_REL_PPC_REL14) => {
code & !0xFFFC
}
RelocationFlags::Elf(
elf::R_PPC_ADDR16_HI | elf::R_PPC_ADDR16_HA | elf::R_PPC_ADDR16_LO,
) => code & !0xFFFF,
)
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI | pe::IMAGE_REL_PPC_REFLO) => {
code & !0xFFFF
}
_ => code,
}
}
@@ -350,34 +410,38 @@ fn display_reloc(
cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
) -> Result<()> {
match resolved.relocation.flags {
RelocationFlags::Elf(r_type) => match r_type {
elf::R_PPC_ADDR16_LO => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@l"))?;
}
elf::R_PPC_ADDR16_HI => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@h"))?;
}
elf::R_PPC_ADDR16_HA => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@ha"))?;
}
elf::R_PPC_EMB_SDA21 => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@sda21"))?;
}
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14 => {
cb(InstructionPart::reloc())?;
}
elf::R_PPC_NONE => {
// Fake pool relocation.
cb(InstructionPart::basic("<"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic(">"))?;
}
_ => cb(InstructionPart::reloc())?,
},
RelocationFlags::Elf(elf::R_PPC_ADDR16_LO)
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFLO) => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@l"))?;
}
RelocationFlags::Elf(elf::R_PPC_ADDR16_HI)
| RelocationFlags::Coff(pe::IMAGE_REL_PPC_REFHI) => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@h"))?;
}
RelocationFlags::Elf(elf::R_PPC_ADDR16_HA) => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@ha"))?;
}
RelocationFlags::Elf(elf::R_PPC_EMB_SDA21) => {
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic("@sda21"))?;
}
RelocationFlags::Elf(
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14,
)
| RelocationFlags::Coff(
pe::IMAGE_REL_PPC_ADDR32 | pe::IMAGE_REL_PPC_REL24 | pe::IMAGE_REL_PPC_REL14,
) => {
cb(InstructionPart::reloc())?;
}
RelocationFlags::Elf(elf::R_PPC_NONE) => {
// Fake pool relocation.
cb(InstructionPart::basic("<"))?;
cb(InstructionPart::reloc())?;
cb(InstructionPart::basic(">"))?;
}
_ => cb(InstructionPart::reloc())?,
};
Ok(())
@@ -515,19 +579,19 @@ fn make_symbol_ref(symbol: &object::Symbol) -> Result<ExtabSymbolRef> {
#[derive(Debug)]
struct PoolReference {
addr_src_gpr: ppc750cl::GPR,
addr_src_gpr: powerpc::GPR,
addr_offset: i16,
addr_dst_gpr: Option<ppc750cl::GPR>,
addr_dst_gpr: Option<powerpc::GPR>,
}
// Given an instruction, check if it could be accessing pooled data at the address in a register.
// If so, return information pertaining to where the instruction is getting that address from and
// what it's doing with the address (e.g. copying it into another register, adding an offset, etc).
fn get_pool_reference_for_inst(
opcode: ppc750cl::Opcode,
simplified: &ppc750cl::ParsedIns,
opcode: powerpc::Opcode,
simplified: &powerpc::ParsedIns,
) -> Option<PoolReference> {
use ppc750cl::{Argument, Opcode};
use powerpc::{Argument, Opcode};
let args = &simplified.args;
if flow_analysis::guess_data_type_from_load_store_inst_op(opcode).is_some() {
match (args[1], args[2]) {
@@ -592,15 +656,15 @@ fn get_pool_reference_for_inst(
// Remove the relocation we're keeping track of in a particular register when an instruction reuses
// that register to hold some other value, unrelated to pool relocation addresses.
fn clear_overwritten_gprs(ins: ppc750cl::Ins, gpr_pool_relocs: &mut BTreeMap<u8, Relocation>) {
use ppc750cl::{Argument, Arguments, Opcode};
fn clear_overwritten_gprs(ins: powerpc::Ins, gpr_pool_relocs: &mut BTreeMap<u8, Relocation>) {
use powerpc::{Argument, Arguments, Opcode};
let mut def_args = Arguments::default();
ins.parse_defs(&mut def_args);
for arg in def_args {
if let Argument::GPR(gpr) = arg {
if ins.op == Opcode::Lmw {
// `lmw` overwrites all registers from rd to r31.
// ppc750cl only returns rd itself, so we manually clear the rest of them.
// powerpc only returns rd itself, so we manually clear the rest of them.
for reg in gpr.0..31 {
gpr_pool_relocs.remove(&reg);
}
@@ -682,12 +746,13 @@ fn generate_fake_pool_relocations_for_function(
code: &[u8],
relocations: &[Relocation],
symbols: &[Symbol],
extensions: powerpc::Extensions,
) -> Vec<Relocation> {
use ppc750cl::{Argument, InsIter, Opcode};
use powerpc::{Argument, InsIter, Opcode};
let mut visited_ins_addrs = BTreeSet::new();
let mut pool_reloc_for_addr = BTreeMap::new();
let mut ins_iters_with_gpr_state =
vec![(InsIter::new(code, func_address as u32), BTreeMap::new())];
vec![(InsIter::new(code, func_address as u32, extensions), BTreeMap::new())];
let mut gpr_state_at_bctr = BTreeMap::new();
while let Some((ins_iter, mut gpr_pool_relocs)) = ins_iters_with_gpr_state.pop() {
for (cur_addr, ins) in ins_iter {
@@ -719,7 +784,7 @@ fn generate_fake_pool_relocations_for_function(
// Conditional branch.
// Add the branch destination to the queue to do later.
ins_iters_with_gpr_state.push((
InsIter::new(dest_code_slice, branch_dest),
InsIter::new(dest_code_slice, branch_dest, extensions),
gpr_pool_relocs.clone(),
));
// Then continue on with the current iterator.
@@ -729,7 +794,7 @@ fn generate_fake_pool_relocations_for_function(
// Unconditional branch.
// Add the branch destination to the queue.
ins_iters_with_gpr_state.push((
InsIter::new(dest_code_slice, branch_dest),
InsIter::new(dest_code_slice, branch_dest, extensions),
gpr_pool_relocs.clone(),
));
// Break out of the current iterator so we can do the newly added one.
@@ -837,7 +902,7 @@ fn generate_fake_pool_relocations_for_function(
let dest_offset_into_func = unseen_addr - func_address as u32;
let dest_code_slice = &code[dest_offset_into_func as usize..];
ins_iters_with_gpr_state.push((
InsIter::new(dest_code_slice, unseen_addr),
InsIter::new(dest_code_slice, unseen_addr, extensions),
gpr_pool_relocs.clone(),
));
break;

View File

@@ -114,7 +114,17 @@ impl Section {
ins_ref: InstructionRef,
) -> Option<ResolvedRelocation<'obj>> {
match self.relocations.binary_search_by_key(&ins_ref.address, |r| r.address) {
Ok(i) => self.relocations.get(i),
Ok(mut i) => {
// Find the first relocation at the address
while i
.checked_sub(1)
.and_then(|n| self.relocations.get(n))
.is_some_and(|r| r.address == ins_ref.address)
{
i -= 1;
}
self.relocations.get(i)
}
Err(i) => self
.relocations
.get(i)