Skip to content

Commit b1f8a2a

Browse files
committed
Improve readability of PPC pool relocs code
1 parent 6365452 commit b1f8a2a

File tree

1 file changed

+35
-22
lines changed

1 file changed

+35
-22
lines changed

objdiff-core/src/arch/ppc.rs

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl Arch for ArchPpc {
166166
relocations: &[Relocation],
167167
symbols: &[Symbol],
168168
) -> Vec<Relocation> {
169-
generate_fake_pool_reloc_for_addr_mapping(address, code, relocations, symbols)
169+
generate_fake_pool_relocations_for_function(address, code, relocations, symbols)
170170
}
171171

172172
fn implcit_addend(
@@ -513,28 +513,34 @@ fn guess_data_type_from_load_store_inst_op(inst_op: ppc750cl::Opcode) -> Option<
513513
}
514514
}
515515

516-
// Given an instruction, determine if it could accessing data at the address in a register.
517-
// If so, return the offset added to the register's address, the register containing that address,
518-
// and (optionally) which destination register the address is being copied into.
519-
fn get_offset_and_addr_gpr_for_possible_pool_reference(
516+
struct PoolReference {
517+
addr_src_gpr: ppc750cl::GPR,
518+
addr_offset: i16,
519+
addr_dst_gpr: Option<ppc750cl::GPR>,
520+
}
521+
522+
// Given an instruction, check if it could be accessing pooled data at the address in a register.
523+
// If so, return information pertaining to where the instruction is getting that address from and
524+
// what it's doing with the address (e.g. copying it into another register, adding an offset, etc).
525+
fn get_pool_reference_for_inst(
520526
opcode: ppc750cl::Opcode,
521527
simplified: &ppc750cl::ParsedIns,
522-
) -> Option<(i16, ppc750cl::GPR, Option<ppc750cl::GPR>)> {
528+
) -> Option<PoolReference> {
523529
use ppc750cl::{Argument, Opcode};
524530
let args = &simplified.args;
525531
if guess_data_type_from_load_store_inst_op(opcode).is_some() {
526532
match (args[1], args[2]) {
527533
(Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => {
528534
// e.g. lwz. Immediate offset.
529-
Some((offset.0, addr_src_gpr, None))
535+
Some(PoolReference { addr_src_gpr, addr_offset: offset.0, addr_dst_gpr: None })
530536
}
531537
(Argument::GPR(addr_src_gpr), Argument::GPR(_offset_gpr)) => {
532538
// e.g. lwzx. The offset is in a register and was likely calculated from an index.
533539
// Treat the offset as being 0 in this case to show the first element of the array.
534540
// It may be possible to show all elements by figuring out the stride of the array
535541
// from the calculations performed on the index before it's put into offset_gpr, but
536542
// this would be much more complicated, so it's not currently done.
537-
Some((0, addr_src_gpr, None))
543+
Some(PoolReference { addr_src_gpr, addr_offset: 0, addr_dst_gpr: None })
538544
}
539545
_ => None,
540546
}
@@ -552,20 +558,32 @@ fn get_offset_and_addr_gpr_for_possible_pool_reference(
552558
Argument::GPR(addr_dst_gpr),
553559
Argument::GPR(addr_src_gpr),
554560
Argument::Simm(simm),
555-
) => Some((simm.0, addr_src_gpr, Some(addr_dst_gpr))),
561+
) => Some(PoolReference {
562+
addr_src_gpr,
563+
addr_offset: simm.0,
564+
addr_dst_gpr: Some(addr_dst_gpr),
565+
}),
556566
(
557567
// `mr` or `mr.`
558568
Opcode::Or,
559569
Argument::GPR(addr_dst_gpr),
560570
Argument::GPR(addr_src_gpr),
561571
Argument::None,
562-
) => Some((0, addr_src_gpr, Some(addr_dst_gpr))),
572+
) => Some(PoolReference {
573+
addr_src_gpr,
574+
addr_offset: 0,
575+
addr_dst_gpr: Some(addr_dst_gpr),
576+
}),
563577
(
564578
Opcode::Add,
565579
Argument::GPR(addr_dst_gpr),
566580
Argument::GPR(addr_src_gpr),
567581
Argument::GPR(_offset_gpr),
568-
) => Some((0, addr_src_gpr, Some(addr_dst_gpr))),
582+
) => Some(PoolReference {
583+
addr_src_gpr,
584+
addr_offset: 0,
585+
addr_dst_gpr: Some(addr_dst_gpr),
586+
}),
569587
_ => None,
570588
}
571589
}
@@ -607,16 +625,13 @@ fn make_fake_pool_reloc(
607625
let pool_reloc = resolve_relocation(symbols, pool_reloc);
608626
let offset_from_pool = pool_reloc.relocation.addend + offset as i64;
609627
let target_address = pool_reloc.symbol.address.checked_add_signed(offset_from_pool)?;
610-
611628
let section_index = pool_reloc.symbol.section?;
612-
613629
let target_symbol = symbols.iter().position(|s| {
614630
s.section == Some(section_index)
615631
&& s.size > 0
616632
&& (s.address..s.address + s.size).contains(&target_address)
617633
})?;
618634
let addend = target_address.checked_sub(symbols[target_symbol].address)? as i64;
619-
620635
Some(Relocation {
621636
flags: RelocationFlags::Elf(elf::R_PPC_NONE),
622637
address: cur_addr as u64,
@@ -644,7 +659,7 @@ fn make_fake_pool_reloc(
644659
// It should be possible to implement jump tables properly by reading them out of .data. But this
645660
// will require keeping track of what value is loaded into each register so we can retrieve the jump
646661
// table symbol when we encounter a `bctr`.
647-
fn generate_fake_pool_reloc_for_addr_mapping(
662+
fn generate_fake_pool_relocations_for_function(
648663
func_address: u64,
649664
code: &[u8],
650665
relocations: &[Relocation],
@@ -754,18 +769,16 @@ fn generate_fake_pool_reloc_for_addr_mapping(
754769
clear_overwritten_gprs(ins, &mut gpr_pool_relocs);
755770
}
756771
}
757-
} else if let Some((offset, addr_src_gpr, addr_dst_gpr)) =
758-
get_offset_and_addr_gpr_for_possible_pool_reference(ins.op, &simplified)
759-
{
772+
} else if let Some(pool_ref) = get_pool_reference_for_inst(ins.op, &simplified) {
760773
// This instruction doesn't have a real relocation, so it may be a reference to one of
761774
// the already-loaded pools.
762-
if let Some(pool_reloc) = gpr_pool_relocs.get(&addr_src_gpr.0) {
775+
if let Some(pool_reloc) = gpr_pool_relocs.get(&pool_ref.addr_src_gpr.0) {
763776
if let Some(fake_pool_reloc) =
764-
make_fake_pool_reloc(offset, cur_addr, pool_reloc, symbols)
777+
make_fake_pool_reloc(pool_ref.addr_offset, cur_addr, pool_reloc, symbols)
765778
{
766779
pool_reloc_for_addr.insert(cur_addr, fake_pool_reloc);
767780
}
768-
if let Some(addr_dst_gpr) = addr_dst_gpr {
781+
if let Some(addr_dst_gpr) = pool_ref.addr_dst_gpr {
769782
// If the address of the pool relocation got copied into another register, we
770783
// need to keep track of it in that register too as future instructions may
771784
// reference the symbol indirectly via this new register, instead of the
@@ -775,7 +788,7 @@ fn generate_fake_pool_reloc_for_addr_mapping(
775788
// with the offset within the .data section of an array variable into r21.
776789
// Then the body of the loop will `lwzx` one of the array elements from r21.
777790
let mut new_reloc = pool_reloc.clone();
778-
new_reloc.addend += offset as i64;
791+
new_reloc.addend += pool_ref.addr_offset as i64;
779792
gpr_pool_relocs.insert(addr_dst_gpr.0, new_reloc);
780793
} else {
781794
clear_overwritten_gprs(ins, &mut gpr_pool_relocs);

0 commit comments

Comments
 (0)