Skip to content

Commit 90e81fa

Browse files
committed
Improve ARM function size inference
This allows 2-byte padding to be trimmed in ARM functions. Resolves #253
1 parent 7a8efb4 commit 90e81fa

File tree

8 files changed

+98
-19
lines changed

8 files changed

+98
-19
lines changed

objdiff-core/src/arch/arm.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -460,12 +460,16 @@ impl Arch for ArchArm {
460460
section: &Section,
461461
mut next_address: u64,
462462
) -> Result<u64> {
463-
// Trim any trailing 4-byte zeroes from the end (padding)
464-
while next_address >= symbol.address + 4
465-
&& let Some(data) = section.data_range(next_address - 4, 4)
466-
&& data == [0u8; 4]
463+
// TODO: This should probably check the disasm mode and trim accordingly,
464+
// but self.disasm_modes isn't populated until post_init, so it needs a refactor.
465+
466+
// Trim any trailing 2-byte zeroes from the end (padding)
467+
while next_address >= symbol.address + 2
468+
&& let Some(data) = section.data_range(next_address - 2, 2)
469+
&& data == [0u8; 2]
470+
&& section.relocation_at(next_address - 2, 2).is_none()
467471
{
468-
next_address -= 4;
472+
next_address -= 2;
469473
}
470474
Ok(next_address.saturating_sub(symbol.address))
471475
}

objdiff-core/src/arch/mips.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ impl Arch for ArchMips {
355355
while new_address >= symbol.address + 4
356356
&& let Some(data) = section.data_range(new_address - 4, 4)
357357
&& data == [0u8; 4]
358+
&& section.relocation_at(next_address - 4, 4).is_none()
358359
{
359360
new_address -= 4;
360361
}

objdiff-core/src/arch/ppc/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ impl Arch for ArchPpc {
457457
while next_address >= symbol.address + 4
458458
&& let Some(data) = section.data_range(next_address - 4, 4)
459459
&& data == [0u8; 4]
460+
&& section.relocation_at(next_address - 4, 4).is_none()
460461
{
461462
next_address -= 4;
462463
}

objdiff-core/src/obj/mod.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,32 +107,33 @@ impl Section {
107107
// The alignment to use when "Combine data/text sections" is enabled.
108108
pub fn combined_alignment(&self) -> u64 {
109109
const MIN_ALIGNMENT: u64 = 4;
110-
self.align.map(|align| align.get().max(MIN_ALIGNMENT)).unwrap_or(MIN_ALIGNMENT)
110+
self.align.map_or(MIN_ALIGNMENT, |align| align.get().max(MIN_ALIGNMENT))
111111
}
112112

113-
pub fn relocation_at<'obj>(
114-
&'obj self,
115-
obj: &'obj Object,
116-
ins_ref: InstructionRef,
117-
) -> Option<ResolvedRelocation<'obj>> {
118-
match self.relocations.binary_search_by_key(&ins_ref.address, |r| r.address) {
113+
pub fn relocation_at(&self, address: u64, size: u8) -> Option<&Relocation> {
114+
match self.relocations.binary_search_by_key(&address, |r| r.address) {
119115
Ok(mut i) => {
120116
// Find the first relocation at the address
121117
while i
122118
.checked_sub(1)
123119
.and_then(|n| self.relocations.get(n))
124-
.is_some_and(|r| r.address == ins_ref.address)
120+
.is_some_and(|r| r.address == address)
125121
{
126122
i -= 1;
127123
}
128124
self.relocations.get(i)
129125
}
130-
Err(i) => self
131-
.relocations
132-
.get(i)
133-
.filter(|r| r.address < ins_ref.address + ins_ref.size as u64),
126+
Err(i) => self.relocations.get(i).filter(|r| r.address < address + size as u64),
134127
}
135-
.and_then(|relocation| {
128+
}
129+
130+
pub fn resolve_relocation_at<'obj>(
131+
&'obj self,
132+
obj: &'obj Object,
133+
address: u64,
134+
size: u8,
135+
) -> Option<ResolvedRelocation<'obj>> {
136+
self.relocation_at(address, size).and_then(|relocation| {
136137
let symbol = obj.symbols.get(relocation.target_symbol)?;
137138
Some(ResolvedRelocation { relocation, symbol })
138139
})
@@ -316,7 +317,7 @@ impl Object {
316317
let section = self.sections.get(section_index)?;
317318
let offset = ins_ref.address.checked_sub(section.address)?;
318319
let code = section.data.get(offset as usize..offset as usize + ins_ref.size as usize)?;
319-
let relocation = section.relocation_at(self, ins_ref);
320+
let relocation = section.resolve_relocation_at(self, ins_ref.address, ins_ref.size);
320321
Some(ResolvedInstructionRef {
321322
ins_ref,
322323
symbol_index,

objdiff-core/tests/arch_arm.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,20 @@ fn combine_text_sections() {
5656
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
5757
insta::assert_snapshot!(output);
5858
}
59+
60+
#[test]
61+
#[cfg(feature = "arm")]
62+
fn trim_trailing_hword() {
63+
let diff_config = diff::DiffObjConfig::default();
64+
let obj = obj::read::parse(
65+
include_object!("data/arm/issue_253.o"),
66+
&diff_config,
67+
diff::DiffSide::Base,
68+
)
69+
.unwrap();
70+
let symbol_idx = obj.symbols.iter().position(|s| s.name == "sub_8030F20").unwrap();
71+
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
72+
insta::assert_debug_snapshot!(diff.instruction_rows);
73+
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
74+
insta::assert_snapshot!(output);
75+
}
748 Bytes
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
source: objdiff-core/tests/arch_arm.rs
3+
expression: output
4+
---
5+
[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("str", 64), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(36)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
6+
[(Address(2), Dim, 5), (Spacing(4), Normal, 0), (Opcode("str", 64), Normal, 10), (Argument(Opaque("r2")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(40)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
7+
[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bx", 23), Normal, 10), (Argument(Opaque("lr")), Normal, 0), (Eol, Normal, 0)]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
source: objdiff-core/tests/arch_arm.rs
3+
expression: diff.instruction_rows
4+
---
5+
[
6+
InstructionDiffRow {
7+
ins_ref: Some(
8+
InstructionRef {
9+
address: 0,
10+
size: 2,
11+
opcode: 64,
12+
branch_dest: None,
13+
},
14+
),
15+
kind: None,
16+
branch_from: None,
17+
branch_to: None,
18+
arg_diff: [],
19+
},
20+
InstructionDiffRow {
21+
ins_ref: Some(
22+
InstructionRef {
23+
address: 2,
24+
size: 2,
25+
opcode: 64,
26+
branch_dest: None,
27+
},
28+
),
29+
kind: None,
30+
branch_from: None,
31+
branch_to: None,
32+
arg_diff: [],
33+
},
34+
InstructionDiffRow {
35+
ins_ref: Some(
36+
InstructionRef {
37+
address: 4,
38+
size: 2,
39+
opcode: 23,
40+
branch_dest: None,
41+
},
42+
),
43+
kind: None,
44+
branch_from: None,
45+
branch_to: None,
46+
arg_diff: [],
47+
},
48+
]

0 commit comments

Comments
 (0)