Skip to content

Commit 3892826

Browse files
committed
Merge branch 'main' into fork/sozud/add_superh_data_info
# Conflicts: # objdiff-core/src/obj/mod.rs
2 parents 87f4c5d + f263e49 commit 3892826

22 files changed

+576
-96
lines changed

objdiff-core/src/arch/arm.rs

Lines changed: 56 additions & 14 deletions
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,
@@ -338,6 +347,7 @@ impl Arch for ArchArm {
338347
cb(InstructionPart::reloc())?;
339348
} else {
340349
push_args(
350+
ins,
341351
&parsed_ins,
342352
resolved.relocation,
343353
resolved.ins_ref.address as u32,
@@ -441,7 +451,7 @@ impl Arch for ArchArm {
441451

442452
fn extra_symbol_flags(&self, symbol: &object::Symbol) -> SymbolFlagSet {
443453
let mut flags = SymbolFlagSet::default();
444-
if DisasmMode::from_symbol(symbol).is_some() {
454+
if DisasmMode::from_object_symbol(symbol).is_some() {
445455
flags |= SymbolFlag::Hidden;
446456
}
447457
flags
@@ -455,15 +465,21 @@ struct DisasmMode {
455465
}
456466

457467
impl DisasmMode {
458-
fn from_symbol<'a>(sym: &object::Symbol<'a, '_, &'a [u8]>) -> Option<Self> {
468+
fn from_object_symbol<'a>(sym: &object::Symbol<'a, '_, &'a [u8]>) -> Option<Self> {
459469
sym.name()
460470
.ok()
461471
.and_then(unarm::ParseMode::from_mapping_symbol)
462472
.map(|mapping| DisasmMode { address: sym.address() as u32, mapping })
463473
}
474+
475+
fn from_symbol(sym: &Symbol) -> Option<Self> {
476+
unarm::ParseMode::from_mapping_symbol(&sym.name)
477+
.map(|mapping| DisasmMode { address: sym.address as u32, mapping })
478+
}
464479
}
465480

466481
fn push_args(
482+
ins: unarm::Ins,
467483
parsed_ins: &unarm::ParsedIns,
468484
relocation: Option<ResolvedRelocation>,
469485
cur_addr: u32,
@@ -609,6 +625,14 @@ fn push_args(
609625
arg_cb(InstructionPart::opaque("!"))?;
610626
}
611627
}
628+
629+
let branch_dest = get_pc_relative_load_address(ins, cur_addr);
630+
if let Some(branch_dest) = branch_dest {
631+
arg_cb(InstructionPart::basic(" (->"))?;
632+
arg_cb(InstructionPart::branch_dest(branch_dest))?;
633+
arg_cb(InstructionPart::basic(")"))?;
634+
}
635+
612636
Ok(())
613637
}
614638

@@ -636,3 +660,21 @@ fn find_reloc_arg(
636660
None
637661
}
638662
}
663+
664+
fn get_pc_relative_load_address(ins: unarm::Ins, address: u32) -> Option<u32> {
665+
match ins {
666+
unarm::Ins::Arm(ins)
667+
if ins.op == arm::Opcode::Ldr
668+
&& ins.modifier_addr_ldr_str() == arm::AddrLdrStr::Imm
669+
&& ins.field_rn_deref().reg == args::Register::Pc =>
670+
{
671+
let offset = ins.field_offset_12().value;
672+
Some(address.wrapping_add_signed(offset + 8))
673+
}
674+
unarm::Ins::Thumb(ins) if ins.op == thumb::Opcode::LdrPc => {
675+
let offset = ins.field_rel_immed_8().value;
676+
Some((address & !3).wrapping_add_signed(offset + 4))
677+
}
678+
_ => None,
679+
}
680+
}

objdiff-core/src/arch/mod.rs

Lines changed: 4 additions & 1 deletion
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/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use alloc::{
99
vec,
1010
vec::Vec,
1111
};
12-
use core::{fmt, num::NonZeroU32};
12+
use core::{
13+
fmt,
14+
num::{NonZeroU32, NonZeroU64},
15+
};
1316

1417
use flagset::{FlagSet, flags};
1518

@@ -70,6 +73,7 @@ pub struct Section {
7073
pub kind: SectionKind,
7174
pub data: SectionData,
7275
pub flags: SectionFlagSet,
76+
pub align: Option<NonZeroU64>,
7377
pub relocations: Vec<Relocation>,
7478
/// Line number info (.line or .debug_line section)
7579
pub line_info: BTreeMap<u64, u32>,
@@ -110,6 +114,12 @@ impl Section {
110114
self.data.get(offset as usize..offset as usize + symbol.size as usize)
111115
}
112116

117+
// The alignment to use when "Combine data/text sections" is enabled.
118+
pub fn combined_alignment(&self) -> u64 {
119+
const MIN_ALIGNMENT: u64 = 4;
120+
self.align.map(|align| align.get().max(MIN_ALIGNMENT)).unwrap_or(MIN_ALIGNMENT)
121+
}
122+
113123
pub fn relocation_at<'obj>(
114124
&'obj self,
115125
obj: &'obj Object,
@@ -368,6 +378,7 @@ static DUMMY_SECTION: Section = Section {
368378
kind: SectionKind::Unknown,
369379
data: SectionData(Vec::new()),
370380
flags: SectionFlagSet::empty(),
381+
align: None,
371382
relocations: Vec::new(),
372383
line_info: BTreeMap::new(),
373384
virtual_address: None,

objdiff-core/src/obj/read.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloc::{
44
string::{String, ToString},
55
vec::Vec,
66
};
7-
use core::cmp::Ordering;
7+
use core::{cmp::Ordering, num::NonZeroU64};
88

99
use anyhow::{Context, Result, anyhow, bail, ensure};
1010
use object::{Object as _, ObjectSection as _, ObjectSymbol as _};
@@ -17,7 +17,7 @@ use crate::{
1717
Symbol, SymbolFlag, SymbolKind,
1818
split_meta::{SPLITMETA_SECTION, SplitMeta},
1919
},
20-
util::{read_u16, read_u32},
20+
util::{align_data_slice_to, align_u64_to, read_u16, read_u32},
2121
};
2222

2323
fn map_section_kind(section: &object::Section) -> SectionKind {
@@ -257,6 +257,7 @@ fn map_sections(
257257
kind,
258258
data: SectionData(data),
259259
flags: Default::default(),
260+
align: NonZeroU64::new(section.align()),
260261
relocations: Default::default(),
261262
virtual_address,
262263
line_info: Default::default(),
@@ -739,7 +740,10 @@ fn do_combine_sections(
739740
}
740741
offsets.push(current_offset);
741742
current_offset += section.size;
743+
let align = section.combined_alignment();
744+
current_offset = align_u64_to(current_offset, align);
742745
data_size += section.data.len();
746+
data_size = align_u64_to(data_size as u64, align) as usize;
743747
num_relocations += section.relocations.len();
744748
}
745749
if data_size > 0 {
@@ -754,6 +758,7 @@ fn do_combine_sections(
754758
let section = &mut sections[i];
755759
section.size = 0;
756760
data.append(&mut section.data.0);
761+
align_data_slice_to(&mut data, section.combined_alignment());
757762
section.relocations.iter_mut().for_each(|r| r.address += offset);
758763
relocations.append(&mut section.relocations);
759764
line_info.append(&mut section.line_info.iter().map(|(&a, &l)| (a + offset, l)).collect());
@@ -843,7 +848,7 @@ pub fn read(obj_path: &std::path::Path, config: &DiffObjConfig) -> Result<Object
843848

844849
pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
845850
let obj_file = object::File::parse(data)?;
846-
let arch = new_arch(&obj_file)?;
851+
let mut arch = new_arch(&obj_file)?;
847852
let split_meta = parse_split_meta(&obj_file)?;
848853
let (mut sections, section_indices) =
849854
map_sections(arch.as_ref(), &obj_file, split_meta.as_ref())?;
@@ -857,6 +862,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
857862
if config.combine_data_sections || config.combine_text_sections {
858863
combine_sections(&mut sections, &mut symbols, config)?;
859864
}
865+
arch.post_init(&sections, &symbols);
860866
Ok(Object {
861867
arch,
862868
endianness: obj_file.endianness(),

objdiff-core/src/obj/snapshots/objdiff_core__obj__read__test__combine_sections.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ expression: "(sections, symbols)"
1414
8,
1515
),
1616
flags: FlagSet(),
17+
align: None,
1718
relocations: [
1819
Relocation {
1920
flags: Elf(
@@ -53,6 +54,7 @@ expression: "(sections, symbols)"
5354
12,
5455
),
5556
flags: FlagSet(Combined),
57+
align: None,
5658
relocations: [
5759
Relocation {
5860
flags: Elf(
@@ -87,6 +89,7 @@ expression: "(sections, symbols)"
8789
0,
8890
),
8991
flags: FlagSet(Hidden),
92+
align: None,
9093
relocations: [],
9194
line_info: {},
9295
virtual_address: None,
@@ -101,6 +104,7 @@ expression: "(sections, symbols)"
101104
0,
102105
),
103106
flags: FlagSet(Hidden),
107+
align: None,
104108
relocations: [],
105109
line_info: {},
106110
virtual_address: None,

objdiff-core/src/obj/split_meta.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ use alloc::{string::String, vec, vec::Vec};
33
use anyhow::{Result, anyhow};
44
use object::{Endian, ObjectSection, elf::SHT_NOTE};
55

6+
#[cfg(feature = "std")]
7+
use crate::util::align_data_to_4;
8+
use crate::util::align_size_to_4;
9+
610
pub const SPLITMETA_SECTION: &str = ".note.split";
711
pub const SHT_SPLITMETA: u32 = SHT_NOTE;
812
pub const ELF_NOTE_SPLIT: &[u8] = b"Split";
@@ -190,17 +194,6 @@ where E: Endian
190194
}
191195
}
192196

193-
fn align_size_to_4(size: usize) -> usize { (size + 3) & !3 }
194-
195-
#[cfg(feature = "std")]
196-
fn align_data_to_4<W: std::io::Write + ?Sized>(writer: &mut W, len: usize) -> std::io::Result<()> {
197-
const ALIGN_BYTES: &[u8] = &[0; 4];
198-
if len % 4 != 0 {
199-
writer.write_all(&ALIGN_BYTES[..4 - len % 4])?;
200-
}
201-
Ok(())
202-
}
203-
204197
// ELF note format:
205198
// Name Size | 4 bytes (integer)
206199
// Desc Size | 4 bytes (integer)

objdiff-core/src/util.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use alloc::format;
1+
use alloc::{format, vec::Vec};
22
use core::fmt;
33

44
use anyhow::{Result, ensure};
@@ -39,3 +39,24 @@ pub fn read_u16(obj_file: &object::File, reader: &mut &[u8]) -> Result<u16> {
3939
*reader = &reader[2..];
4040
Ok(obj_file.endianness().read_u16(value))
4141
}
42+
43+
pub fn align_size_to_4(size: usize) -> usize { (size + 3) & !3 }
44+
45+
#[cfg(feature = "std")]
46+
pub fn align_data_to_4<W: std::io::Write + ?Sized>(
47+
writer: &mut W,
48+
len: usize,
49+
) -> std::io::Result<()> {
50+
const ALIGN_BYTES: &[u8] = &[0; 4];
51+
if len % 4 != 0 {
52+
writer.write_all(&ALIGN_BYTES[..4 - len % 4])?;
53+
}
54+
Ok(())
55+
}
56+
57+
pub fn align_u64_to(len: u64, align: u64) -> u64 { len + ((align - (len % align)) % align) }
58+
59+
pub fn align_data_slice_to(data: &mut Vec<u8>, align: u64) {
60+
const ALIGN_BYTE: u8 = 0;
61+
data.resize(align_u64_to(data.len() as u64, align) as usize, ALIGN_BYTE);
62+
}

objdiff-core/tests/arch_arm.rs

Lines changed: 14 additions & 2 deletions
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.
Lines changed: 8 additions & 0 deletions
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)]

0 commit comments

Comments
 (0)