isa.c (45058B)
1 /* ARM32 (Thumb-2) instruction descriptor table + operand print dispatch. 2 * 3 * Mirrors the rv64_isa.c / aa64_isa.c pattern. Each row records (mnemonic, 4 * match, mask, format, flags); arm32_disasm_find returns the first row whose 5 * masked bits match the word (first-match wins, so aliases use tighter masks 6 * placed before the canonical row), and arm32_print_operands renders the 7 * operand text from the format's field layout. 8 * 9 * Thumb-2 has two widths. A 32-bit instruction is decoded as the single value 10 * (hw1 << 16) | hw2 (hw1 = first half-word in memory); a 16-bit instruction is 11 * decoded in the low 16 bits. The descriptor's ARM_FMT_W16 flag tags 16-bit 12 * rows, which arm32_disasm_find matches against the low-16-bit word; 32-bit 13 * rows match the full word. The caller (disasm.c) determines the width from the 14 * Thumb-2 rule (first half-word bits[15:11] in {11101,11110,11111} => 32-bit) 15 * and presents the appropriate word + is16 flag. */ 16 17 #include "arch/arm32/isa.h" 18 19 #include <string.h> 20 21 #include "core/slice.h" 22 #include "core/strbuf.h" 23 24 /* Mnemonic Slice literal for a static table row (compile-time length). */ 25 #define MN(s) {{(s)}, sizeof(s) - 1} 26 27 /* ---- 32-bit match/mask helpers ---- 28 * A 32-bit Thumb-2 word is (hw1 << 16) | hw2. We pin the bits that select the 29 * instruction (opcode + family selectors) in `match` and clear the operand 30 * fields in `mask`. Helper macros keep the common families readable. */ 31 32 /* Data-processing (modified-immediate, hw1=0xF0xx): op4 in word bits 24:21 33 * (hw1[8:5]), S in word bit 20 (hw1[4]), `i` in word bit 26 (free). Mask pins 34 * op(31:27)=11110 (0xF8000000), op4 (0x01E00000), S (0x00100000), and hw2[15] 35 * (0x8000); it leaves rn(19:16), i(26), imm3(14:12), rd(11:8), imm8(7:0) free. */ 36 #define M32_DPIMM(op4, s) \ 37 ((0xf000u << 16) | (((u32)(op4) & 0xfu) << 21) | (((u32)(s) & 1u) << 20)) 38 #define MK_DPIMM (0xfbf08000u) 39 40 /* Data-processing (shifted register, hw1=0xEAxx): op4 in word bits 24:21, S in 41 * word bit 20. Mask pins op(31:25)=1110101 (0xFE000000), op4 (0x01E00000), S 42 * (0x00100000), hw2[15] (0x8000); clears rn, imm3/imm2/type shift, rd, rm. */ 43 #define M32_DPREG(op4, s) \ 44 ((0xea00u << 16) | (((u32)(op4) & 0xfu) << 21) | (((u32)(s) & 1u) << 20)) 45 #define MK_DPREG (0xfff08000u) 46 47 const Arm32InsnDesc arm32_insn_table[] = { 48 /* ================================================================= 49 * 32-bit data processing — modified immediate (hw1 = 0xF0xx). 50 * MOV/MVN use rn=1111 (own formats so the rn operand is suppressed); 51 * CMP/CMN/TST/TEQ use rd=1111 (S=1, CMP_IMM format). Aliases come 52 * first (tighter mask). 53 * ================================================================= */ 54 {MN("mov.w"), M32_DPIMM(2u, 0u) | (0xfu << 16), MK_DPIMM | (0xfu << 16), 55 ARM_FMT_MOV_IMM, ARM_ASMFL_ALIAS, {0}}, 56 {MN("movs.w"), M32_DPIMM(2u, 1u) | (0xfu << 16), MK_DPIMM | (0xfu << 16), 57 ARM_FMT_MOV_IMM, ARM_ASMFL_ALIAS, {0}}, 58 {MN("mvn.w"), M32_DPIMM(3u, 0u) | (0xfu << 16), MK_DPIMM | (0xfu << 16), 59 ARM_FMT_MOV_IMM, ARM_ASMFL_ALIAS, {0}}, 60 {MN("cmn.w"), M32_DPIMM(8u, 1u) | (0xfu << 8), MK_DPIMM | (0xfu << 8), 61 ARM_FMT_CMP_IMM, ARM_ASMFL_ALIAS, {0}}, 62 {MN("cmp.w"), M32_DPIMM(13u, 1u) | (0xfu << 8), MK_DPIMM | (0xfu << 8), 63 ARM_FMT_CMP_IMM, ARM_ASMFL_ALIAS, {0}}, 64 {MN("tst.w"), M32_DPIMM(0u, 1u) | (0xfu << 8), MK_DPIMM | (0xfu << 8), 65 ARM_FMT_CMP_IMM, ARM_ASMFL_ALIAS, {0}}, 66 {MN("teq.w"), M32_DPIMM(4u, 1u) | (0xfu << 8), MK_DPIMM | (0xfu << 8), 67 ARM_FMT_CMP_IMM, ARM_ASMFL_ALIAS, {0}}, 68 {MN("and.w"), M32_DPIMM(0u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 69 {MN("ands.w"), M32_DPIMM(0u, 1u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 70 {MN("bic.w"), M32_DPIMM(1u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 71 {MN("orr.w"), M32_DPIMM(2u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 72 {MN("orn.w"), M32_DPIMM(3u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 73 {MN("eor.w"), M32_DPIMM(4u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 74 {MN("add.w"), M32_DPIMM(8u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 75 {MN("adds.w"), M32_DPIMM(8u, 1u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 76 {MN("adc.w"), M32_DPIMM(10u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 77 {MN("sbc.w"), M32_DPIMM(11u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 78 {MN("sub.w"), M32_DPIMM(13u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 79 {MN("subs.w"), M32_DPIMM(13u, 1u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 80 {MN("rsb.w"), M32_DPIMM(14u, 0u), MK_DPIMM, ARM_FMT_DP_IMM, 0, {0}}, 81 82 /* ================================================================= 83 * 32-bit data processing — shifted register (hw1 = 0xEAxx). 84 * MOV.W rd, rm = ORR rn=1111; MVN.W = ORN rn=1111 (own formats); 85 * CMP/CMN/TST/TEQ use rd=1111. 86 * ================================================================= */ 87 {MN("mov.w"), M32_DPREG(2u, 0u) | (0xfu << 16), MK_DPREG | (0xfu << 16), 88 ARM_FMT_MOV_REG, ARM_ASMFL_ALIAS, {0}}, 89 {MN("mvn.w"), M32_DPREG(3u, 0u) | (0xfu << 16), MK_DPREG | (0xfu << 16), 90 ARM_FMT_MOV_REG, ARM_ASMFL_ALIAS, {0}}, 91 {MN("cmn.w"), M32_DPREG(8u, 1u) | (0xfu << 8), MK_DPREG | (0xfu << 8), 92 ARM_FMT_CMP_REG, ARM_ASMFL_ALIAS, {0}}, 93 {MN("cmp.w"), M32_DPREG(13u, 1u) | (0xfu << 8), MK_DPREG | (0xfu << 8), 94 ARM_FMT_CMP_REG, ARM_ASMFL_ALIAS, {0}}, 95 {MN("tst.w"), M32_DPREG(0u, 1u) | (0xfu << 8), MK_DPREG | (0xfu << 8), 96 ARM_FMT_CMP_REG, ARM_ASMFL_ALIAS, {0}}, 97 {MN("teq.w"), M32_DPREG(4u, 1u) | (0xfu << 8), MK_DPREG | (0xfu << 8), 98 ARM_FMT_CMP_REG, ARM_ASMFL_ALIAS, {0}}, 99 {MN("and.w"), M32_DPREG(0u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 100 {MN("ands.w"), M32_DPREG(0u, 1u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 101 {MN("bic.w"), M32_DPREG(1u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 102 {MN("orr.w"), M32_DPREG(2u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 103 {MN("orn.w"), M32_DPREG(3u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 104 {MN("eor.w"), M32_DPREG(4u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 105 {MN("add.w"), M32_DPREG(8u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 106 {MN("adds.w"), M32_DPREG(8u, 1u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 107 {MN("adc.w"), M32_DPREG(10u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 108 {MN("sbc.w"), M32_DPREG(11u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 109 {MN("sub.w"), M32_DPREG(13u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 110 {MN("subs.w"), M32_DPREG(13u, 1u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 111 {MN("rsb.w"), M32_DPREG(14u, 0u), MK_DPREG, ARM_FMT_DP_REG, 0, {0}}, 112 113 /* ================================================================= 114 * Shifts (immediate): MOV.W rd, rm, <type> #sh — hw1 = 0xEA4F, type in 115 * hw2[5:4], imm3:imm2 the shift amount. These overlap the MOV_REG row 116 * above (which is shift type=LSL imm=0); the shift-imm rows are tighter 117 * (pin type != 0 or imm != 0) so they sit BEFORE and win. We model all 118 * four as a single shift-imm family keyed on hw2[5:4] in the printer. 119 * ================================================================= */ 120 {MN("lsl.w"), (0xea4fu << 16) | 0x0000u, 0xffef8030u, ARM_FMT_SHIFT_IMM, 0, 121 {0}}, 122 {MN("lsr.w"), (0xea4fu << 16) | 0x0010u, 0xffef8030u, ARM_FMT_SHIFT_IMM, 0, 123 {0}}, 124 {MN("asr.w"), (0xea4fu << 16) | 0x0020u, 0xffef8030u, ARM_FMT_SHIFT_IMM, 0, 125 {0}}, 126 {MN("ror.w"), (0xea4fu << 16) | 0x0030u, 0xffef8030u, ARM_FMT_SHIFT_IMM, 0, 127 {0}}, 128 129 /* Shifts (register): LSL/LSR/ASR/ROR rd, rn, rm — hw1 = 0xFA0x, type in 130 * hw1[6:5] (LSL=0xFA00, LSR=0xFA20, ASR=0xFA40, ROR=0xFA60), hw2=0xF0x0. */ 131 {MN("lsl.w"), (0xfa00u << 16) | 0xf000u, 0xffe0f0f0u, ARM_FMT_SHIFT_REG, 0, 132 {0}}, 133 {MN("lsr.w"), (0xfa20u << 16) | 0xf000u, 0xffe0f0f0u, ARM_FMT_SHIFT_REG, 0, 134 {0}}, 135 {MN("asr.w"), (0xfa40u << 16) | 0xf000u, 0xffe0f0f0u, ARM_FMT_SHIFT_REG, 0, 136 {0}}, 137 {MN("ror.w"), (0xfa60u << 16) | 0xf000u, 0xffe0f0f0u, ARM_FMT_SHIFT_REG, 0, 138 {0}}, 139 140 /* ================================================================= 141 * MOVW / MOVT (16-bit immediate); ADDW / SUBW (12-bit immediate). 142 * ================================================================= */ 143 {MN("movw"), (0xf2400000u), 0xfbf08000u, ARM_FMT_MOVW, 0, {0}}, 144 {MN("movt"), (0xf2c00000u), 0xfbf08000u, ARM_FMT_MOVW, 0, {0}}, 145 {MN("addw"), (0xf2000000u), 0xfbf08000u, ARM_FMT_ADDW, 0, {0}}, 146 {MN("subw"), (0xf2a00000u), 0xfbf08000u, ARM_FMT_ADDW, 0, {0}}, 147 148 /* ================================================================= 149 * Multiply / divide. 150 * ================================================================= */ 151 /* MUL is MLA with ra=1111; pin ra=1111 + place before MLA. */ 152 {MN("mul"), (0xfb000000u) | (0xfu << 12), 0xfff0f0f0u, ARM_FMT_MUL, 0, {0}}, 153 {MN("mla"), (0xfb000000u), 0xfff000f0u, ARM_FMT_MLA, 0, {0}}, 154 {MN("mls"), (0xfb000010u), 0xfff000f0u, ARM_FMT_MLA, 0, {0}}, 155 {MN("umull"), (0xfba00000u), 0xfff000f0u, ARM_FMT_MULL, 0, {0}}, 156 {MN("smull"), (0xfb800000u), 0xfff000f0u, ARM_FMT_MULL, 0, {0}}, 157 {MN("sdiv"), (0xfb90f0f0u), 0xfff0f0f0u, ARM_FMT_DIV, 0, {0}}, 158 {MN("udiv"), (0xfbb0f0f0u), 0xfff0f0f0u, ARM_FMT_DIV, 0, {0}}, 159 160 /* ================================================================= 161 * Sign/zero extends (hw1 = 0xFAxF, rn=1111, hw2 = 0xF080). 162 * ================================================================= */ 163 {MN("sxth"), (0xfa0ff080u), 0xfffff0c0u, ARM_FMT_EXT, 0, {0}}, 164 {MN("uxth"), (0xfa1ff080u), 0xfffff0c0u, ARM_FMT_EXT, 0, {0}}, 165 {MN("sxtb"), (0xfa4ff080u), 0xfffff0c0u, ARM_FMT_EXT, 0, {0}}, 166 {MN("uxtb"), (0xfa5ff080u), 0xfffff0c0u, ARM_FMT_EXT, 0, {0}}, 167 168 /* ================================================================= 169 * REV / REV16 / REVSH / RBIT / CLZ. 170 * ================================================================= */ 171 {MN("rev"), (0xfa90f080u), 0xfff0f0f0u, ARM_FMT_REV, 0, {0}}, 172 {MN("rev16"), (0xfa90f090u), 0xfff0f0f0u, ARM_FMT_REV, 0, {0}}, 173 {MN("rbit"), (0xfa90f0a0u), 0xfff0f0f0u, ARM_FMT_REV, 0, {0}}, 174 {MN("revsh"), (0xfa90f0b0u), 0xfff0f0f0u, ARM_FMT_REV, 0, {0}}, 175 {MN("clz"), (0xfab0f080u), 0xfff0f0f0u, ARM_FMT_REV, 0, {0}}, 176 177 /* ================================================================= 178 * Bitfield: BFC (rn=1111) before BFI; SBFX/UBFX. 179 * ================================================================= */ 180 {MN("bfc"), (0xf36f0000u), 0xffff8020u, ARM_FMT_BFC, ARM_ASMFL_ALIAS, {0}}, 181 {MN("bfi"), (0xf3600000u), 0xfff08020u, ARM_FMT_BFI, 0, {0}}, 182 {MN("sbfx"), (0xf3400000u), 0xfff08020u, ARM_FMT_BFX, 0, {0}}, 183 {MN("ubfx"), (0xf3c00000u), 0xfff08020u, ARM_FMT_BFX, 0, {0}}, 184 185 /* ================================================================= 186 * ARMv7E-M DSP saturating. SSAT/USAT share the 0xF3xx plain-binary-imm 187 * group with the bitfield/movw rows above; the mask pins the LSL/no-shift 188 * forms (word[21]=0, since the ASR and SSAT16/USAT16 forms have word[21]=1) 189 * plus hw2[15]=0 and hw2[5:4]=00, so SSAT16/USAT16/SBFX/UBFX/BFI/MOVW never 190 * collide. The ASR-shifted SSAT/USAT (word[21]=1) is intentionally not 191 * decoded — it falls through to .inst rather than risk misdecoding the 192 * encoding-overlapping SSAT16. QADD/QSUB/QDADD/QDSUB pin hw1[15:4]=0xFA8, 193 * hw2[15:12]=1111, hw2[7:4]=op (collision-free vs CLZ 0xFAB0 / REV/RBIT 194 * 0xFA9x). Verified by round-tripping each match word through llvm-mc 195 * (`--triple=thumbv7em-none-eabi --mattr=+dsp -disassemble`). 196 * ================================================================= */ 197 {MN("ssat"), (0xf3000000u), 0xffe08030u, ARM_FMT_SAT, 0, {0}}, 198 {MN("usat"), (0xf3800000u), 0xffe08030u, ARM_FMT_SAT, 0, {0}}, 199 {MN("qadd"), (0xfa80f080u), 0xfff0f0f0u, ARM_FMT_QADD, 0, {0}}, 200 {MN("qdadd"), (0xfa80f090u), 0xfff0f0f0u, ARM_FMT_QADD, 0, {0}}, 201 {MN("qsub"), (0xfa80f0a0u), 0xfff0f0f0u, ARM_FMT_QADD, 0, {0}}, 202 {MN("qdsub"), (0xfa80f0b0u), 0xfff0f0f0u, ARM_FMT_QADD, 0, {0}}, 203 204 /* ================================================================= 205 * Loads / stores — T3 (positive imm12). hw1 selects op+width: 206 * LDR 0xF8D0 STR 0xF8C0 LDRB 0xF890 STRB 0xF880 207 * LDRH 0xF8B0 STRH 0xF8A0 LDRSB 0xF990 LDRSH 0xF9B0. 208 * ================================================================= */ 209 {MN("strb.w"), (0xf8800000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 210 {MN("ldrb.w"), (0xf8900000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 211 {MN("strh.w"), (0xf8a00000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 212 {MN("ldrh.w"), (0xf8b00000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 213 {MN("str.w"), (0xf8c00000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 214 {MN("ldr.w"), (0xf8d00000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 215 {MN("ldrsb.w"), (0xf9900000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 216 {MN("ldrsh.w"), (0xf9b00000u), 0xfff00000u, ARM_FMT_LDST_T3, 0, {0}}, 217 218 /* Loads / stores — T4 (±imm8, offset addressing P=1,U=add,W=0 => hw2[11:8] 219 * = 0b1100|U). hw1 bases: LDR 0xF850 STR 0xF840 LDRB 0xF810 STRB 0xF800 220 * LDRH 0xF830 STRH 0xF820 LDRSB 0xF910 LDRSH 0xF930. Pin hw2[11]=1, 221 * hw2[10]=1 (P=1,W=0), hw2[8]=0; U (hw2[9]) free. */ 222 {MN("strb.w"), (0xf8000c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 223 {MN("ldrb.w"), (0xf8100c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 224 {MN("strh.w"), (0xf8200c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 225 {MN("ldrh.w"), (0xf8300c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 226 {MN("str.w"), (0xf8400c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 227 {MN("ldr.w"), (0xf8500c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 228 {MN("ldrsb.w"), (0xf9100c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 229 {MN("ldrsh.w"), (0xf9300c00u), 0xfff00d00u, ARM_FMT_LDST_T4, 0, {0}}, 230 231 /* ================================================================= 232 * Exclusive load/store; barriers; table branch. 233 * ================================================================= */ 234 {MN("ldrex"), (0xe8500f00u), 0xfff00f00u, ARM_FMT_LDREX, 0, {0}}, 235 {MN("strex"), (0xe8400000u), 0xfff00000u, ARM_FMT_STREX, 0, {0}}, 236 {MN("dsb"), (0xf3bf8f40u), 0xfffffff0u, ARM_FMT_BARRIER, 0, {0}}, 237 {MN("dmb"), (0xf3bf8f50u), 0xfffffff0u, ARM_FMT_BARRIER, 0, {0}}, 238 {MN("isb"), (0xf3bf8f60u), 0xfffffff0u, ARM_FMT_BARRIER, 0, {0}}, 239 {MN("tbb"), (0xe8d0f000u), 0xfff0fff0u, ARM_FMT_TB, 0, {0}}, 240 {MN("tbh"), (0xe8d0f010u), 0xfff0fff0u, ARM_FMT_TB, 0, {0}}, 241 242 /* ================================================================= 243 * PUSH.W / POP.W (STMDB sp! / LDMIA sp!). 244 * ================================================================= */ 245 {MN("push.w"), (0xe92d0000u), 0xffff0000u, ARM_FMT_PUSHPOP, 0, {0}}, 246 {MN("pop.w"), (0xe8bd0000u), 0xffff0000u, ARM_FMT_PUSHPOP, 0, {0}}, 247 248 /* ================================================================= 249 * 32-bit branches: BL (T1), B.W (T4), B<cond>.W (T3). 250 * BL: hw1=0xF0xx, hw2[15:14]=11, hw2[12]=1. 251 * B.W: hw1=0xF0xx, hw2[15:14]=10, hw2[12]=1. 252 * Bcond.W: hw1=0xF0xx (cond in hw1[9:6]), hw2[15:14]=10, hw2[12]=0. 253 * Order BL and B.W before Bcond.W and pin the hw2[15,12] selectors. 254 * ================================================================= */ 255 {MN("bl"), (0xf000d000u), 0xf800d000u, ARM_FMT_BL, 0, {0}}, 256 {MN("b.w"), (0xf0009000u), 0xf800d000u, ARM_FMT_BRANCH_T4, 0, {0}}, 257 {MN("b.w"), (0xf0008000u), 0xf800d000u, ARM_FMT_BRANCH_T3, 0, {0}}, 258 259 /* ================================================================= 260 * 16-bit instructions (ARM_FMT_W16 — matched against the low 16 bits). 261 * Aliases first. 262 * ================================================================= */ 263 {MN("nop"), 0x0000bf00u, 0x0000ffffu, ARM_FMT_NONE, ARM_FMT_W16, {0}}, 264 {MN("yield"), 0x0000bf10u, 0x0000ffffu, ARM_FMT_NONE, ARM_FMT_W16, {0}}, 265 {MN("wfe"), 0x0000bf20u, 0x0000ffffu, ARM_FMT_NONE, ARM_FMT_W16, {0}}, 266 {MN("wfi"), 0x0000bf30u, 0x0000ffffu, ARM_FMT_NONE, ARM_FMT_W16, {0}}, 267 {MN("sev"), 0x0000bf40u, 0x0000ffffu, ARM_FMT_NONE, ARM_FMT_W16, {0}}, 268 /* IT block: 0xBFxx with mask (low nibble) != 0. NOP (0xBF00) above is the 269 * mask==0 hint; pin mask nonzero is implicit by ordering after the hints. */ 270 {MN("it"), 0x0000bf00u, 0x0000ff00u, ARM_FMT_IT, ARM_FMT_W16, {0}}, 271 {MN("bkpt"), 0x0000be00u, 0x0000ff00u, ARM_FMT_BKPT, ARM_FMT_W16, {0}}, 272 /* UDF #imm8 (T1, 0xDExx): same imm8 shape as BKPT, decoded after the 0xB0xx 273 * hint/branch block so it does not shadow a tighter match. */ 274 {MN("udf"), 0x0000de00u, 0x0000ff00u, ARM_FMT_BKPT, ARM_FMT_W16, {0}}, 275 /* CBZ/CBNZ: 0xB1xx (op=0)/0xB9xx (op=1); mask the i/imm5/rn fields. */ 276 {MN("cbz"), 0x0000b100u, 0x0000fd00u, ARM_FMT_CBZ, ARM_FMT_W16, {0}}, 277 {MN("cbnz"), 0x0000b900u, 0x0000fd00u, ARM_FMT_CBZ, ARM_FMT_W16, {0}}, 278 /* 16-bit sign/zero-extend + byte-reverse (rd[2:0], rm[5:3]). clang prefers 279 * these over the 32-bit forms when rd/rm are low registers. */ 280 {MN("sxth"), 0x0000b200u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 281 {MN("sxtb"), 0x0000b240u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 282 {MN("uxth"), 0x0000b280u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 283 {MN("uxtb"), 0x0000b2c0u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 284 {MN("rev"), 0x0000ba00u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 285 {MN("rev16"), 0x0000ba40u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 286 {MN("revsh"), 0x0000bac0u, 0x0000ffc0u, ARM_FMT_EXT16, ARM_FMT_W16, {0}}, 287 /* BX/BLX (register, T1): 0x4700 (BX) / 0x4780 (BLX). */ 288 {MN("bx"), 0x00004700u, 0x0000ff87u, ARM_FMT_BX, ARM_FMT_W16, {0}}, 289 {MN("blx"), 0x00004780u, 0x0000ff87u, ARM_FMT_BX, ARM_FMT_W16, {0}}, 290 /* Hi-register ADD/CMP/MOV (T1/T2): 0x4400/0x4500/0x4600. MOV is its own 291 * format (handles sp/pc); ADD/CMP use HIREG_16. */ 292 {MN("add"), 0x00004400u, 0x0000ff00u, ARM_FMT_HIREG_16, ARM_FMT_W16, {0}}, 293 {MN("cmp"), 0x00004500u, 0x0000ff00u, ARM_FMT_HIREG_16, ARM_FMT_W16, {0}}, 294 /* MOV (register, high form T1): 0x4600, full r0..r15 incl. sp/pc. */ 295 {MN("mov"), 0x00004600u, 0x0000ff00u, ARM_FMT_MOVHI16, ARM_FMT_W16, {0}}, 296 297 /* 16-bit data-processing register (T1): 0x4000 | (op<<6). rdn[2:0], rm[5:3]. 298 * MUL prints 3 operands (rdm, rn, rdm); the rest print rdn, rm. */ 299 {MN("ands"), 0x00004000u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 300 {MN("eors"), 0x00004040u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 301 {MN("lsls"), 0x00004080u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 302 {MN("lsrs"), 0x000040c0u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 303 {MN("asrs"), 0x00004100u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 304 {MN("adcs"), 0x00004140u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 305 {MN("sbcs"), 0x00004180u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 306 {MN("rors"), 0x000041c0u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 307 {MN("tst"), 0x00004200u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 308 {MN("rsbs"), 0x00004240u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 309 {MN("cmp"), 0x00004280u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 310 {MN("cmn"), 0x000042c0u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 311 {MN("orrs"), 0x00004300u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 312 {MN("muls"), 0x00004340u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 313 {MN("bics"), 0x00004380u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 314 {MN("mvns"), 0x000043c0u, 0x0000ffc0u, ARM_FMT_ALU_16, ARM_FMT_W16, {0}}, 315 316 /* 16-bit ADD/SUB register (T1) + ADD/SUB imm3 (T1). 0x1800/0x1A00 reg, 317 * 0x1C00/0x1E00 imm3. */ 318 {MN("adds"), 0x00001800u, 0x0000fe00u, ARM_FMT_ADDSUBR_16, ARM_FMT_W16, {0}}, 319 {MN("subs"), 0x00001a00u, 0x0000fe00u, ARM_FMT_ADDSUBR_16, ARM_FMT_W16, {0}}, 320 {MN("adds"), 0x00001c00u, 0x0000fe00u, ARM_FMT_ADDSUB3_16, ARM_FMT_W16, {0}}, 321 {MN("subs"), 0x00001e00u, 0x0000fe00u, ARM_FMT_ADDSUB3_16, ARM_FMT_W16, {0}}, 322 323 /* 16-bit shift-immediate (T1): 0x0000(lsls)/0x0800(lsrs)/0x1000(asrs). 324 * These overlap movs (0x0000 lsls #0 == movs); placed after to let the 325 * imm5!=0 forms decode. lsls #0 with imm5=0 is actually `movs` but we keep 326 * lsls for fidelity. */ 327 {MN("lsls"), 0x00000000u, 0x0000f800u, ARM_FMT_SHIFTI_16, ARM_FMT_W16, {0}}, 328 {MN("lsrs"), 0x00000800u, 0x0000f800u, ARM_FMT_SHIFTI_16, ARM_FMT_W16, {0}}, 329 {MN("asrs"), 0x00001000u, 0x0000f800u, ARM_FMT_SHIFTI_16, ARM_FMT_W16, {0}}, 330 331 /* 16-bit MOV/CMP/ADD/SUB immediate-8 (T1/T2): 0x2000/0x2800/0x3000/0x3800. 332 * rd/rn in [10:8], imm8 in [7:0]. */ 333 {MN("movs"), 0x00002000u, 0x0000f800u, ARM_FMT_DPI8_16, ARM_FMT_W16, {0}}, 334 {MN("cmp"), 0x00002800u, 0x0000f800u, ARM_FMT_DPI8_16, ARM_FMT_W16, {0}}, 335 {MN("adds"), 0x00003000u, 0x0000f800u, ARM_FMT_DPI8_16, ARM_FMT_W16, {0}}, 336 {MN("subs"), 0x00003800u, 0x0000f800u, ARM_FMT_DPI8_16, ARM_FMT_W16, {0}}, 337 338 /* 16-bit LDR/STR{,B,H} immediate (T1): rt[2:0], rn[5:3], imm5[10:6] scaled 339 * by 4/1/2 by width. 0x6000 str / 0x6800 ldr / 0x7000 strb / 0x7800 ldrb / 340 * 0x8000 strh / 0x8800 ldrh. */ 341 {MN("str"), 0x00006000u, 0x0000f800u, ARM_FMT_LDSTI5_16, ARM_FMT_W16, {0}}, 342 {MN("ldr"), 0x00006800u, 0x0000f800u, ARM_FMT_LDSTI5_16, ARM_FMT_W16, {0}}, 343 {MN("strb"), 0x00007000u, 0x0000f800u, ARM_FMT_LDSTI5_16, ARM_FMT_W16, {0}}, 344 {MN("ldrb"), 0x00007800u, 0x0000f800u, ARM_FMT_LDSTI5_16, ARM_FMT_W16, {0}}, 345 {MN("strh"), 0x00008000u, 0x0000f800u, ARM_FMT_LDSTI5_16, ARM_FMT_W16, {0}}, 346 {MN("ldrh"), 0x00008800u, 0x0000f800u, ARM_FMT_LDSTI5_16, ARM_FMT_W16, {0}}, 347 348 /* 16-bit LDR/STR sp-relative (T2): rt[10:8], imm8*4. 0x9000 str / 0x9800 349 * ldr. */ 350 {MN("str"), 0x00009000u, 0x0000f800u, ARM_FMT_LDSTSP_16, ARM_FMT_W16, {0}}, 351 {MN("ldr"), 0x00009800u, 0x0000f800u, ARM_FMT_LDSTSP_16, ARM_FMT_W16, {0}}, 352 353 /* 16-bit ADD rd, pc/sp, #imm8*4 (T1): 0xA000 (pc) / 0xA800 (sp). */ 354 {MN("adr"), 0x0000a000u, 0x0000f800u, ARM_FMT_ADDSP_16, ARM_FMT_W16, {0}}, 355 {MN("add"), 0x0000a800u, 0x0000f800u, ARM_FMT_ADDSP_16, ARM_FMT_W16, {0}}, 356 357 /* 16-bit ADD/SUB sp, sp, #imm7*4 (T2): 0xB000 add / 0xB080 sub. */ 358 {MN("add"), 0x0000b000u, 0x0000ff80u, ARM_FMT_ADJSP_16, ARM_FMT_W16, {0}}, 359 {MN("sub"), 0x0000b080u, 0x0000ff80u, ARM_FMT_ADJSP_16, ARM_FMT_W16, {0}}, 360 361 /* 16-bit PUSH/POP (T1): 0xB400 push (M=bit8 -> LR) / 0xBC00 pop (P=bit8 -> 362 * PC). */ 363 {MN("push"), 0x0000b400u, 0x0000fe00u, ARM_FMT_PUSHPOP_16, ARM_FMT_W16, {0}}, 364 {MN("pop"), 0x0000bc00u, 0x0000fe00u, ARM_FMT_PUSHPOP_16, ARM_FMT_W16, {0}}, 365 /* B<cond> (T1, 8-bit): 0xDxyy (cond in [11:8], not 1110/1111). The 0xDE/DF 366 * slots are UDF/SVC; the cond test in the printer guards them. */ 367 {MN("b"), 0x0000d000u, 0x0000f000u, ARM_FMT_BCC16, ARM_FMT_W16, {0}}, 368 /* B (T2, 11-bit unconditional): 0xExxx (top 5 bits 11100). */ 369 {MN("b"), 0x0000e000u, 0x0000f800u, ARM_FMT_B16, ARM_FMT_W16, {0}}, 370 }; 371 372 const u32 arm32_insn_table_n = 373 (u32)(sizeof arm32_insn_table / sizeof arm32_insn_table[0]); 374 375 #undef MN 376 377 const Arm32InsnDesc* arm32_disasm_find(u32 word, int is16) { 378 u32 w = is16 ? (word & 0xffffu) : word; 379 for (u32 i = 0; i < arm32_insn_table_n; ++i) { 380 const Arm32InsnDesc* d = &arm32_insn_table[i]; 381 int row16 = (d->flags & ARM_FMT_W16) != 0; 382 if (row16 != (is16 != 0)) continue; 383 if ((w & d->mask) == d->match) return d; 384 } 385 return NULL; 386 } 387 388 const Arm32InsnDesc* arm32_asm_find(Slice mnemonic) { 389 if (!mnemonic.s) return NULL; 390 /* Prefer the canonical (non-alias) row; fall back to aliases. */ 391 for (u32 i = 0; i < arm32_insn_table_n; ++i) { 392 const Arm32InsnDesc* d = &arm32_insn_table[i]; 393 if (d->flags & ARM_ASMFL_ALIAS) continue; 394 if (slice_eq(d->mnemonic, mnemonic)) return d; 395 } 396 for (u32 i = 0; i < arm32_insn_table_n; ++i) { 397 const Arm32InsnDesc* d = &arm32_insn_table[i]; 398 if (slice_eq(d->mnemonic, mnemonic)) return d; 399 } 400 return NULL; 401 } 402 403 /* ===================================================================== 404 * Condition codes. 405 * ===================================================================== */ 406 static const char* const ARM_CC_NAMES[16] = { 407 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", 408 "hi", "ls", "ge", "lt", "gt", "le", "", "", 409 }; 410 411 const char* arm32_cond_name(u32 cond) { 412 return ARM_CC_NAMES[cond & 0xfu]; 413 } 414 415 int arm32_cond_from_name(Slice s) { 416 for (u32 i = 0; i < 14u; ++i) { 417 if (slice_eq_cstr(s, ARM_CC_NAMES[i])) return (int)i; 418 } 419 if (slice_eq_cstr(s, "al")) return (int)ARM_CC_AL; 420 if (slice_eq_cstr(s, "hs")) return (int)ARM_CC_CS; 421 if (slice_eq_cstr(s, "lo")) return (int)ARM_CC_CC; 422 return -1; 423 } 424 425 /* ===================================================================== 426 * Operand printing. 427 * ===================================================================== */ 428 429 static const char* const ARM_RNAMES[16] = { 430 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 431 "r8", "r9", "r10", "r11", "ip", "sp", "lr", "pc", 432 }; 433 434 static void p_reg(StrBuf* sb, u32 r) { strbuf_puts(sb, ARM_RNAMES[r & 0xfu]); } 435 static void p_sep(StrBuf* sb) { strbuf_puts(sb, ", "); } 436 static void p_imm(StrBuf* sb, i64 v) { 437 strbuf_putc(sb, '#'); 438 strbuf_put_i64(sb, v); 439 } 440 static void p_rel(StrBuf* sb, u64 vaddr, i64 off) { 441 if (vaddr) 442 strbuf_put_hex_u64(sb, vaddr + (u64)off); 443 else { 444 strbuf_putc(sb, '#'); 445 strbuf_put_i64(sb, off); 446 } 447 } 448 449 /* ThumbExpandImm: decode the 12-bit i:imm3:imm8 modified immediate to its 450 * 32-bit value. Inverse of thumb_expand_imm_encode. */ 451 static u32 thumb_expand_imm_decode(u32 imm12) { 452 u32 imm8 = imm12 & 0xffu; 453 u32 ctl = (imm12 >> 8) & 0xfu; /* i:imm3 */ 454 if ((ctl & 0xcu) == 0u) { 455 switch (ctl & 3u) { 456 case 0: 457 return imm8; 458 case 1: 459 return (imm8 << 16) | imm8; 460 case 2: 461 return (imm8 << 24) | (imm8 << 8); 462 default: 463 return (imm8 << 24) | (imm8 << 16) | (imm8 << 8) | imm8; 464 } 465 } 466 { 467 /* Rotated form: imm12[11:7] = rotation (8..31), imm12[6:0] = base[6:0], 468 * base[7] implicitly 1. value = ror(base, rot). */ 469 u32 base = 0x80u | (imm8 & 0x7fu); 470 u32 rot = (imm12 >> 7) & 0x1fu; 471 return (base >> rot) | (base << (32u - rot)); 472 } 473 } 474 475 /* ---- 32-bit field extractors ---- */ 476 static u32 f_hw1(u32 w) { return (w >> 16) & 0xffffu; } 477 static u32 f_hw2(u32 w) { return w & 0xffffu; } 478 static u32 f_rn(u32 w) { return f_hw1(w) & 0xfu; } 479 static u32 f_rd(u32 w) { return (f_hw2(w) >> 8) & 0xfu; } 480 static u32 f_rm(u32 w) { return f_hw2(w) & 0xfu; } 481 /* i:imm3:imm8 modified immediate from a 0xF0xx DP-imm / MOVW form. */ 482 static u32 f_modimm12(u32 w) { 483 u32 i = (f_hw1(w) >> 10) & 1u; 484 u32 imm3 = (f_hw2(w) >> 12) & 7u; 485 u32 imm8 = f_hw2(w) & 0xffu; 486 return (i << 11) | (imm3 << 8) | imm8; 487 } 488 489 /* Shift-type names for the DP-shift / MOV-shift / MVN-shift suffix 490 * (index = hw2[5:4]). */ 491 static const char* const ARM_SHIFT_NAMES[4] = {"lsl", "lsr", "asr", "ror"}; 492 493 static void print_dp_reg(StrBuf* sb, u32 w) { 494 p_reg(sb, f_rd(w)); 495 p_sep(sb); 496 p_reg(sb, f_rn(w)); 497 p_sep(sb); 498 p_reg(sb, f_rm(w)); 499 /* Optional shift on rm (imm3:imm2 in hw2[14:12]/[7:6], type hw2[5:4]). */ 500 { 501 u32 imm3 = (f_hw2(w) >> 12) & 7u, imm2 = (f_hw2(w) >> 6) & 3u; 502 u32 type = (f_hw2(w) >> 4) & 3u; 503 u32 sh = (imm3 << 2) | imm2; 504 if (sh != 0u || type != 0u) { 505 p_sep(sb); 506 strbuf_puts(sb, ARM_SHIFT_NAMES[type]); 507 strbuf_putc(sb, ' '); 508 p_imm(sb, (i64)(sh == 0u && type != 0u ? 32u : sh)); 509 } 510 } 511 } 512 513 static void print_dp_imm(StrBuf* sb, u32 w) { 514 p_reg(sb, f_rd(w)); 515 p_sep(sb); 516 p_reg(sb, f_rn(w)); 517 p_sep(sb); 518 p_imm(sb, (i64)(i32)thumb_expand_imm_decode(f_modimm12(w))); 519 } 520 521 static void print_mov_imm(StrBuf* sb, u32 w) { 522 p_reg(sb, f_rd(w)); 523 p_sep(sb); 524 p_imm(sb, (i64)(i32)thumb_expand_imm_decode(f_modimm12(w))); 525 } 526 527 const char* arm32_mov_shift_alias(u32 word, u32* type_out, u32* amount_out) { 528 /* hw2[14:12] = imm3, hw2[7:6] = imm2, hw2[5:4] = type. */ 529 u32 imm3 = (f_hw2(word) >> 12) & 7u, imm2 = (f_hw2(word) >> 6) & 3u; 530 u32 type = (f_hw2(word) >> 4) & 3u; 531 u32 amount = (imm3 << 2) | imm2; 532 if (type_out) *type_out = type; 533 if (amount_out) *amount_out = amount; 534 if (type == 0u && amount == 0u) return NULL; /* plain mov.w rd, rm. */ 535 switch (type) { 536 case 0u: return "lsl.w"; /* amount != 0 here. */ 537 case 1u: 538 if (amount == 0u) amount = 32u; /* LSR #0 means #32. */ 539 if (amount_out) *amount_out = amount; 540 return "lsr.w"; 541 case 2u: 542 if (amount == 0u) amount = 32u; /* ASR #0 means #32. */ 543 if (amount_out) *amount_out = amount; 544 return "asr.w"; 545 default: /* type == 3 (ROR). */ 546 return (amount == 0u) ? "rrx" : "ror.w"; 547 } 548 } 549 550 /* MOV (ORR) form. op4 == 3 is MVN (ORN), which keeps its own mnemonic and 551 * renders the shift as a `, <sh> #n` suffix; op4 == 2 is MOV, which is aliased 552 * to the shift mnemonic (so here it prints just the operands). */ 553 static void print_mov_reg(StrBuf* sb, u32 w) { 554 u32 op4 = (f_hw1(w) >> 5) & 0xfu; 555 u32 type = 0u, amount = 0u; 556 const char* alias = arm32_mov_shift_alias(w, &type, &amount); 557 p_reg(sb, f_rd(w)); 558 p_sep(sb); 559 p_reg(sb, f_rm(w)); 560 if (op4 == 3u) { 561 /* MVN: append the shift suffix when present (mnemonic stays mvn.w). */ 562 if (alias) { 563 p_sep(sb); 564 strbuf_puts(sb, ARM_SHIFT_NAMES[type]); 565 strbuf_putc(sb, ' '); 566 p_imm(sb, (i64)amount); 567 } 568 return; 569 } 570 /* MOV (op4 == 2): the mnemonic carries the shift; append the amount unless 571 * the alias is a plain mov.w (NULL) or rrx (ROR #0 -> two operands only). */ 572 if (alias && !(type == 3u && amount == 0u)) { 573 p_sep(sb); 574 p_imm(sb, (i64)amount); 575 } 576 } 577 578 static void print_cmp_reg(StrBuf* sb, u32 w) { 579 p_reg(sb, f_rn(w)); 580 p_sep(sb); 581 p_reg(sb, f_rm(w)); 582 } 583 584 static void print_cmp_imm(StrBuf* sb, u32 w) { 585 p_reg(sb, f_rn(w)); 586 p_sep(sb); 587 p_imm(sb, (i64)(i32)thumb_expand_imm_decode(f_modimm12(w))); 588 } 589 590 static void print_movw(StrBuf* sb, u32 w) { 591 /* imm16 = imm4:i:imm3:imm8. imm4 = hw1[3:0]. */ 592 u32 imm4 = f_hw1(w) & 0xfu; 593 u32 i = (f_hw1(w) >> 10) & 1u; 594 u32 imm3 = (f_hw2(w) >> 12) & 7u; 595 u32 imm8 = f_hw2(w) & 0xffu; 596 u32 imm16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; 597 p_reg(sb, f_rd(w)); 598 p_sep(sb); 599 strbuf_putc(sb, '#'); 600 strbuf_put_u64(sb, (u64)imm16); 601 } 602 603 static void print_addw(StrBuf* sb, u32 w) { 604 u32 i = (f_hw1(w) >> 10) & 1u; 605 u32 imm3 = (f_hw2(w) >> 12) & 7u; 606 u32 imm8 = f_hw2(w) & 0xffu; 607 u32 imm12 = (i << 11) | (imm3 << 8) | imm8; 608 p_reg(sb, f_rd(w)); 609 p_sep(sb); 610 p_reg(sb, f_rn(w)); 611 p_sep(sb); 612 p_imm(sb, (i64)imm12); 613 } 614 615 static void print_shift_imm(StrBuf* sb, u32 w) { 616 u32 imm3 = (f_hw2(w) >> 12) & 7u, imm2 = (f_hw2(w) >> 6) & 3u; 617 u32 sh = (imm3 << 2) | imm2; 618 u32 type = (f_hw2(w) >> 4) & 3u; 619 p_reg(sb, f_rd(w)); 620 p_sep(sb); 621 p_reg(sb, f_rm(w)); 622 p_sep(sb); 623 /* LSR/ASR shift of 0 means 32. */ 624 p_imm(sb, (i64)((sh == 0u && (type == 1u || type == 2u)) ? 32u : sh)); 625 } 626 627 static void print_shift_reg(StrBuf* sb, u32 w) { 628 p_reg(sb, f_rd(w)); 629 p_sep(sb); 630 p_reg(sb, f_rn(w)); 631 p_sep(sb); 632 p_reg(sb, f_rm(w)); 633 } 634 635 static void print_mul(StrBuf* sb, u32 w) { 636 p_reg(sb, f_rd(w)); 637 p_sep(sb); 638 p_reg(sb, f_rn(w)); 639 p_sep(sb); 640 p_reg(sb, f_rm(w)); 641 } 642 643 static void print_mla(StrBuf* sb, u32 w) { 644 u32 ra = (f_hw2(w) >> 12) & 0xfu; 645 p_reg(sb, f_rd(w)); 646 p_sep(sb); 647 p_reg(sb, f_rn(w)); 648 p_sep(sb); 649 p_reg(sb, f_rm(w)); 650 p_sep(sb); 651 p_reg(sb, ra); 652 } 653 654 static void print_div(StrBuf* sb, u32 w) { 655 p_reg(sb, f_rd(w)); 656 p_sep(sb); 657 p_reg(sb, f_rn(w)); 658 p_sep(sb); 659 p_reg(sb, f_rm(w)); 660 } 661 662 static void print_mull(StrBuf* sb, u32 w) { 663 u32 rdlo = (f_hw2(w) >> 12) & 0xfu; 664 u32 rdhi = (f_hw2(w) >> 8) & 0xfu; 665 p_reg(sb, rdlo); 666 p_sep(sb); 667 p_reg(sb, rdhi); 668 p_sep(sb); 669 p_reg(sb, f_rn(w)); 670 p_sep(sb); 671 p_reg(sb, f_rm(w)); 672 } 673 674 static void print_ext(StrBuf* sb, u32 w) { 675 p_reg(sb, f_rd(w)); 676 p_sep(sb); 677 p_reg(sb, f_rm(w)); 678 } 679 680 static void print_rev(StrBuf* sb, u32 w) { 681 p_reg(sb, f_rd(w)); 682 p_sep(sb); 683 p_reg(sb, f_rm(w)); 684 } 685 686 static void print_bfx(StrBuf* sb, u32 w) { 687 u32 imm3 = (f_hw2(w) >> 12) & 7u, imm2 = (f_hw2(w) >> 6) & 3u; 688 u32 lsb = (imm3 << 2) | imm2; 689 u32 wm1 = f_hw2(w) & 0x1fu; 690 p_reg(sb, f_rd(w)); 691 p_sep(sb); 692 p_reg(sb, f_rn(w)); 693 p_sep(sb); 694 p_imm(sb, (i64)lsb); 695 p_sep(sb); 696 p_imm(sb, (i64)(wm1 + 1u)); 697 } 698 699 static void print_bfi(StrBuf* sb, u32 w) { 700 u32 imm3 = (f_hw2(w) >> 12) & 7u, imm2 = (f_hw2(w) >> 6) & 3u; 701 u32 lsb = (imm3 << 2) | imm2; 702 u32 msb = f_hw2(w) & 0x1fu; 703 p_reg(sb, f_rd(w)); 704 p_sep(sb); 705 p_reg(sb, f_rn(w)); 706 p_sep(sb); 707 p_imm(sb, (i64)lsb); 708 p_sep(sb); 709 p_imm(sb, (i64)(msb - lsb + 1u)); 710 } 711 712 static void print_bfc(StrBuf* sb, u32 w) { 713 u32 imm3 = (f_hw2(w) >> 12) & 7u, imm2 = (f_hw2(w) >> 6) & 3u; 714 u32 lsb = (imm3 << 2) | imm2; 715 u32 msb = f_hw2(w) & 0x1fu; 716 p_reg(sb, f_rd(w)); 717 p_sep(sb); 718 p_imm(sb, (i64)lsb); 719 p_sep(sb); 720 p_imm(sb, (i64)(msb - lsb + 1u)); 721 } 722 723 /* SSAT/USAT rd, #sat, rm. The U bit (word[23] = hw1[7]) selects USAT, which 724 * encodes the saturation position directly; SSAT encodes sat-1. Rm sits in 725 * hw1[3:0] (f_rn). The (LSL) shift amount lives in imm3:imm2 (hw2[14:12]:[7:6]); 726 * it is appended only when nonzero. */ 727 static void print_sat(StrBuf* sb, u32 w) { 728 u32 is_usat = (f_hw1(w) >> 7) & 1u; 729 u32 sat_imm = f_hw2(w) & 0x1fu; 730 u32 sat = is_usat ? sat_imm : (sat_imm + 1u); 731 u32 imm3 = (f_hw2(w) >> 12) & 7u, imm2 = (f_hw2(w) >> 6) & 3u; 732 u32 sh = (imm3 << 2) | imm2; 733 p_reg(sb, f_rd(w)); 734 p_sep(sb); 735 p_imm(sb, (i64)sat); 736 p_sep(sb); 737 p_reg(sb, f_rn(w)); /* Rm */ 738 if (sh) { 739 strbuf_puts(sb, ", lsl "); 740 p_imm(sb, (i64)sh); 741 } 742 } 743 744 /* QADD/QSUB/QDADD/QDSUB rd, rm, rn. Rd = hw2[11:8], Rm = hw2[3:0], Rn lands in 745 * hw1[3:0] (the ARM operand order is Rd, Rm, Rn). */ 746 static void print_qadd(StrBuf* sb, u32 w) { 747 p_reg(sb, f_rd(w)); 748 p_sep(sb); 749 p_reg(sb, f_rm(w)); 750 p_sep(sb); 751 p_reg(sb, f_rn(w)); 752 } 753 754 static void print_ldst_t3(StrBuf* sb, u32 w) { 755 u32 rt = (f_hw2(w) >> 12) & 0xfu; 756 u32 imm12 = f_hw2(w) & 0xfffu; 757 p_reg(sb, rt); 758 p_sep(sb); 759 strbuf_putc(sb, '['); 760 p_reg(sb, f_rn(w)); 761 if (imm12) { 762 p_sep(sb); 763 p_imm(sb, (i64)imm12); 764 } 765 strbuf_putc(sb, ']'); 766 } 767 768 static void print_ldst_t4(StrBuf* sb, u32 w) { 769 u32 rt = (f_hw2(w) >> 12) & 0xfu; 770 u32 add = (f_hw2(w) >> 9) & 1u; 771 u32 imm8 = f_hw2(w) & 0xffu; 772 p_reg(sb, rt); 773 p_sep(sb); 774 strbuf_putc(sb, '['); 775 p_reg(sb, f_rn(w)); 776 if (imm8) { 777 p_sep(sb); 778 p_imm(sb, add ? (i64)imm8 : -(i64)imm8); 779 } 780 strbuf_putc(sb, ']'); 781 } 782 783 static void print_ldrex(StrBuf* sb, u32 w) { 784 u32 rt = (f_hw2(w) >> 12) & 0xfu; 785 u32 imm8 = f_hw2(w) & 0xffu; 786 p_reg(sb, rt); 787 p_sep(sb); 788 strbuf_putc(sb, '['); 789 p_reg(sb, f_rn(w)); 790 if (imm8) { 791 p_sep(sb); 792 p_imm(sb, (i64)(imm8 * 4u)); 793 } 794 strbuf_putc(sb, ']'); 795 } 796 797 static void print_strex(StrBuf* sb, u32 w) { 798 u32 rd = (f_hw2(w) >> 8) & 0xfu; 799 u32 rt = (f_hw2(w) >> 12) & 0xfu; 800 u32 imm8 = f_hw2(w) & 0xffu; 801 p_reg(sb, rd); 802 p_sep(sb); 803 p_reg(sb, rt); 804 p_sep(sb); 805 strbuf_putc(sb, '['); 806 p_reg(sb, f_rn(w)); 807 if (imm8) { 808 p_sep(sb); 809 p_imm(sb, (i64)(imm8 * 4u)); 810 } 811 strbuf_putc(sb, ']'); 812 } 813 814 static void print_reglist(StrBuf* sb, u32 reglist) { 815 int first = 1; 816 strbuf_putc(sb, '{'); 817 for (u32 r = 0; r < 16u; ++r) { 818 if (reglist & (1u << r)) { 819 if (!first) p_sep(sb); 820 p_reg(sb, r); 821 first = 0; 822 } 823 } 824 strbuf_putc(sb, '}'); 825 } 826 827 static void print_pushpop(StrBuf* sb, u32 w) { 828 print_reglist(sb, f_hw2(w)); 829 } 830 831 static void print_barrier(StrBuf* sb, u32 w) { 832 u32 opt = f_hw2(w) & 0xfu; 833 if (opt == 0xfu) 834 strbuf_puts(sb, "sy"); 835 else 836 strbuf_put_u64(sb, (u64)opt); 837 } 838 839 static void print_tb(StrBuf* sb, u32 w) { 840 strbuf_putc(sb, '['); 841 p_reg(sb, f_rn(w)); 842 p_sep(sb); 843 p_reg(sb, f_rm(w)); 844 if (((f_hw2(w) >> 4) & 1u)) strbuf_puts(sb, ", lsl #1"); 845 strbuf_putc(sb, ']'); 846 } 847 848 /* B.W (T4) 24-bit signed offset: S:I1:I2:imm10:imm11 (imm32 in 2-byte units), 849 * I1=NOT(J1^S), I2=NOT(J2^S). */ 850 static i64 decode_branch_t4(u32 w) { 851 u32 s = (f_hw1(w) >> 10) & 1u; 852 u32 imm10 = f_hw1(w) & 0x3ffu; 853 u32 j1 = (f_hw2(w) >> 13) & 1u; 854 u32 j2 = (f_hw2(w) >> 11) & 1u; 855 u32 imm11 = f_hw2(w) & 0x7ffu; 856 u32 i1 = (~(j1 ^ s)) & 1u; 857 u32 i2 = (~(j2 ^ s)) & 1u; 858 u32 raw = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); 859 i64 off = (i64)raw; 860 if (s) off |= ~(i64)0x1ffffff; /* sign-extend bit 24 (after the <<1) */ 861 return off + 4; /* Thumb PC bias */ 862 } 863 864 /* B<cond>.W (T3) 20-bit signed offset: S:J2:J1:imm6:imm11 (no XOR). */ 865 static i64 decode_branch_t3(u32 w) { 866 u32 s = (f_hw1(w) >> 10) & 1u; 867 u32 imm6 = f_hw1(w) & 0x3fu; 868 u32 j1 = (f_hw2(w) >> 13) & 1u; 869 u32 j2 = (f_hw2(w) >> 11) & 1u; 870 u32 imm11 = f_hw2(w) & 0x7ffu; 871 u32 raw = (s << 20) | (j2 << 19) | (j1 << 18) | (imm6 << 12) | (imm11 << 1); 872 i64 off = (i64)raw; 873 if (s) off |= ~(i64)0x1fffff; /* sign-extend bit 20 */ 874 return off + 4; 875 } 876 877 static u32 branch_t3_cond(u32 w) { return (f_hw1(w) >> 6) & 0xfu; } 878 879 static void print_branch_t4(StrBuf* sb, u32 w, u64 vaddr) { 880 p_rel(sb, vaddr, decode_branch_t4(w)); 881 } 882 883 static void print_bl(StrBuf* sb, u32 w, u64 vaddr) { 884 p_rel(sb, vaddr, decode_branch_t4(w)); 885 } 886 887 /* ---- 16-bit field extractors ---- */ 888 static void print_cbz(StrBuf* sb, u32 w, u64 vaddr) { 889 u32 hw = w & 0xffffu; 890 u32 rn = hw & 7u; 891 u32 i = (hw >> 9) & 1u, imm5 = (hw >> 3) & 0x1fu; 892 i64 off = (i64)((i << 6) | (imm5 << 1)) + 4; /* PC bias */ 893 p_reg(sb, rn); 894 p_sep(sb); 895 p_rel(sb, vaddr, off); 896 } 897 898 static void print_movhi16(StrBuf* sb, u32 w) { 899 u32 hw = w & 0xffffu; 900 u32 rd = ((hw >> 7) & 1u) << 3 | (hw & 7u); 901 u32 rm = (hw >> 3) & 0xfu; 902 p_reg(sb, rd); 903 p_sep(sb); 904 p_reg(sb, rm); 905 } 906 907 static void print_bx(StrBuf* sb, u32 w) { 908 u32 rm = (w >> 3) & 0xfu; 909 p_reg(sb, rm); 910 } 911 912 static void print_bkpt(StrBuf* sb, u32 w) { 913 p_imm(sb, (i64)(w & 0xffu)); 914 } 915 916 static void print_ext16(StrBuf* sb, u32 w) { 917 u32 rd = w & 7u, rm = (w >> 3) & 7u; 918 p_reg(sb, rd); 919 p_sep(sb); 920 p_reg(sb, rm); 921 } 922 923 /* ---- additional 16-bit families ---- */ 924 static void print_dpi8_16(StrBuf* sb, u32 w) { 925 u32 rd = (w >> 8) & 7u, imm8 = w & 0xffu; 926 p_reg(sb, rd); 927 p_sep(sb); 928 p_imm(sb, (i64)imm8); 929 } 930 931 static void print_addsub3_16(StrBuf* sb, u32 w) { 932 u32 rd = w & 7u, rn = (w >> 3) & 7u, imm3 = (w >> 6) & 7u; 933 p_reg(sb, rd); 934 p_sep(sb); 935 p_reg(sb, rn); 936 p_sep(sb); 937 p_imm(sb, (i64)imm3); 938 } 939 940 static void print_addsubr_16(StrBuf* sb, u32 w) { 941 u32 rd = w & 7u, rn = (w >> 3) & 7u, rm = (w >> 6) & 7u; 942 p_reg(sb, rd); 943 p_sep(sb); 944 p_reg(sb, rn); 945 p_sep(sb); 946 p_reg(sb, rm); 947 } 948 949 static void print_shifti_16(StrBuf* sb, u32 w) { 950 u32 rd = w & 7u, rm = (w >> 3) & 7u, imm5 = (w >> 6) & 0x1fu; 951 p_reg(sb, rd); 952 p_sep(sb); 953 p_reg(sb, rm); 954 p_sep(sb); 955 p_imm(sb, (i64)imm5); 956 } 957 958 static void print_alu_16(StrBuf* sb, u32 w, const Arm32InsnDesc* d) { 959 u32 rdn = w & 7u, rm = (w >> 3) & 7u; 960 /* MULS prints `rdm, rn, rdm`; the others print `rdn, rm`. */ 961 if (slice_eq_cstr(d->mnemonic, "muls")) { 962 p_reg(sb, rdn); 963 p_sep(sb); 964 p_reg(sb, rm); 965 p_sep(sb); 966 p_reg(sb, rdn); 967 return; 968 } 969 p_reg(sb, rdn); 970 p_sep(sb); 971 p_reg(sb, rm); 972 } 973 974 static void print_hireg_16(StrBuf* sb, u32 w) { 975 u32 rdn = (w & 7u) | (((w >> 7) & 1u) << 3); 976 u32 rm = (w >> 3) & 0xfu; 977 p_reg(sb, rdn); 978 p_sep(sb); 979 p_reg(sb, rm); 980 } 981 982 static void print_ldsti5_16(StrBuf* sb, u32 w) { 983 u32 rt = w & 7u, rn = (w >> 3) & 7u, imm5 = (w >> 6) & 0x1fu; 984 u32 op = (w >> 11) & 0x1fu; /* 0x0C/0x0D str/ldr(*4); 0x0E/0x0F strb/ldrb(*1); 985 0x10/0x11 strh/ldrh(*2) */ 986 u32 scale = (op <= 0x0du) ? 4u : (op <= 0x0fu) ? 1u : 2u; 987 p_reg(sb, rt); 988 p_sep(sb); 989 strbuf_putc(sb, '['); 990 p_reg(sb, rn); 991 if (imm5) { 992 p_sep(sb); 993 p_imm(sb, (i64)(imm5 * scale)); 994 } 995 strbuf_putc(sb, ']'); 996 } 997 998 static void print_ldstsp_16(StrBuf* sb, u32 w) { 999 u32 rt = (w >> 8) & 7u, imm8 = w & 0xffu; 1000 p_reg(sb, rt); 1001 p_sep(sb); 1002 strbuf_putc(sb, '['); 1003 p_reg(sb, ARM_SP); 1004 if (imm8) { 1005 p_sep(sb); 1006 p_imm(sb, (i64)(imm8 * 4u)); 1007 } 1008 strbuf_putc(sb, ']'); 1009 } 1010 1011 static void print_addsp_16(StrBuf* sb, u32 w) { 1012 u32 rd = (w >> 8) & 7u, imm8 = w & 0xffu; 1013 u32 sp = (w >> 11) & 1u; /* 0 = pc (adr), 1 = sp */ 1014 p_reg(sb, rd); 1015 p_sep(sb); 1016 p_reg(sb, sp ? ARM_SP : ARM_PC); 1017 p_sep(sb); 1018 p_imm(sb, (i64)(imm8 * 4u)); 1019 } 1020 1021 static void print_adjsp_16(StrBuf* sb, u32 w) { 1022 u32 imm7 = w & 0x7fu; 1023 p_reg(sb, ARM_SP); 1024 p_sep(sb); 1025 p_reg(sb, ARM_SP); 1026 p_sep(sb); 1027 p_imm(sb, (i64)(imm7 * 4u)); 1028 } 1029 1030 static void print_pushpop_16(StrBuf* sb, u32 w) { 1031 u32 list = w & 0xffu; 1032 u32 extra = (w >> 8) & 1u; /* push: bit8 -> LR; pop: bit8 -> PC */ 1033 if ((w >> 11) & 1u) 1034 list |= extra ? (1u << 15) : 0u; /* pop -> PC */ 1035 else 1036 list |= extra ? (1u << 14) : 0u; /* push -> LR */ 1037 print_reglist(sb, list); 1038 } 1039 1040 static void print_b16(StrBuf* sb, u32 w, u64 vaddr) { 1041 u32 hw = w & 0xffffu; 1042 u32 imm11 = hw & 0x7ffu; 1043 i64 off = (i64)(imm11 << 1); 1044 if (imm11 & 0x400u) off |= ~(i64)0xfff; /* sign-extend 12-bit */ 1045 off += 4; 1046 p_rel(sb, vaddr, off); 1047 } 1048 1049 static void print_bcc16(StrBuf* sb, u32 w, u64 vaddr) { 1050 u32 hw = w & 0xffffu; 1051 u32 imm8 = hw & 0xffu; 1052 i64 off = (i64)(imm8 << 1); 1053 if (imm8 & 0x80u) off |= ~(i64)0x1ff; /* sign-extend 9-bit */ 1054 off += 4; 1055 p_rel(sb, vaddr, off); 1056 } 1057 1058 void arm32_print_operands(StrBuf* sb, const Arm32InsnDesc* desc, u32 word, 1059 u64 vaddr) { 1060 switch ((Arm32Format)desc->fmt) { 1061 case ARM_FMT_NONE: 1062 break; 1063 case ARM_FMT_DP_REG: 1064 print_dp_reg(sb, word); 1065 break; 1066 case ARM_FMT_DP_IMM: 1067 print_dp_imm(sb, word); 1068 break; 1069 case ARM_FMT_MOV_IMM: 1070 print_mov_imm(sb, word); 1071 break; 1072 case ARM_FMT_CMP_REG: 1073 print_cmp_reg(sb, word); 1074 break; 1075 case ARM_FMT_CMP_IMM: 1076 print_cmp_imm(sb, word); 1077 break; 1078 case ARM_FMT_MOV_REG: 1079 print_mov_reg(sb, word); 1080 break; 1081 case ARM_FMT_MOVW: 1082 print_movw(sb, word); 1083 break; 1084 case ARM_FMT_ADDW: 1085 print_addw(sb, word); 1086 break; 1087 case ARM_FMT_SHIFT_IMM: 1088 print_shift_imm(sb, word); 1089 break; 1090 case ARM_FMT_SHIFT_REG: 1091 print_shift_reg(sb, word); 1092 break; 1093 case ARM_FMT_MUL: 1094 print_mul(sb, word); 1095 break; 1096 case ARM_FMT_MLA: 1097 print_mla(sb, word); 1098 break; 1099 case ARM_FMT_DIV: 1100 print_div(sb, word); 1101 break; 1102 case ARM_FMT_MULL: 1103 print_mull(sb, word); 1104 break; 1105 case ARM_FMT_EXT: 1106 print_ext(sb, word); 1107 break; 1108 case ARM_FMT_REV: 1109 print_rev(sb, word); 1110 break; 1111 case ARM_FMT_BFX: 1112 print_bfx(sb, word); 1113 break; 1114 case ARM_FMT_BFI: 1115 print_bfi(sb, word); 1116 break; 1117 case ARM_FMT_BFC: 1118 print_bfc(sb, word); 1119 break; 1120 case ARM_FMT_SAT: 1121 print_sat(sb, word); 1122 break; 1123 case ARM_FMT_QADD: 1124 print_qadd(sb, word); 1125 break; 1126 case ARM_FMT_LDST_T3: 1127 print_ldst_t3(sb, word); 1128 break; 1129 case ARM_FMT_LDST_T4: 1130 print_ldst_t4(sb, word); 1131 break; 1132 case ARM_FMT_LDREX: 1133 print_ldrex(sb, word); 1134 break; 1135 case ARM_FMT_STREX: 1136 print_strex(sb, word); 1137 break; 1138 case ARM_FMT_PUSHPOP: 1139 print_pushpop(sb, word); 1140 break; 1141 case ARM_FMT_BARRIER: 1142 print_barrier(sb, word); 1143 break; 1144 case ARM_FMT_TB: 1145 print_tb(sb, word); 1146 break; 1147 case ARM_FMT_BRANCH_T4: 1148 print_branch_t4(sb, word, vaddr); 1149 break; 1150 case ARM_FMT_BRANCH_T3: 1151 p_rel(sb, vaddr, decode_branch_t3(word)); 1152 break; 1153 case ARM_FMT_BL: 1154 print_bl(sb, word, vaddr); 1155 break; 1156 case ARM_FMT_B16: 1157 print_b16(sb, word, vaddr); 1158 break; 1159 case ARM_FMT_BCC16: 1160 print_bcc16(sb, word, vaddr); 1161 break; 1162 case ARM_FMT_CBZ: 1163 print_cbz(sb, word, vaddr); 1164 break; 1165 case ARM_FMT_IT: 1166 break; /* mnemonic carries the cc suffix; no operands here */ 1167 case ARM_FMT_MOVHI16: 1168 print_movhi16(sb, word); 1169 break; 1170 case ARM_FMT_BX: 1171 print_bx(sb, word); 1172 break; 1173 case ARM_FMT_BKPT: 1174 print_bkpt(sb, word); 1175 break; 1176 case ARM_FMT_EXT16: 1177 print_ext16(sb, word); 1178 break; 1179 case ARM_FMT_DPI8_16: 1180 print_dpi8_16(sb, word); 1181 break; 1182 case ARM_FMT_ADDSUB3_16: 1183 print_addsub3_16(sb, word); 1184 break; 1185 case ARM_FMT_ADDSUBR_16: 1186 print_addsubr_16(sb, word); 1187 break; 1188 case ARM_FMT_SHIFTI_16: 1189 print_shifti_16(sb, word); 1190 break; 1191 case ARM_FMT_ALU_16: 1192 print_alu_16(sb, word, desc); 1193 break; 1194 case ARM_FMT_HIREG_16: 1195 print_hireg_16(sb, word); 1196 break; 1197 case ARM_FMT_LDSTI5_16: 1198 print_ldsti5_16(sb, word); 1199 break; 1200 case ARM_FMT_LDSTSP_16: 1201 print_ldstsp_16(sb, word); 1202 break; 1203 case ARM_FMT_ADDSP_16: 1204 print_addsp_16(sb, word); 1205 break; 1206 case ARM_FMT_ADJSP_16: 1207 print_adjsp_16(sb, word); 1208 break; 1209 case ARM_FMT_PUSHPOP_16: 1210 print_pushpop_16(sb, word); 1211 break; 1212 } 1213 } 1214 1215 /* B<cond>.W condition field — disasm.c appends the cc to the mnemonic. */ 1216 u32 arm32_branch_t3_cond(u32 w) { return branch_t3_cond(w); }