Skip to content

Commit e1c51ac

Browse files
authored
ARM: Fix "Combine text sections" confusing code and data (#195)
* ARM: Fix parsing of mapping symbols when "Combine text sections" is enabled * Add test
1 parent 39b1b49 commit e1c51ac

File tree

7 files changed

+102
-18
lines changed

7 files changed

+102
-18
lines changed

objdiff-core/src/arch/arm.rs

+28-14
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig, display::InstructionPart},
1616
obj::{
1717
InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation,
18-
ScannedInstruction, SymbolFlag, SymbolFlagSet, SymbolKind,
18+
ScannedInstruction, Section, SectionKind, Symbol, SymbolFlag, SymbolFlagSet, SymbolKind,
1919
},
2020
};
2121

@@ -32,7 +32,8 @@ impl ArchArm {
3232
let endianness = file.endianness();
3333
match file {
3434
object::File::Elf32(_) => {
35-
let disasm_modes = Self::elf_get_mapping_symbols(file);
35+
// The disasm_modes mapping is populated later in the post_init step so that we have access to merged sections.
36+
let disasm_modes = BTreeMap::new();
3637
let detected_version = Self::elf_detect_arm_version(file)?;
3738
Ok(Self { disasm_modes, detected_version, endianness })
3839
}
@@ -73,18 +74,22 @@ impl ArchArm {
7374
Ok(None)
7475
}
7576

76-
fn elf_get_mapping_symbols(file: &object::File) -> BTreeMap<usize, Vec<DisasmMode>> {
77-
file.sections()
78-
.filter(|s| s.kind() == object::SectionKind::Text)
79-
.map(|s| {
80-
let index = s.index();
81-
let mut mapping_symbols: Vec<_> = file
82-
.symbols()
83-
.filter(|s| s.section_index().map(|i| i == index).unwrap_or(false))
84-
.filter_map(|s| DisasmMode::from_symbol(&s))
77+
fn get_mapping_symbols(
78+
sections: &[Section],
79+
symbols: &[Symbol],
80+
) -> BTreeMap<usize, Vec<DisasmMode>> {
81+
sections
82+
.iter()
83+
.enumerate()
84+
.filter(|(_, section)| section.kind == SectionKind::Code)
85+
.map(|(index, _)| {
86+
let mut mapping_symbols: Vec<_> = symbols
87+
.iter()
88+
.filter(|s| s.section.map(|i| i == index).unwrap_or(false))
89+
.filter_map(DisasmMode::from_symbol)
8590
.collect();
8691
mapping_symbols.sort_unstable_by_key(|x| x.address);
87-
(s.index().0 - 1, mapping_symbols)
92+
(index, mapping_symbols)
8893
})
8994
.collect()
9095
}
@@ -178,6 +183,10 @@ impl ArchArm {
178183
}
179184

180185
impl Arch for ArchArm {
186+
fn post_init(&mut self, sections: &[Section], symbols: &[Symbol]) {
187+
self.disasm_modes = Self::get_mapping_symbols(sections, symbols);
188+
}
189+
181190
fn scan_instructions(
182191
&self,
183192
address: u64,
@@ -441,7 +450,7 @@ impl Arch for ArchArm {
441450

442451
fn extra_symbol_flags(&self, symbol: &object::Symbol) -> SymbolFlagSet {
443452
let mut flags = SymbolFlagSet::default();
444-
if DisasmMode::from_symbol(symbol).is_some() {
453+
if DisasmMode::from_object_symbol(symbol).is_some() {
445454
flags |= SymbolFlag::Hidden;
446455
}
447456
flags
@@ -455,12 +464,17 @@ struct DisasmMode {
455464
}
456465

457466
impl DisasmMode {
458-
fn from_symbol<'a>(sym: &object::Symbol<'a, '_, &'a [u8]>) -> Option<Self> {
467+
fn from_object_symbol<'a>(sym: &object::Symbol<'a, '_, &'a [u8]>) -> Option<Self> {
459468
sym.name()
460469
.ok()
461470
.and_then(unarm::ParseMode::from_mapping_symbol)
462471
.map(|mapping| DisasmMode { address: sym.address() as u32, mapping })
463472
}
473+
474+
fn from_symbol(sym: &Symbol) -> Option<Self> {
475+
unarm::ParseMode::from_mapping_symbol(&sym.name)
476+
.map(|mapping| DisasmMode { address: sym.address as u32, mapping })
477+
}
464478
}
465479

466480
fn push_args(

objdiff-core/src/arch/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
},
1313
obj::{
1414
InstructionArg, Object, ParsedInstruction, Relocation, RelocationFlags,
15-
ResolvedInstructionRef, ScannedInstruction, Symbol, SymbolFlagSet, SymbolKind,
15+
ResolvedInstructionRef, ScannedInstruction, Section, Symbol, SymbolFlagSet, SymbolKind,
1616
},
1717
util::ReallySigned,
1818
};
@@ -183,6 +183,9 @@ impl DataType {
183183
}
184184

185185
pub trait Arch: Send + Sync + Debug {
186+
// Finishes arch-specific initialization that must be done after sections have been combined.
187+
fn post_init(&mut self, _sections: &[Section], _symbols: &[Symbol]) {}
188+
186189
/// Generate a list of instructions references (offset, size, opcode) from the given code.
187190
///
188191
/// The opcode IDs are used to generate the initial diff. Implementations should do as little

objdiff-core/src/obj/read.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ pub fn read(obj_path: &std::path::Path, config: &DiffObjConfig) -> Result<Object
843843

844844
pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
845845
let obj_file = object::File::parse(data)?;
846-
let arch = new_arch(&obj_file)?;
846+
let mut arch = new_arch(&obj_file)?;
847847
let split_meta = parse_split_meta(&obj_file)?;
848848
let (mut sections, section_indices) =
849849
map_sections(arch.as_ref(), &obj_file, split_meta.as_ref())?;
@@ -857,6 +857,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
857857
if config.combine_data_sections || config.combine_text_sections {
858858
combine_sections(&mut sections, &mut symbols, config)?;
859859
}
860+
arch.post_init(&sections, &symbols);
860861
Ok(Object {
861862
arch,
862863
endianness: obj_file.endianness(),

objdiff-core/tests/arch_arm.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod common;
55
#[test]
66
#[cfg(feature = "arm")]
77
fn read_arm() {
8-
let diff_config = diff::DiffObjConfig { mips_register_prefix: true, ..Default::default() };
8+
let diff_config = diff::DiffObjConfig { ..Default::default() };
99
let obj = obj::read::parse(include_object!("data/arm/LinkStateItem.o"), &diff_config).unwrap();
1010
insta::assert_debug_snapshot!(obj);
1111
let symbol_idx =
@@ -19,7 +19,7 @@ fn read_arm() {
1919
#[test]
2020
#[cfg(feature = "arm")]
2121
fn read_thumb() {
22-
let diff_config = diff::DiffObjConfig { mips_register_prefix: true, ..Default::default() };
22+
let diff_config = diff::DiffObjConfig { ..Default::default() };
2323
let obj = obj::read::parse(include_object!("data/arm/thumb.o"), &diff_config).unwrap();
2424
insta::assert_debug_snapshot!(obj);
2525
let symbol_idx = obj
@@ -32,3 +32,15 @@ fn read_thumb() {
3232
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
3333
insta::assert_snapshot!(output);
3434
}
35+
36+
#[test]
37+
#[cfg(feature = "arm")]
38+
fn combine_text_sections() {
39+
let diff_config = diff::DiffObjConfig { combine_text_sections: true, ..Default::default() };
40+
let obj = obj::read::parse(include_object!("data/arm/enemy300.o"), &diff_config).unwrap();
41+
let symbol_idx = obj.symbols.iter().position(|s| s.name == "Enemy300Draw").unwrap();
42+
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
43+
insta::assert_debug_snapshot!(diff.instruction_rows);
44+
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
45+
insta::assert_snapshot!(output);
46+
}
17.8 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
source: objdiff-core/tests/arch_arm.rs
3+
assertion_line: 45
4+
expression: output
5+
---
6+
[(Line(90), Dim, 5), (Address(0), Normal, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32799), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
7+
[(Line(90), Dim, 5), (Address(4), Normal, 5), (Spacing(4), Normal, 0), (Opcode("bx", 32779), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Eol, Normal, 0)]
8+
[(Line(90), Dim, 5), (Address(8), Normal, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65535), Normal, 10), (Symbol(Symbol { name: "esEnemyDraw", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
source: objdiff-core/tests/arch_arm.rs
3+
assertion_line: 43
4+
expression: diff.instruction_rows
5+
---
6+
[
7+
InstructionDiffRow {
8+
ins_ref: Some(
9+
InstructionRef {
10+
address: 76,
11+
size: 4,
12+
opcode: 32799,
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: 80,
24+
size: 4,
25+
opcode: 32779,
26+
},
27+
),
28+
kind: None,
29+
branch_from: None,
30+
branch_to: None,
31+
arg_diff: [],
32+
},
33+
InstructionDiffRow {
34+
ins_ref: Some(
35+
InstructionRef {
36+
address: 84,
37+
size: 4,
38+
opcode: 65535,
39+
},
40+
),
41+
kind: None,
42+
branch_from: None,
43+
branch_to: None,
44+
arg_diff: [],
45+
},
46+
]

0 commit comments

Comments
 (0)