Skip to content

Commit 9051f48

Browse files
committed
Move big functions to bottom ppc.rs
1 parent cdf3fd1 commit 9051f48

File tree

1 file changed

+174
-174
lines changed

1 file changed

+174
-174
lines changed

objdiff-core/src/arch/ppc.rs

Lines changed: 174 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -30,180 +30,6 @@ fn is_rel_abs_arg(arg: &Argument) -> bool {
3030

3131
fn is_offset_arg(arg: &Argument) -> bool { matches!(arg, Argument::Offset(_)) }
3232

33-
fn guess_data_type_from_load_store_inst_op(inst_op: Opcode) -> Option<DataType> {
34-
match inst_op {
35-
Opcode::Lbz | Opcode::Lbzu | Opcode::Lbzux | Opcode::Lbzx => Some(DataType::Int8),
36-
Opcode::Lhz | Opcode::Lhzu | Opcode::Lhzux | Opcode::Lhzx => Some(DataType::Int16),
37-
Opcode::Lha | Opcode::Lhau | Opcode::Lhaux | Opcode::Lhax => Some(DataType::Int16),
38-
Opcode::Lwz | Opcode::Lwzu | Opcode::Lwzux | Opcode::Lwzx => Some(DataType::Int32),
39-
Opcode::Lfs | Opcode::Lfsu | Opcode::Lfsux | Opcode::Lfsx => Some(DataType::Float),
40-
Opcode::Lfd | Opcode::Lfdu | Opcode::Lfdux | Opcode::Lfdx => Some(DataType::Double),
41-
42-
Opcode::Stb | Opcode::Stbu | Opcode::Stbux | Opcode::Stbx => Some(DataType::Int8),
43-
Opcode::Sth | Opcode::Sthu | Opcode::Sthux | Opcode::Sthx => Some(DataType::Int16),
44-
Opcode::Stw | Opcode::Stwu | Opcode::Stwux | Opcode::Stwx => Some(DataType::Int32),
45-
Opcode::Stfs | Opcode::Stfsu | Opcode::Stfsux | Opcode::Stfsx => Some(DataType::Float),
46-
Opcode::Stfd | Opcode::Stfdu | Opcode::Stfdux | Opcode::Stfdx => Some(DataType::Double),
47-
_ => None,
48-
}
49-
}
50-
51-
// Given an instruction, determine if it could accessing data at the address in a register.
52-
// If so, return the offset added to the register's address, the register containing that address,
53-
// and (optionally) which destination register the address is being copied into.
54-
fn get_offset_and_addr_gpr_for_possible_pool_reference(
55-
opcode: Opcode,
56-
simplified: &ParsedIns,
57-
) -> Option<(i16, GPR, Option<GPR>)> {
58-
let args = &simplified.args;
59-
if guess_data_type_from_load_store_inst_op(opcode).is_some() {
60-
match (args[1], args[2]) {
61-
(Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => {
62-
// e.g. lwz. Immediate offset.
63-
Some((offset.0, addr_src_gpr, None))
64-
}
65-
(Argument::GPR(addr_src_gpr), Argument::GPR(_offset_gpr)) => {
66-
// e.g. lwzx. The offset is in a register and was likely calculated from an index.
67-
// Treat the offset as being 0 in this case to show the first element of the array.
68-
// It may be possible to show all elements by figuring out the stride of the array
69-
// from the calculations performed on the index before it's put into offset_gpr, but
70-
// this would be much more complicated, so it's not currently done.
71-
Some((0, addr_src_gpr, None))
72-
}
73-
_ => None,
74-
}
75-
} else {
76-
// If it's not a load/store instruction, there's two more possibilities we need to handle.
77-
// 1. It could be a reference to @stringBase.
78-
// 2. It could be moving the relocation address plus an offset into a different register to
79-
// load from later.
80-
// If either of these match, we also want to return the destination register that the
81-
// address is being copied into so that we can detect any future references to that new
82-
// register as well.
83-
match (opcode, args[0], args[1], args[2]) {
84-
(
85-
Opcode::Addi,
86-
Argument::GPR(addr_dst_gpr),
87-
Argument::GPR(addr_src_gpr),
88-
Argument::Simm(simm),
89-
) => Some((simm.0, addr_src_gpr, Some(addr_dst_gpr))),
90-
(
91-
Opcode::Or,
92-
Argument::GPR(addr_dst_gpr),
93-
Argument::GPR(addr_src_gpr),
94-
Argument::None,
95-
) => Some((0, addr_src_gpr, Some(addr_dst_gpr))), // `mr` or `mr.`
96-
_ => None,
97-
}
98-
}
99-
}
100-
101-
// We create a fake relocation for an instruction, vaguely simulating what the actual relocation
102-
// might have looked like if it wasn't pooled. This is so minimal changes are needed to display
103-
// pooled accesses vs non-pooled accesses. We set the relocation type to R_PPC_NONE to indicate that
104-
// there isn't really a relocation here, as copying the pool relocation's type wouldn't make sense.
105-
// Also, if this instruction is accessing the middle of a symbol instead of the start, we add an
106-
// addend to indicate that.
107-
fn make_fake_pool_reloc(
108-
offset: i16,
109-
cur_addr: u32,
110-
pool_reloc: &ObjReloc,
111-
sections: &[ObjSection],
112-
) -> Option<ObjReloc> {
113-
let offset_from_pool = pool_reloc.addend + offset as i64;
114-
let target_address = pool_reloc.target.address.checked_add_signed(offset_from_pool)?;
115-
let orig_section_index = pool_reloc.target.orig_section_index?;
116-
let section = sections.iter().find(|s| s.orig_index == orig_section_index)?;
117-
let target_symbol = section
118-
.symbols
119-
.iter()
120-
.find(|s| s.size > 0 && (s.address..s.address + s.size).contains(&target_address))?;
121-
let addend = (target_address - target_symbol.address) as i64;
122-
Some(ObjReloc {
123-
flags: RelocationFlags::Elf { r_type: elf::R_PPC_NONE },
124-
address: cur_addr as u64,
125-
target: target_symbol.clone(),
126-
addend,
127-
})
128-
}
129-
130-
// Searches through all instructions in a function, determining which registers have the addresses
131-
// of pooled data relocations in them, finding which instructions load data from those addresses,
132-
// and constructing a mapping of the address of that instruction to a "fake pool relocation" that
133-
// simulates what that instruction's relocation would look like if data hadn't been pooled.
134-
// Limitations: This method currently only goes through the instructions in a function in linear
135-
// order, from start to finish. It does *not* follow any branches. This means that it could have
136-
// false positives or false negatives in determining which relocation is currently loaded in which
137-
// register at any given point in the function, as control flow is not respected.
138-
// There are currently no known examples of this method producing inaccurate results in reality, but
139-
// if examples are found, it may be possible to update this method to also follow all branches so
140-
// that it produces more accurate results.
141-
fn generate_fake_pool_reloc_for_addr_mapping(
142-
address: u64,
143-
code: &[u8],
144-
relocations: &[ObjReloc],
145-
sections: &[ObjSection],
146-
) -> HashMap<u32, ObjReloc> {
147-
let mut active_pool_relocs = HashMap::new();
148-
let mut pool_reloc_for_addr = HashMap::new();
149-
for (cur_addr, ins) in InsIter::new(code, address as u32) {
150-
let simplified = ins.simplified();
151-
let reloc = relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
152-
153-
if let Some(reloc) = reloc {
154-
// This instruction has a real relocation, so it may be a pool load we want to keep
155-
// track of.
156-
let args = &simplified.args;
157-
match (ins.op, args[0], args[1], args[2]) {
158-
(
159-
Opcode::Addi,
160-
Argument::GPR(addr_dst_gpr),
161-
Argument::GPR(_addr_src_gpr),
162-
Argument::Simm(_simm),
163-
) => {
164-
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone()); // `lis` + `addi`
165-
}
166-
(
167-
Opcode::Ori,
168-
Argument::GPR(addr_dst_gpr),
169-
Argument::GPR(_addr_src_gpr),
170-
Argument::Uimm(_uimm),
171-
) => {
172-
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone()); // `lis` + `ori`
173-
}
174-
_ => {}
175-
}
176-
} else if let Some((offset, addr_src_gpr, addr_dst_gpr)) =
177-
get_offset_and_addr_gpr_for_possible_pool_reference(ins.op, &simplified)
178-
{
179-
// This instruction doesn't have a real relocation, so it may be a reference to one of
180-
// the already-loaded pools.
181-
if let Some(pool_reloc) = active_pool_relocs.get(&addr_src_gpr.0) {
182-
if let Some(fake_pool_reloc) =
183-
make_fake_pool_reloc(offset, cur_addr, pool_reloc, sections)
184-
{
185-
pool_reloc_for_addr.insert(cur_addr, fake_pool_reloc);
186-
}
187-
if let Some(addr_dst_gpr) = addr_dst_gpr {
188-
// If the address of the pool relocation got copied into another register, we
189-
// need to keep track of it in that register too as future instructions may
190-
// reference the symbol indirectly via this new register, instead of the
191-
// register the symbol's address was originally loaded into.
192-
// For example, the start of the function might `lis` + `addi` the start of the
193-
// ...data pool into r25, and then later the start of a loop will `addi` r25
194-
// with the offset within the .data section of an array variable into r21.
195-
// Then the body of the loop will `lwzx` one of the array elements from r21.
196-
let mut new_reloc = pool_reloc.clone();
197-
new_reloc.addend += offset as i64;
198-
active_pool_relocs.insert(addr_dst_gpr.0, new_reloc);
199-
}
200-
}
201-
}
202-
}
203-
204-
pool_reloc_for_addr
205-
}
206-
20733
pub struct ObjArchPpc {
20834
/// Exception info
20935
pub extab: Option<BTreeMap<usize, ExceptionInfo>>,
@@ -552,3 +378,177 @@ fn make_symbol_ref(symbol: &Symbol) -> Result<ExtabSymbolRef> {
552378
let demangled_name = cwdemangle::demangle(&name, &cwdemangle::DemangleOptions::default());
553379
Ok(ExtabSymbolRef { original_index: symbol.index().0, name, demangled_name })
554380
}
381+
382+
fn guess_data_type_from_load_store_inst_op(inst_op: Opcode) -> Option<DataType> {
383+
match inst_op {
384+
Opcode::Lbz | Opcode::Lbzu | Opcode::Lbzux | Opcode::Lbzx => Some(DataType::Int8),
385+
Opcode::Lhz | Opcode::Lhzu | Opcode::Lhzux | Opcode::Lhzx => Some(DataType::Int16),
386+
Opcode::Lha | Opcode::Lhau | Opcode::Lhaux | Opcode::Lhax => Some(DataType::Int16),
387+
Opcode::Lwz | Opcode::Lwzu | Opcode::Lwzux | Opcode::Lwzx => Some(DataType::Int32),
388+
Opcode::Lfs | Opcode::Lfsu | Opcode::Lfsux | Opcode::Lfsx => Some(DataType::Float),
389+
Opcode::Lfd | Opcode::Lfdu | Opcode::Lfdux | Opcode::Lfdx => Some(DataType::Double),
390+
391+
Opcode::Stb | Opcode::Stbu | Opcode::Stbux | Opcode::Stbx => Some(DataType::Int8),
392+
Opcode::Sth | Opcode::Sthu | Opcode::Sthux | Opcode::Sthx => Some(DataType::Int16),
393+
Opcode::Stw | Opcode::Stwu | Opcode::Stwux | Opcode::Stwx => Some(DataType::Int32),
394+
Opcode::Stfs | Opcode::Stfsu | Opcode::Stfsux | Opcode::Stfsx => Some(DataType::Float),
395+
Opcode::Stfd | Opcode::Stfdu | Opcode::Stfdux | Opcode::Stfdx => Some(DataType::Double),
396+
_ => None,
397+
}
398+
}
399+
400+
// Given an instruction, determine if it could accessing data at the address in a register.
401+
// If so, return the offset added to the register's address, the register containing that address,
402+
// and (optionally) which destination register the address is being copied into.
403+
fn get_offset_and_addr_gpr_for_possible_pool_reference(
404+
opcode: Opcode,
405+
simplified: &ParsedIns,
406+
) -> Option<(i16, GPR, Option<GPR>)> {
407+
let args = &simplified.args;
408+
if guess_data_type_from_load_store_inst_op(opcode).is_some() {
409+
match (args[1], args[2]) {
410+
(Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => {
411+
// e.g. lwz. Immediate offset.
412+
Some((offset.0, addr_src_gpr, None))
413+
}
414+
(Argument::GPR(addr_src_gpr), Argument::GPR(_offset_gpr)) => {
415+
// e.g. lwzx. The offset is in a register and was likely calculated from an index.
416+
// Treat the offset as being 0 in this case to show the first element of the array.
417+
// It may be possible to show all elements by figuring out the stride of the array
418+
// from the calculations performed on the index before it's put into offset_gpr, but
419+
// this would be much more complicated, so it's not currently done.
420+
Some((0, addr_src_gpr, None))
421+
}
422+
_ => None,
423+
}
424+
} else {
425+
// If it's not a load/store instruction, there's two more possibilities we need to handle.
426+
// 1. It could be a reference to @stringBase.
427+
// 2. It could be moving the relocation address plus an offset into a different register to
428+
// load from later.
429+
// If either of these match, we also want to return the destination register that the
430+
// address is being copied into so that we can detect any future references to that new
431+
// register as well.
432+
match (opcode, args[0], args[1], args[2]) {
433+
(
434+
Opcode::Addi,
435+
Argument::GPR(addr_dst_gpr),
436+
Argument::GPR(addr_src_gpr),
437+
Argument::Simm(simm),
438+
) => Some((simm.0, addr_src_gpr, Some(addr_dst_gpr))),
439+
(
440+
Opcode::Or,
441+
Argument::GPR(addr_dst_gpr),
442+
Argument::GPR(addr_src_gpr),
443+
Argument::None,
444+
) => Some((0, addr_src_gpr, Some(addr_dst_gpr))), // `mr` or `mr.`
445+
_ => None,
446+
}
447+
}
448+
}
449+
450+
// We create a fake relocation for an instruction, vaguely simulating what the actual relocation
451+
// might have looked like if it wasn't pooled. This is so minimal changes are needed to display
452+
// pooled accesses vs non-pooled accesses. We set the relocation type to R_PPC_NONE to indicate that
453+
// there isn't really a relocation here, as copying the pool relocation's type wouldn't make sense.
454+
// Also, if this instruction is accessing the middle of a symbol instead of the start, we add an
455+
// addend to indicate that.
456+
fn make_fake_pool_reloc(
457+
offset: i16,
458+
cur_addr: u32,
459+
pool_reloc: &ObjReloc,
460+
sections: &[ObjSection],
461+
) -> Option<ObjReloc> {
462+
let offset_from_pool = pool_reloc.addend + offset as i64;
463+
let target_address = pool_reloc.target.address.checked_add_signed(offset_from_pool)?;
464+
let orig_section_index = pool_reloc.target.orig_section_index?;
465+
let section = sections.iter().find(|s| s.orig_index == orig_section_index)?;
466+
let target_symbol = section
467+
.symbols
468+
.iter()
469+
.find(|s| s.size > 0 && (s.address..s.address + s.size).contains(&target_address))?;
470+
let addend = (target_address - target_symbol.address) as i64;
471+
Some(ObjReloc {
472+
flags: RelocationFlags::Elf { r_type: elf::R_PPC_NONE },
473+
address: cur_addr as u64,
474+
target: target_symbol.clone(),
475+
addend,
476+
})
477+
}
478+
479+
// Searches through all instructions in a function, determining which registers have the addresses
480+
// of pooled data relocations in them, finding which instructions load data from those addresses,
481+
// and constructing a mapping of the address of that instruction to a "fake pool relocation" that
482+
// simulates what that instruction's relocation would look like if data hadn't been pooled.
483+
// Limitations: This method currently only goes through the instructions in a function in linear
484+
// order, from start to finish. It does *not* follow any branches. This means that it could have
485+
// false positives or false negatives in determining which relocation is currently loaded in which
486+
// register at any given point in the function, as control flow is not respected.
487+
// There are currently no known examples of this method producing inaccurate results in reality, but
488+
// if examples are found, it may be possible to update this method to also follow all branches so
489+
// that it produces more accurate results.
490+
fn generate_fake_pool_reloc_for_addr_mapping(
491+
address: u64,
492+
code: &[u8],
493+
relocations: &[ObjReloc],
494+
sections: &[ObjSection],
495+
) -> HashMap<u32, ObjReloc> {
496+
let mut active_pool_relocs = HashMap::new();
497+
let mut pool_reloc_for_addr = HashMap::new();
498+
for (cur_addr, ins) in InsIter::new(code, address as u32) {
499+
let simplified = ins.simplified();
500+
let reloc = relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
501+
502+
if let Some(reloc) = reloc {
503+
// This instruction has a real relocation, so it may be a pool load we want to keep
504+
// track of.
505+
let args = &simplified.args;
506+
match (ins.op, args[0], args[1], args[2]) {
507+
(
508+
Opcode::Addi,
509+
Argument::GPR(addr_dst_gpr),
510+
Argument::GPR(_addr_src_gpr),
511+
Argument::Simm(_simm),
512+
) => {
513+
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone()); // `lis` + `addi`
514+
}
515+
(
516+
Opcode::Ori,
517+
Argument::GPR(addr_dst_gpr),
518+
Argument::GPR(_addr_src_gpr),
519+
Argument::Uimm(_uimm),
520+
) => {
521+
active_pool_relocs.insert(addr_dst_gpr.0, reloc.clone()); // `lis` + `ori`
522+
}
523+
_ => {}
524+
}
525+
} else if let Some((offset, addr_src_gpr, addr_dst_gpr)) =
526+
get_offset_and_addr_gpr_for_possible_pool_reference(ins.op, &simplified)
527+
{
528+
// This instruction doesn't have a real relocation, so it may be a reference to one of
529+
// the already-loaded pools.
530+
if let Some(pool_reloc) = active_pool_relocs.get(&addr_src_gpr.0) {
531+
if let Some(fake_pool_reloc) =
532+
make_fake_pool_reloc(offset, cur_addr, pool_reloc, sections)
533+
{
534+
pool_reloc_for_addr.insert(cur_addr, fake_pool_reloc);
535+
}
536+
if let Some(addr_dst_gpr) = addr_dst_gpr {
537+
// If the address of the pool relocation got copied into another register, we
538+
// need to keep track of it in that register too as future instructions may
539+
// reference the symbol indirectly via this new register, instead of the
540+
// register the symbol's address was originally loaded into.
541+
// For example, the start of the function might `lis` + `addi` the start of the
542+
// ...data pool into r25, and then later the start of a loop will `addi` r25
543+
// with the offset within the .data section of an array variable into r21.
544+
// Then the body of the loop will `lwzx` one of the array elements from r21.
545+
let mut new_reloc = pool_reloc.clone();
546+
new_reloc.addend += offset as i64;
547+
active_pool_relocs.insert(addr_dst_gpr.0, new_reloc);
548+
}
549+
}
550+
}
551+
}
552+
553+
pool_reloc_for_addr
554+
}

0 commit comments

Comments
 (0)