Skip to content

Commit 0c7df23

Browse files
committed
PPC: Clear relocs from GPRs when overwritten
1 parent 5a086fd commit 0c7df23

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

objdiff-core/src/arch/ppc.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use object::{
1010
elf, File, Object, ObjectSection, ObjectSymbol, Relocation, RelocationFlags, RelocationTarget,
1111
Symbol, SymbolKind,
1212
};
13-
use ppc750cl::{Argument, InsIter, Opcode, ParsedIns, GPR};
13+
use ppc750cl::{Argument, Arguments, Ins, InsIter, Opcode, ParsedIns, GPR};
1414

1515
use crate::{
1616
arch::{DataType, ObjArch, ProcessCodeResult},
@@ -445,16 +445,29 @@ fn get_offset_and_addr_gpr_for_possible_pool_reference(
445445
Argument::Simm(simm),
446446
) => Some((simm.0, addr_src_gpr, Some(addr_dst_gpr))),
447447
(
448+
// `mr` or `mr.`
448449
Opcode::Or,
449450
Argument::GPR(addr_dst_gpr),
450451
Argument::GPR(addr_src_gpr),
451452
Argument::None,
452-
) => Some((0, addr_src_gpr, Some(addr_dst_gpr))), // `mr` or `mr.`
453+
) => Some((0, addr_src_gpr, Some(addr_dst_gpr))),
453454
_ => None,
454455
}
455456
}
456457
}
457458

459+
// Remove the relocation we're keeping track of in a particular register when an instruction reuses
460+
// that register to hold some other value, unrelated to pool relocation addresses.
461+
fn clear_overwritten_gprs(ins: Ins, active_pool_relocs: &mut HashMap<u8, ObjReloc>) {
462+
let mut def_args = Arguments::default();
463+
ins.parse_defs(&mut def_args);
464+
for arg in def_args {
465+
if let Argument::GPR(gpr) = arg {
466+
active_pool_relocs.remove(&gpr.0);
467+
}
468+
}
469+
}
470+
458471
// We create a fake relocation for an instruction, vaguely simulating what the actual relocation
459472
// might have looked like if it wasn't pooled. This is so minimal changes are needed to display
460473
// pooled accesses vs non-pooled accesses. We set the relocation type to R_PPC_NONE to indicate that
@@ -537,20 +550,22 @@ fn generate_fake_pool_reloc_for_addr_mapping(
537550
let args = &simplified.args;
538551
match (ins.op, args[0], args[1], args[2]) {
539552
(
553+
// `lis` + `addi`
540554
Opcode::Addi,
541555
Argument::GPR(addr_dst_gpr),
542556
Argument::GPR(_addr_src_gpr),
543557
Argument::Simm(_simm),
544558
) => {
545-
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone()); // `lis` + `addi`
559+
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone());
546560
}
547561
(
562+
// `lis` + `ori`
548563
Opcode::Ori,
549564
Argument::GPR(addr_dst_gpr),
550565
Argument::GPR(_addr_src_gpr),
551566
Argument::Uimm(_uimm),
552567
) => {
553-
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone()); // `lis` + `ori`
568+
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone());
554569
}
555570
(Opcode::B, _, _, _) => {
556571
if simplified.mnemonic == "bl" {
@@ -562,7 +577,9 @@ fn generate_fake_pool_reloc_for_addr_mapping(
562577
}
563578
}
564579
}
565-
_ => {}
580+
_ => {
581+
clear_overwritten_gprs(ins, &mut active_pool_relocs);
582+
}
566583
}
567584
} else if let Some((offset, addr_src_gpr, addr_dst_gpr)) =
568585
get_offset_and_addr_gpr_for_possible_pool_reference(ins.op, &simplified)
@@ -585,8 +602,14 @@ fn generate_fake_pool_reloc_for_addr_mapping(
585602
let mut new_reloc = pool_reloc.clone();
586603
new_reloc.addend += offset as i64;
587604
active_pool_relocs.insert(addr_dst_gpr.0, new_reloc);
605+
} else {
606+
clear_overwritten_gprs(ins, &mut active_pool_relocs);
588607
}
608+
} else {
609+
clear_overwritten_gprs(ins, &mut active_pool_relocs);
589610
}
611+
} else {
612+
clear_overwritten_gprs(ins, &mut active_pool_relocs);
590613
}
591614
}
592615

0 commit comments

Comments
 (0)