diff options
| -rw-r--r-- | CHANGELOG | 8 | ||||
| -rw-r--r-- | src/armv7.rs | 25 | ||||
| -rw-r--r-- | tests/armv7/mod.rs | 13 |
3 files changed, 44 insertions, 2 deletions
@@ -7,8 +7,14 @@ * support non-`*2` forms of coprocessor instructions * collapse `*2` encoding choice for coprocessor instructions into a paramter on the opcode (rather than distinct opcodes) + +several fixes from @Grond66: * ARMv7: added `armv7::InstDecoder::in_thumb_mode` to read back if an ARMv7 - decoder is operating in thumb mode. thank you for the patch, @Grond66! + decoder is operating in thumb mode. +* ARMv7: fix incorrect handling of registers lsr or asr by an immediate 32. + yaxpeax-arm incorrectly reported a shift of 0, but should have reported 32. + +thank you for the patches! ## 0.4.0 diff --git a/src/armv7.rs b/src/armv7.rs index 2ce8122..f911388 100644 --- a/src/armv7.rs +++ b/src/armv7.rs @@ -389,8 +389,31 @@ pub struct RegImmShift { impl RegImmShift { /// the immediate this register is shifted by. pub fn imm(&self) -> u8 { - (self.data >> 7) as u8 & 0b11111 + let raw = (self.data >> 7) as u8 & 0b11111; + // in the ARMv7m reference, + // `Instruction Details` -> + // `Shifts applied to a register` -> + // `Constant shifts`: + // + // > The assembler encodes <shift> into two type bits and five immediate bits, as follows: + // > ... + // > LSR #<n> type = 0b01 + // > If <n> < 32, immediate = <n>. + // > If <n> == 32, immediate = 0. + // > ASR #<n> type = 0b10 + // > If <n> < 32, immediate = <n>. + // > If <n> == 32, immediate = 0. + // + // so we have to fix this up here. + if raw == 0 { + let stype = self.stype(); + if stype == ShiftStyle::LSR || stype == ShiftStyle::ASR { + return 32; + } + } + raw } + /// the way in which this register is shifted. pub fn stype(&self) -> ShiftStyle { ShiftStyle::from((self.data >> 5) as u8 & 0b11) diff --git a/tests/armv7/mod.rs b/tests/armv7/mod.rs index 8f413ca..9a9e718 100644 --- a/tests/armv7/mod.rs +++ b/tests/armv7/mod.rs @@ -696,6 +696,19 @@ fn test_decode_mul() { ); } +#[test] +fn test_register_shift_rotate() { + test_armv6([0xec, 0x02, 0x00, 0x00], "andeq r0, r0, ip, ror 5"); + test_armv6([0xa0, 0x33, 0x0b, 0x00], "andeq r3, fp, r0, lsr 7"); + test_armv6([0xa4, 0x33, 0x0b, 0x00], "andeq r3, fp, r4, lsr 7"); + test_armv6([0xa0, 0x7d, 0x0b, 0x00], "andeq r7, fp, r0, lsr 27"); + + // When an LSR or ASR shift has an encoded immediate of zero, it actually means that the + // applied shift is 32. + test_armv6([0x21, 0x00, 0x20, 0x00], "eoreq r0, r0, r1, lsr 32"); + test_armv6([0x41, 0x00, 0x20, 0x00], "eoreq r0, r0, r1, asr 32"); +} + static INSTRUCTION_BYTES: [u8; 4 * 60] = [ 0x24, 0xc0, 0x9f, 0xe5, 0x00, 0xb0, 0xa0, 0xe3, |
