diff options
| -rw-r--r-- | CHANGELOG | 4 | ||||
| -rw-r--r-- | src/armv7/thumb.rs | 37 | ||||
| -rw-r--r-- | tests/armv7/thumb.rs | 37 |
3 files changed, 55 insertions, 23 deletions
@@ -41,6 +41,10 @@ as well as thumb2 fixes from @brandonros: * 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, +* thumb2: preload hints (PLD, PLI) were over-eagerly decoded + namely, ldrb{t} and ldrh{t} into pc are .. weird .. but just weird. +* thumb2: preload data reported two operands when it has one + (the "first operand" was the Rd=r15 operand which makes them preload in the first place) thank you for the patches! diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs index b8d1192..1f0cdf5 100644 --- a/src/armv7/thumb.rs +++ b/src/armv7/thumb.rs @@ -2419,19 +2419,11 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d } else if op2 & 0b111100 == 0b111000 { // `(immediate, Thumb)` - let opcode = if rt == 0b1111 { - [ - Opcode::PLD, - Opcode::PLD, - Opcode::LDRT, - ][size] - } else { - [ - Opcode::LDRBT, - Opcode::LDRHT, - Opcode::LDRT, - ][size] - }; + let opcode = [ + Opcode::LDRBT, + Opcode::LDRHT, + Opcode::LDRT, + ][size]; let w = lower2[8]; let u = lower2[9]; let p = lower2[10]; @@ -2449,19 +2441,11 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d ]; } else if op2 & 0b100100 == 0b100100 { // `(immediate, Thumb)` - let opcode = if rt == 0b1111 { - [ - Opcode::PLD, - Opcode::PLD, - Opcode::LDR, - ][size] - } else { - [ + let opcode = [ Opcode::LDRB, Opcode::LDRH, Opcode::LDR, - ][size] - }; + ][size]; let w = lower2[8]; let u = lower2[9]; let p = lower2[10]; @@ -2760,6 +2744,13 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d } } } + + // TODO: so, this is gross! the PLD/PLI/PLT handling needs improvement across + // the board. + if inst.opcode == Opcode::PLD { + inst.operands[0] = inst.operands[1]; + inst.operands[1] = Operand::Nothing; + } } else { if !op2[4] { // `Data-processing (register)` (`A6-243`) diff --git a/tests/armv7/thumb.rs b/tests/armv7/thumb.rs index e6e1bfb..9ace8d2 100644 --- a/tests/armv7/thumb.rs +++ b/tests/armv7/thumb.rs @@ -4573,6 +4573,43 @@ fn msr_mrs() { } #[test] +fn prefetch() { + test_display( + &[0xb0, 0xf8, 0x03, 0xfe], + "pld.w [r0, #0xe03]" + ); + // ldrb with upper word bit 7 clear is just ldrb, + // but with it set it would be pld + test_display( + &[0x11, 0xf8, 0x78, 0xff], + "ldrb.w pc, [r1, #0x78]!" + ); + test_display( + &[0x91, 0xf8, 0x78, 0xff], + "pld.w [r1, #0xf78]" + ); + // likewise, ldrh with bits 7, 8 clear Rt=1111 is only prefetch + // for some op2 patterns.. + test_display( + &[0x3b, 0xf8, 0x78, 0xff], + "ldrh.w pc, [fp, #0x78]!" + ); + test_display( + &[0x3b, 0xf8, 0x78, 0xfc], + "pld.w [fp, #-0x78]" + ); + test_display( + &[0x3b, 0xf8, 0x38, 0xf0], + "pld.w [fp, r8, lsl #3]" + ); + // and ldrbt also does not become pld on rt==1111 + test_display( + &[0x10, 0xf8, 0x7c, 0xfe], + "ldrbt.w pc, [r0, #0x7c]" + ); +} + +#[test] fn pkh() { test_display( &[0xc7, 0xea, 0xe8, 0x77], |
