aboutsummaryrefslogtreecommitdiff
path: root/src/armv7/thumb.rs
diff options
context:
space:
mode:
authorBrandon Ros <brandonros1@gmail.com>2026-07-02 23:20:56 -0400
committeriximeow <me@iximeow.net>2026-07-28 02:53:24 +0000
commit82df9f3af144814889afb7e289d04dcc1ffa5dbf (patch)
tree608b1826f4e09a7469cdf464e36b4b63ef0d4d6e /src/armv7/thumb.rs
parent0b4ce1210eb90aa370d286390c8566f2bee133bd (diff)
fix several thumb2 decode bugs
- 32-bit store encodings with the imm12 bit (bit 23) set were decoded as the register-offset form when imm12 < 64, or as strbt/strht/strt when imm12 was 0xExx. bit 23 set always means the imm12 form. - movw/movt packed imm4 at bit 16 instead of bit 12, producing 20-bit immediates (e.g. 0xf0005 instead of 0xf005) - mvn (immediate) was decoded as mov, dropping the bitwise not - ror (immediate) was decoded as asr all cases verified against binutils objdump
Diffstat (limited to 'src/armv7/thumb.rs')
-rw-r--r--src/armv7/thumb.rs22
1 files changed, 12 insertions, 10 deletions
diff --git a/src/armv7/thumb.rs b/src/armv7/thumb.rs
index a2809eb..99ab46b 100644
--- a/src/armv7/thumb.rs
+++ b/src/armv7/thumb.rs
@@ -838,7 +838,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
inst.set_w(false);
let rm = lower2[..4].load::<u8>();
let rd = lower2[8..12].load::<u8>();
- inst.opcode = Opcode::ASR;
+ inst.opcode = Opcode::ROR;
inst.operands = [
Operand::Reg(Reg::from_u8(rd)),
Operand::Reg(Reg::from_u8(rm)),
@@ -1111,7 +1111,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
if rn == 0b1111 {
// `MVN` (`A8-505`)
// v6T2
- inst.opcode = Opcode::MOV;
+ inst.opcode = Opcode::MVN;
inst.operands = [
Operand::Reg(Reg::from_u8(rd)),
Operand::Imm32(imm as u32),
@@ -1292,7 +1292,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
inst.opcode = Opcode::MOV;
inst.operands = [
Operand::Reg(Reg::from_u8(rd)),
- Operand::Imm32(imm as u32 | ((rn as u32) << 16)),
+ Operand::Imm32(imm as u32 | ((rn as u32) << 12)),
Operand::Nothing,
Operand::Nothing,
];
@@ -1330,7 +1330,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
inst.opcode = Opcode::MOVT;
inst.operands = [
Operand::Reg(Reg::from_u8(rd)),
- Operand::Imm32(imm as u32 | ((rn as u32) << 16)),
+ Operand::Imm32(imm as u32 | ((rn as u32) << 12)),
Operand::Nothing,
Operand::Nothing,
];
@@ -2023,7 +2023,9 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
match size_bits {
0b00 => {
// `STRB_`
- if op2 == 0 {
+ // op2 only selects a form when the imm12 bit is clear;
+ // otherwise it's just the high bits of imm12.
+ if !has_imm12 && op2 == 0 {
// `STRB (register)` (`A8-683`)
// encoding T2
// v6T2
@@ -2048,7 +2050,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Operand::Nothing,
Operand::Nothing,
];
- } else if (op2 & 0b111100) == 0b111000 {
+ } else if !has_imm12 && (op2 & 0b111100) == 0b111000 {
// `STRBT` (`A8-685`)
// v6T2
let imm8 = lower & 0b1111_1111;
@@ -2112,7 +2114,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
0b01 => {
// `STRH_`
// v6T2
- if op2 == 0 {
+ if !has_imm12 && op2 == 0 {
// `STRH (register)` (`A8-703`)
let rm = (lower & 0b1111) as u8;
let imm2 = (lower >> 4) & 0b11;
@@ -2135,7 +2137,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Operand::Nothing,
Operand::Nothing,
];
- } else if (op2 & 0b111100) == 0b111000 {
+ } else if !has_imm12 && (op2 & 0b111100) == 0b111000 {
// `STRHT` (`A8-705`)
let imm8 = lower & 0b1111_1111;
let rt = ((lower >> 12) & 0b1111) as u8;
@@ -2197,7 +2199,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
}
0b10 => {
// `STR_`
- if op2 == 0 {
+ if !has_imm12 && op2 == 0 {
// `STR (register)` (`A8-677`)
// v6T2
let rm = (lower & 0b1111) as u8;
@@ -2221,7 +2223,7 @@ pub fn decode_into<T: Reader<<ARMv7 as Arch>::Address, <ARMv7 as Arch>::Word>>(d
Operand::Nothing,
Operand::Nothing,
];
- } else if (op2 & 0b111100) == 0b111000 {
+ } else if !has_imm12 && (op2 & 0b111100) == 0b111000 {
// `STRT` (`A8-707`)
let imm8 = lower & 0b1111_1111;
let rt = ((lower >> 12) & 0b1111) as u8;