Skip to content

Commit 7a65e07

Browse files
authored
Add support for R_ARM_THM_PC8 and R_ARM_THM_PC11 (#342)
* Add support for `R_ARM_THM_JUMP8` and `R_ARM_THM_JUMP11` * Fix `scan_instructions_internal` when reading 2-bytes instruction
1 parent 3c4092b commit 7a65e07

3 files changed

Lines changed: 51 additions & 2 deletions

File tree

objdiff-core/src/arch/arm.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,9 @@ impl Arch for ArchArm {
224224
}
225225

226226
// Check how many bytes we can/should read
227-
let num_code_bytes = if data.len() >= 4 {
227+
let bytes_until_next_mapping =
228+
next_mapping.map(|m| (m.address - address) as usize).unwrap_or(usize::MAX);
229+
let num_code_bytes = if data.len() >= 4 && bytes_until_next_mapping >= 4 {
228230
if mode == unarm::ParseMode::Data && address & 3 != 0 {
229231
// 32-bit .word value should be aligned on a 4-byte boundary, otherwise use .hword
230232
2
@@ -366,6 +368,22 @@ impl Arch for ArchArm {
366368
(imm22 << 1) << 9 >> 9
367369
}
368370

371+
// Thumb unconditional branch (B, 11-bit offset)
372+
elf::R_ARM_THM_PC11 => {
373+
let data = section_data[address..address + 2].try_into()?;
374+
let insn = self.endianness.read_u16_bytes(data) as i32;
375+
let imm11 = insn & 0x7ff;
376+
(imm11 << 1) << 20 >> 20
377+
}
378+
379+
// Thumb conditional branch (B<cond>, 8-bit offset)
380+
elf::R_ARM_THM_PC9 => {
381+
let data = section_data[address..address + 2].try_into()?;
382+
let insn = self.endianness.read_u16_bytes(data) as i32;
383+
let imm8 = insn & 0xff;
384+
(imm8 << 1) << 23 >> 23
385+
}
386+
369387
// Data
370388
elf::R_ARM_ABS32 => {
371389
let data = section_data[address..address + 4].try_into()?;
@@ -399,6 +417,8 @@ impl Arch for ArchArm {
399417
elf::R_ARM_PC24 => Some("R_ARM_PC24"),
400418
elf::R_ARM_XPC25 => Some("R_ARM_XPC25"),
401419
elf::R_ARM_CALL => Some("R_ARM_CALL"),
420+
elf::R_ARM_THM_PC11 => Some("R_ARM_THM_PC11"),
421+
elf::R_ARM_THM_PC9 => Some("R_ARM_THM_PC9"),
402422
_ => None,
403423
},
404424
_ => None,
@@ -418,6 +438,8 @@ impl Arch for ArchArm {
418438
elf::R_ARM_PC24 => 4,
419439
elf::R_ARM_XPC25 => 4,
420440
elf::R_ARM_CALL => 4,
441+
elf::R_ARM_THM_PC11 => 2,
442+
elf::R_ARM_THM_PC9 => 2,
421443
_ => 1,
422444
},
423445
_ => 1,
@@ -544,7 +566,9 @@ impl unarm::FormatIns for ArgsFormatter<'_> {
544566
| RelocationFlags::Elf(elf::R_ARM_THM_PC22)
545567
| RelocationFlags::Elf(elf::R_ARM_PC24)
546568
| RelocationFlags::Elf(elf::R_ARM_XPC25)
547-
| RelocationFlags::Elf(elf::R_ARM_CALL) => {
569+
| RelocationFlags::Elf(elf::R_ARM_CALL)
570+
| RelocationFlags::Elf(elf::R_ARM_THM_PC11)
571+
| RelocationFlags::Elf(elf::R_ARM_THM_PC9) => {
548572
return self.write(InstructionPart::reloc());
549573
}
550574
_ => {}

objdiff-core/tests/arch_arm.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,31 @@ fn combine_text_sections() {
5757
insta::assert_snapshot!(output);
5858
}
5959

60+
#[test]
61+
#[cfg(feature = "arm")]
62+
fn thumb_short_data_mapping() {
63+
// When a .2byte directive is used in Thumb code, the assembler emits
64+
// $d/$t mapping symbols for a 2-byte data region. The disassembler must
65+
// not read 4 bytes as a .word when the next mapping symbol limits the
66+
// data region to 2 bytes.
67+
let diff_config = diff::DiffObjConfig::default();
68+
let obj = obj::read::parse(
69+
include_object!("data/arm/code_1_vblank.o"),
70+
&diff_config,
71+
diff::DiffSide::Base,
72+
)
73+
.unwrap();
74+
let symbol_idx = obj.symbols.iter().position(|s| s.name == "VBlankDMA_Level1").unwrap();
75+
let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap();
76+
let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config);
77+
// .2byte data followed by Thumb code must not be merged into a 4-byte .word
78+
assert!(
79+
!output.contains(".word"),
80+
"2-byte data regions should not be decoded as 4-byte .word values.\n\
81+
The disassembler must respect mapping symbol boundaries."
82+
);
83+
}
84+
6085
#[test]
6186
#[cfg(feature = "arm")]
6287
fn trim_trailing_hword() {
338 KB
Binary file not shown.

0 commit comments

Comments
 (0)