From bbbb546ee0b73d295be891b1b2e0e5a18cbfd3d1 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Fri, 3 Jul 2026 20:48:35 -0400 Subject: fix thumb2 TBH decode: wrong opcode and register-shift operand the T1 TBH arm set Opcode::TBB instead of Opcode::TBH, and built the index operand with bit 4 set in the RegShift raw value. bit 4 is the RegReg selector in RegShift::into_shift, so the mandatory 'lsl #1' index scaling decoded as a register shift 'lsl r0' instead. clear bit 4 so it reads back as the RegImm 'lsl #1' the encoding specifies. verified against binutils objdump: df e8 13 f0 is tbh [pc, r3, lsl #1]. --- CHANGELOG | 1 + src/armv7/thumb.rs | 7 +++---- tests/armv7/thumb.rs | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5de5ee7..c2cc889 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -30,6 +30,7 @@ as well as thumb2 fixes from @brandonros: * mvn (immediate) was decoded as mov, * sxtab was decoded as sxtah, * lsl, lsr, asr, ror were determining opcode from an incorrect bitfield, + * tbh was decoded as an shifted tbb, * thumb2: (un)signed extend-and-rotate loaded an incorrect field for rotate, thank you for the patches! diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs index e9427d1..7aa3a5d 100644 --- a/src/armv7/thumb.rs +++ b/src/armv7/thumb.rs @@ -357,15 +357,14 @@ pub fn decode_into::Address, ::Word>>(d // TODO: should_is_must() // rt == 0b1111 // rd == 0b0000 - inst.opcode = Opcode::TBB; + inst.opcode = Opcode::TBH; inst.operands = [ Operand::RegDerefPreindexRegShift( Reg::from_u8(rn), // want `, LSL #1`, construct a raw shift - // ourselves + // ourselves. bit 4 clear selects `RegImm`. RegShift::from_raw( - 0b10000 | // `RegImm` - rd as u16 | // reg == rd + rd as u16 | // reg == rm (0b00 << 5) | // LSL (1 << 7) // shift == #1 ), diff --git a/tests/armv7/thumb.rs b/tests/armv7/thumb.rs index 8c1885d..6384af7 100644 --- a/tests/armv7/thumb.rs +++ b/tests/armv7/thumb.rs @@ -4325,3 +4325,40 @@ fn test_decode_shift_reg_32b_cases() { "ror.w r1, r2, r3" ); } + +#[test] +fn test_decode_tbb_tbh_cases() { + test_display( + &[0xdf, 0xe8, 0x13, 0xf0], + "tbh [pc, r3, lsl 1]" + ); + test_display( + &[0xdf, 0xe8, 0x0b, 0xf0], + "tbb [pc, fp]" + ); +} + +#[test] +fn test_decode_tbh_operand_shape() { + use yaxpeax_arm::armv7::{Opcode, Operand, RegShiftStyle, ShiftStyle}; + + let mut reader = yaxpeax_arch::U8Reader::new(&[0xdf, 0xe8, 0x13, 0xf0][..]); + let inst = InstDecoder::default_thumb().decode(&mut reader).unwrap(); + assert_eq!(inst.opcode, Opcode::TBH); + match inst.operands[0] { + Operand::RegDerefPreindexRegShift(base, shift, add, wback) => { + assert_eq!(base.number(), 15); + assert!(add); + assert!(!wback); + match shift.into_shift() { + RegShiftStyle::RegImm(s) => { + assert_eq!(s.shiftee().number(), 3); + assert_eq!(s.stype(), ShiftStyle::LSL); + assert_eq!(s.imm(), 1); + } + RegShiftStyle::RegReg(_) => panic!("TBH index must be a register+immediate shift"), + } + } + other => panic!("unexpected TBH operand: {:?}", other), + } +} -- cgit v1.1