arm32_decode_test.c (24943B)
1 /* ARM32 (Thumb-2) structured decode test. 2 * 3 * Pins the ArchDecodeOps path: bytes encoded via the isa.h inline encoders 4 * decode into KitDecodedInsn records, and the formatter renders those records 5 * back to text. Covers each 16-bit and 32-bit family, the MOVW/MOVT immediate 6 * split, the BL/B.W split-immediate, IT, CBZ/TBB, and a few data-proc + ldst. 7 * Mirrors test/arch/rv64_decode_test.c. */ 8 9 #include <kit/compile.h> 10 #include <kit/core.h> 11 #include <stdarg.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include "arch/arch.h" 17 #include "arch/arm32/isa.h" 18 #include "lib/kit_unit.h" 19 20 static KitUnit g_u; 21 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 22 23 static KitCompiler* new_compiler(void) { 24 /* arm32 is ILP32: pointers are 4 bytes (the shared helper defaults to 8). */ 25 KitTargetSpec t = 26 kit_unit_target(KIT_ARCH_ARM_32, KIT_OS_FREESTANDING, KIT_OBJ_ELF); 27 KitCompiler* c = NULL; 28 t.ptr_size = 4; 29 t.ptr_align = 4; 30 if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) { 31 fprintf(stderr, "compiler_new failed\n"); 32 exit(2); 33 } 34 return c; 35 } 36 37 /* Emit a 32-bit Thumb-2 word ((hw1<<16)|hw2) as two LE half-words, hw1 first. */ 38 static void put_t32(unsigned char* b, size_t off, unsigned w) { 39 unsigned hw1 = (w >> 16) & 0xffffu, hw2 = w & 0xffffu; 40 b[off + 0] = (unsigned char)(hw1 & 0xffu); 41 b[off + 1] = (unsigned char)((hw1 >> 8) & 0xffu); 42 b[off + 2] = (unsigned char)(hw2 & 0xffu); 43 b[off + 3] = (unsigned char)((hw2 >> 8) & 0xffu); 44 } 45 46 static void put_t16(unsigned char* b, size_t off, unsigned hw) { 47 b[off + 0] = (unsigned char)(hw & 0xffu); 48 b[off + 1] = (unsigned char)((hw >> 8) & 0xffu); 49 } 50 51 /* Decode one instruction and assert the rendered mnemonic + an operand needle. 52 * `nbytes_want` is 2 or 4. */ 53 static void expect_text(KitCompiler* pub, const unsigned char* bytes, 54 size_t len, u64 pc, u8 nbytes_want, const char* mnem, 55 const char* op_needle, const char* what) { 56 Compiler* c = (Compiler*)pub; 57 KitDecodedInsn insn; 58 ArchInsnFormatter* fmt; 59 KitInsn text; 60 KitStatus st; 61 memset(&insn, 0, sizeof insn); 62 st = arch_decode_one(c, bytes, len, pc, &insn); 63 EXPECT(st == KIT_OK, "%s: decode_one status %d", what, (int)st); 64 EXPECT(insn.nbytes == nbytes_want, "%s: nbytes = %u (want %u)", what, 65 (unsigned)insn.nbytes, (unsigned)nbytes_want); 66 fmt = arch_insn_formatter_new(c); 67 EXPECT(fmt != NULL, "%s: formatter_new NULL", what); 68 if (!fmt) return; 69 memset(&text, 0, sizeof text); 70 st = arch_format_insn(fmt, &insn, &text); 71 EXPECT(st == KIT_OK, "%s: format status %d", what, (int)st); 72 EXPECT(kit_slice_eq_cstr(text.mnemonic, mnem), "%s: mnemonic = '%.*s' want '%s'", 73 what, KIT_SLICE_ARG(text.mnemonic), mnem); 74 if (op_needle && op_needle[0]) { 75 EXPECT(text.operands.s && strstr(text.operands.s, op_needle), 76 "%s: operands '%.*s' missing '%s'", what, KIT_SLICE_ARG(text.operands), 77 op_needle); 78 } 79 arch_insn_formatter_free(fmt); 80 } 81 82 static void decode_movw_movt(KitCompiler* pub) { 83 unsigned char b[4]; 84 put_t32(b, 0, arm_movw(ARM_R0, 0x1234)); 85 expect_text(pub, b, 4, 0x1000, 4, "movw", "r0", "movw imm"); 86 expect_text(pub, b, 4, 0x1000, 4, "movw", "4660", "movw value"); /* 0x1234 */ 87 put_t32(b, 0, arm_movt(ARM_R0, 0xabcd)); 88 expect_text(pub, b, 4, 0x1000, 4, "movt", "r0", "movt"); 89 90 /* Confirm the operand-decode path recovers the immediate. */ 91 { 92 Compiler* c = (Compiler*)pub; 93 KitDecodedInsn insn; 94 put_t32(b, 0, arm_movw(ARM_R3, 0xbeef)); 95 memset(&insn, 0, sizeof insn); 96 EXPECT(arch_decode_one(c, b, 4, 0, &insn) == KIT_OK, "movw decode"); 97 EXPECT(insn.noperands == 2, "movw noperands = %u", (unsigned)insn.noperands); 98 EXPECT(insn.operands[0].kind == KIT_DECOP_REG && insn.operands[0].reg == 3, 99 "movw rd"); 100 EXPECT(insn.operands[1].kind == KIT_DECOP_IMM && 101 insn.operands[1].imm == 0xbeef, 102 "movw imm = 0x%llx", (unsigned long long)insn.operands[1].imm); 103 } 104 } 105 106 static void decode_dp(KitCompiler* pub) { 107 unsigned char b[4]; 108 put_t32(b, 0, arm_add_reg(ARM_R0, ARM_R1, ARM_R2)); 109 expect_text(pub, b, 4, 0, 4, "add.w", "r0, r1, r2", "add.w reg"); 110 put_t32(b, 0, arm_sub_reg(ARM_R3, ARM_R4, ARM_R5)); 111 expect_text(pub, b, 4, 0, 4, "sub.w", "r3, r4, r5", "sub.w reg"); 112 put_t32(b, 0, arm_orr_reg(ARM_R0, ARM_R1, ARM_R2)); 113 expect_text(pub, b, 4, 0, 4, "orr.w", "r0, r1, r2", "orr.w reg"); 114 { 115 u32 out12; 116 EXPECT(thumb_expand_imm_encode(0xff, &out12), "encode 0xff modimm"); 117 put_t32(b, 0, arm_dp_imm(8u, 0u, ARM_R0, ARM_R1, out12)); /* add.w r0,r1,#255 */ 118 expect_text(pub, b, 4, 0, 4, "add.w", "#255", "add.w imm"); 119 } 120 put_t32(b, 0, arm_mov_reg(ARM_R0, ARM_R1)); 121 expect_text(pub, b, 4, 0, 4, "mov.w", "r0, r1", "mov.w reg"); 122 put_t32(b, 0, arm_cmp_reg(ARM_R2, ARM_R3)); 123 expect_text(pub, b, 4, 0, 4, "cmp.w", "r2, r3", "cmp.w reg"); 124 } 125 126 /* The Thumb-2 shifted-MOV family (0xea4f....) is the ORR-based MOV-with-shift; 127 * it disassembles (per llvm-objdump --triple=thumbv7em) to the shift mnemonic 128 * (lsl/lsr/asr/ror, or rrx for ROR #0) — except a plain LSL #0, which stays 129 * `mov.w`. The MVN-with-shift form (0xea6f....) keeps its `mvn.w` mnemonic and 130 * appends a `, <sh> #n` suffix. No direct encoder, so raw words via put_t32. */ 131 static void decode_shifts(KitCompiler* pub) { 132 unsigned char b[4]; 133 /* LSL #0 = plain mov.w (regression guard). */ 134 put_t32(b, 0, 0xea4f0001u); 135 expect_text(pub, b, 4, 0, 4, "mov.w", "r0, r1", "mov-shift lsl#0 = mov.w"); 136 /* LSL #3 -> lsl.w. */ 137 put_t32(b, 0, 0xea4f00c1u); 138 expect_text(pub, b, 4, 0, 4, "lsl.w", "r0, r1, #3", "mov-shift lsl#3"); 139 /* LSR #0 means #32. */ 140 put_t32(b, 0, 0xea4f0011u); 141 expect_text(pub, b, 4, 0, 4, "lsr.w", "r0, r1, #32", "mov-shift lsr#0->32"); 142 /* ASR #0 means #32. */ 143 put_t32(b, 0, 0xea4f0021u); 144 expect_text(pub, b, 4, 0, 4, "asr.w", "r0, r1, #32", "mov-shift asr#0->32"); 145 /* ROR #5. */ 146 put_t32(b, 0, 0xea4f1071u); 147 expect_text(pub, b, 4, 0, 4, "ror.w", "r0, r1, #5", "mov-shift ror#5"); 148 /* ROR #0 -> rrx (two operands, no amount, no .w). */ 149 put_t32(b, 0, 0xea4f0031u); 150 expect_text(pub, b, 4, 0, 4, "rrx", "r0, r1", "mov-shift ror#0 = rrx"); 151 /* MVN LSL #3 keeps mvn.w + appends the shift suffix. */ 152 put_t32(b, 0, 0xea6f00c1u); 153 expect_text(pub, b, 4, 0, 4, "mvn.w", "r0, r1, lsl #3", "mvn-shift lsl#3"); 154 /* MVN LSL #0 = plain mvn.w (regression guard). */ 155 put_t32(b, 0, 0xea6f0001u); 156 expect_text(pub, b, 4, 0, 4, "mvn.w", "r0, r1", "mvn lsl#0 = mvn.w"); 157 } 158 159 static void decode_mul_div_ext(KitCompiler* pub) { 160 unsigned char b[4]; 161 put_t32(b, 0, arm_mul(ARM_R0, ARM_R1, ARM_R2)); 162 expect_text(pub, b, 4, 0, 4, "mul", "r0, r1, r2", "mul"); 163 put_t32(b, 0, arm_sdiv(ARM_R0, ARM_R1, ARM_R2)); 164 expect_text(pub, b, 4, 0, 4, "sdiv", "r0, r1, r2", "sdiv"); 165 put_t32(b, 0, arm_udiv(ARM_R3, ARM_R4, ARM_R5)); 166 expect_text(pub, b, 4, 0, 4, "udiv", "r3, r4, r5", "udiv"); 167 put_t32(b, 0, arm_umull(ARM_R0, ARM_R1, ARM_R2, ARM_R3)); 168 expect_text(pub, b, 4, 0, 4, "umull", "r0, r1, r2, r3", "umull"); 169 put_t32(b, 0, arm_sxtb(ARM_R0, ARM_R1)); 170 expect_text(pub, b, 4, 0, 4, "sxtb", "r0, r1", "sxtb"); 171 put_t32(b, 0, arm_uxth(ARM_R2, ARM_R3)); 172 expect_text(pub, b, 4, 0, 4, "uxth", "r2, r3", "uxth"); 173 } 174 175 static void decode_rev_clz_bitfield(KitCompiler* pub) { 176 unsigned char b[4]; 177 /* kit emits the 16-bit REV (arm_rev returns a u16, 0xba__); the disassembler 178 * decodes both the 16-bit (T1) and 32-bit (T2) forms via separate table rows. */ 179 put_t16(b, 0, arm_rev(ARM_R0, ARM_R1)); 180 expect_text(pub, b, 2, 0, 2, "rev", "r0, r1", "rev"); 181 put_t32(b, 0, arm_clz(ARM_R2, ARM_R3)); 182 expect_text(pub, b, 4, 0, 4, "clz", "r2, r3", "clz"); 183 put_t32(b, 0, arm_bfi(ARM_R0, ARM_R1, 4, 8)); 184 expect_text(pub, b, 4, 0, 4, "bfi", "r0, r1, #4, #8", "bfi"); 185 put_t32(b, 0, arm_ubfx(ARM_R0, ARM_R1, 4, 8)); 186 expect_text(pub, b, 4, 0, 4, "ubfx", "r0, r1, #4, #8", "ubfx"); 187 put_t32(b, 0, arm_sbfx(ARM_R2, ARM_R3, 0, 5)); 188 expect_text(pub, b, 4, 0, 4, "sbfx", "r2, r3, #0, #5", "sbfx"); 189 } 190 191 static void decode_ldst(KitCompiler* pub) { 192 unsigned char b[4]; 193 put_t32(b, 0, arm_ldr_imm(ARM_R0, ARM_R1, 4)); 194 expect_text(pub, b, 4, 0, 4, "ldr.w", "[r1, #4]", "ldr.w T3"); 195 put_t32(b, 0, arm_str_imm(ARM_R2, ARM_R3, 8)); 196 expect_text(pub, b, 4, 0, 4, "str.w", "[r3, #8]", "str.w T3"); 197 put_t32(b, 0, arm_ldrb_imm(ARM_R0, ARM_R1, 1)); 198 expect_text(pub, b, 4, 0, 4, "ldrb.w", "[r1, #1]", "ldrb.w T3"); 199 /* T4 negative offset. */ 200 put_t32(b, 0, arm_ldst_t4(0xf850u, ARM_R0, ARM_R1, 4, 0)); 201 expect_text(pub, b, 4, 0, 4, "ldr.w", "[r1, #-4]", "ldr.w T4 -imm8"); 202 /* Structured operand path on the T3 load. */ 203 { 204 Compiler* c = (Compiler*)pub; 205 KitDecodedInsn insn; 206 put_t32(b, 0, arm_ldr_imm(ARM_R5, ARM_R6, 12)); 207 memset(&insn, 0, sizeof insn); 208 EXPECT(arch_decode_one(c, b, 4, 0, &insn) == KIT_OK, "ldr decode"); 209 EXPECT((insn.flags & KIT_DECODE_MEMORY) != 0, "ldr is memory"); 210 EXPECT(insn.operands[1].kind == KIT_DECOP_MEM && 211 insn.operands[1].reg == 6 && insn.operands[1].imm == 12, 212 "ldr mem operand"); 213 } 214 } 215 216 static void decode_pushpop(KitCompiler* pub) { 217 unsigned char b[4]; 218 put_t32(b, 0, arm_push_w((1u << 4) | (1u << 14))); /* push {r4, lr} */ 219 expect_text(pub, b, 4, 0, 4, "push.w", "r4", "push.w"); 220 expect_text(pub, b, 4, 0, 4, "push.w", "lr", "push.w lr"); 221 put_t32(b, 0, arm_pop_w((1u << 4) | (1u << 15))); /* pop {r4, pc} */ 222 expect_text(pub, b, 4, 0, 4, "pop.w", "pc", "pop.w"); 223 } 224 225 static void decode_branches(KitCompiler* pub) { 226 unsigned char b[4]; 227 /* BL +8: the 24-bit split immediate {S,I1,I2,imm10,imm11} encodes the byte 228 * offset (target - pc - 4). For +8 with S=0: I1=I2=1 (so J1=J2=1), imm11=2. */ 229 put_t32(b, 0, 0xf000f802u); 230 expect_text(pub, b, 4, 0x1000, 4, "bl", "0x1008", "bl +8"); 231 232 /* B.W +8 (T4): hw2[15:14]=10, hw2[12]=1, J1=J2=1, imm11=2. */ 233 put_t32(b, 0, 0xf000b802u); 234 expect_text(pub, b, 4, 0x1000, 4, "b.w", "0x1008", "b.w +8"); 235 236 /* B<cond>.W +8 (T3): cond eq in hw1[9:6]; hw2[15:14]=10, hw2[12]=0. */ 237 put_t32(b, 0, 0xf0008002u); 238 expect_text(pub, b, 4, 0x1000, 4, "beq.w", "0x1008", "beq.w +8"); 239 240 /* 16-bit Bcc (T1): 0xDxyy, cond=NE (1), imm8=2 -> off = 4 + 4 = 8. */ 241 put_t16(b, 0, 0xd102u); 242 expect_text(pub, b, 2, 0x1000, 2, "bne", "0x1008", "bne 16-bit"); 243 244 /* 16-bit B (T2): 0xE002 -> off = 4 + 4 = 8. */ 245 put_t16(b, 0, 0xe002u); 246 expect_text(pub, b, 2, 0x1000, 2, "b", "0x1008", "b 16-bit"); 247 248 /* BX lr / BLX r3. */ 249 put_t16(b, 0, arm_bx(ARM_LR)); 250 expect_text(pub, b, 2, 0, 2, "bx", "lr", "bx lr"); 251 put_t16(b, 0, arm_blx_reg(ARM_R3)); 252 expect_text(pub, b, 2, 0, 2, "blx", "r3", "blx r3"); 253 } 254 255 static void decode_cbz_tbb(KitCompiler* pub) { 256 unsigned char b[4]; 257 /* CBZ r0, +8: imm6 = (8-4)/2 = 2. */ 258 put_t16(b, 0, arm_cbz(ARM_R0, 2)); 259 expect_text(pub, b, 2, 0x1000, 2, "cbz", "r0", "cbz r0"); 260 expect_text(pub, b, 2, 0x1000, 2, "cbz", "0x1008", "cbz target"); 261 put_t16(b, 0, arm_cbnz(ARM_R1, 2)); 262 expect_text(pub, b, 2, 0x1000, 2, "cbnz", "r1", "cbnz r1"); 263 /* TBB [r0, r1]. */ 264 put_t32(b, 0, arm_tbb(ARM_R0, ARM_R1)); 265 expect_text(pub, b, 4, 0, 4, "tbb", "[r0, r1]", "tbb"); 266 put_t32(b, 0, arm_tbh(ARM_R2, ARM_R3)); 267 expect_text(pub, b, 4, 0, 4, "tbh", "[r2, r3", "tbh"); 268 } 269 270 static void decode_misc16(KitCompiler* pub) { 271 unsigned char b[4]; 272 put_t16(b, 0, arm_nop16()); 273 expect_text(pub, b, 2, 0, 2, "nop", "", "nop"); 274 put_t16(b, 0, arm_bkpt(0xab)); 275 expect_text(pub, b, 2, 0, 2, "bkpt", "#171", "bkpt"); 276 put_t16(b, 0, arm_mov_hi(ARM_R7, ARM_SP)); /* mov r7, sp */ 277 expect_text(pub, b, 2, 0, 2, "mov", "r7, sp", "mov r7, sp"); 278 } 279 280 static void decode_barriers(KitCompiler* pub) { 281 unsigned char b[4]; 282 put_t32(b, 0, arm_dmb(0xf)); 283 expect_text(pub, b, 4, 0, 4, "dmb", "sy", "dmb sy"); 284 put_t32(b, 0, arm_dsb(0xf)); 285 expect_text(pub, b, 4, 0, 4, "dsb", "sy", "dsb sy"); 286 put_t32(b, 0, arm_isb(0xf)); 287 expect_text(pub, b, 4, 0, 4, "isb", "sy", "isb sy"); 288 } 289 290 /* ARMv7E-M DSP saturating ops: SSAT/USAT (Rd, #sat, Rm) + the QADD family 291 * (Rd, Rm, Rn — note Rn lands in hw1[3:0], Rm in hw2[3:0]). Golden words pinned 292 * to llvm-mc (`--triple=thumbv7em-none-eabi --mattr=+dsp -show-encoding`). */ 293 static void decode_dsp_sat(KitCompiler* pub) { 294 unsigned char b[4]; 295 296 /* Direct encoder -> word equality, pinned to the oracle bytes. */ 297 EXPECT(arm_ssat(ARM_R0, 16, ARM_R1) == 0xf301000fu, "ssat encode = %#x", 298 arm_ssat(ARM_R0, 16, ARM_R1)); 299 /* llvm-mc bytes [0x06,0xf3,0x1f,0x05] -> hw1=0xf306, hw2=0x051f. (The task 300 * spec quoted 0xf3061f05 with hw2's bytes transposed; the real word is 301 * 0xf306051f, hw2 = (rd<<8)|(sat-1) = (5<<8)|31.) */ 302 EXPECT(arm_ssat(ARM_R5, 32, ARM_R6) == 0xf306051fu, "ssat32 encode = %#x", 303 arm_ssat(ARM_R5, 32, ARM_R6)); 304 EXPECT(arm_usat(ARM_R0, 15, ARM_R1) == 0xf381000fu, "usat encode = %#x", 305 arm_usat(ARM_R0, 15, ARM_R1)); 306 EXPECT(arm_qadd(ARM_R3, ARM_R1, ARM_R2) == 0xfa82f381u, "qadd encode = %#x", 307 arm_qadd(ARM_R3, ARM_R1, ARM_R2)); 308 EXPECT(arm_qadd(ARM_R0, ARM_R2, ARM_R1) == 0xfa81f082u, "qadd2 encode = %#x", 309 arm_qadd(ARM_R0, ARM_R2, ARM_R1)); 310 EXPECT(arm_qsub(ARM_R3, ARM_R1, ARM_R2) == 0xfa82f3a1u, "qsub encode = %#x", 311 arm_qsub(ARM_R3, ARM_R1, ARM_R2)); 312 EXPECT(arm_qdadd(ARM_R3, ARM_R1, ARM_R2) == 0xfa82f391u, "qdadd encode = %#x", 313 arm_qdadd(ARM_R3, ARM_R1, ARM_R2)); 314 EXPECT(arm_qdsub(ARM_R3, ARM_R1, ARM_R2) == 0xfa82f3b1u, "qdsub encode = %#x", 315 arm_qdsub(ARM_R3, ARM_R1, ARM_R2)); 316 317 /* Disassembly round-trips. */ 318 put_t32(b, 0, arm_ssat(ARM_R0, 16, ARM_R1)); 319 expect_text(pub, b, 4, 0, 4, "ssat", "r0, #16, r1", "ssat"); 320 put_t32(b, 0, arm_usat(ARM_R0, 15, ARM_R1)); 321 expect_text(pub, b, 4, 0, 4, "usat", "r0, #15, r1", "usat"); 322 put_t32(b, 0, arm_qadd(ARM_R3, ARM_R1, ARM_R2)); 323 expect_text(pub, b, 4, 0, 4, "qadd", "r3, r1, r2", "qadd"); 324 put_t32(b, 0, arm_qsub(ARM_R3, ARM_R1, ARM_R2)); 325 expect_text(pub, b, 4, 0, 4, "qsub", "r3, r1, r2", "qsub"); 326 put_t32(b, 0, arm_qdadd(ARM_R3, ARM_R1, ARM_R2)); 327 expect_text(pub, b, 4, 0, 4, "qdadd", "r3, r1, r2", "qdadd"); 328 put_t32(b, 0, arm_qdsub(ARM_R3, ARM_R1, ARM_R2)); 329 expect_text(pub, b, 4, 0, 4, "qdsub", "r3, r1, r2", "qdsub"); 330 331 /* Structured-operand check: SSAT decodes to (reg, imm=16, reg). */ 332 { 333 Compiler* c = (Compiler*)pub; 334 KitDecodedInsn insn; 335 put_t32(b, 0, arm_ssat(ARM_R0, 16, ARM_R1)); 336 memset(&insn, 0, sizeof insn); 337 EXPECT(arch_decode_one(c, b, 4, 0, &insn) == KIT_OK, "ssat decode"); 338 EXPECT(insn.noperands == 3, "ssat noperands = %u", 339 (unsigned)insn.noperands); 340 EXPECT(insn.operands[0].kind == KIT_DECOP_REG && insn.operands[0].reg == 0, 341 "ssat rd"); 342 EXPECT(insn.operands[1].kind == KIT_DECOP_IMM && insn.operands[1].imm == 16, 343 "ssat sat = %lld", (long long)insn.operands[1].imm); 344 EXPECT(insn.operands[2].kind == KIT_DECOP_REG && insn.operands[2].reg == 1, 345 "ssat rm"); 346 } 347 } 348 349 static void decode_ldrex_strex(KitCompiler* pub) { 350 unsigned char b[4]; 351 put_t32(b, 0, arm_ldrex(ARM_R0, ARM_R1, 0)); 352 expect_text(pub, b, 4, 0, 4, "ldrex", "[r1]", "ldrex"); 353 put_t32(b, 0, arm_strex(ARM_R0, ARM_R1, ARM_R2, 0)); 354 expect_text(pub, b, 4, 0, 4, "strex", "r0, r1, [r2]", "strex"); 355 } 356 357 /* The IT block renders its firstcond suffix on the following instruction. */ 358 static void decode_it_block(KitCompiler* pub) { 359 Compiler* c = (Compiler*)pub; 360 unsigned char b[8]; 361 KitDecodedInsn insts[2]; 362 ArchInsnFormatter* fmt; 363 KitInsn t0, t1; 364 u32 n = 0; 365 u32 out12; 366 367 put_t16(b, 0, arm_it(ARM_CC_EQ, 0x8)); /* it eq */ 368 thumb_expand_imm_encode(1, &out12); 369 put_t32(b, 2, arm_mov_imm(ARM_R0, out12)); /* mov.w r0, #1 -> moveq */ 370 371 memset(insts, 0, sizeof insts); 372 EXPECT(arch_decode_block(c, b, sizeof b, 0x2000, insts, 2, &n) == KIT_OK, 373 "it block decode_block"); 374 EXPECT(n == 2, "it block n = %u", (unsigned)n); 375 EXPECT(insts[0].nbytes == 2, "it nbytes = %u", (unsigned)insts[0].nbytes); 376 EXPECT(insts[0].opcode == ARM32_DEC_IT, "it opcode = %u", 377 (unsigned)insts[0].opcode); 378 379 /* Format both through one formatter so the IT-state threads across. */ 380 fmt = arch_insn_formatter_new(c); 381 EXPECT(fmt != NULL, "it formatter"); 382 if (!fmt) return; 383 memset(&t0, 0, sizeof t0); 384 memset(&t1, 0, sizeof t1); 385 EXPECT(arch_format_insn(fmt, &insts[0], &t0) == KIT_OK, "format it"); 386 EXPECT(kit_slice_eq_cstr(t0.mnemonic, "it"), "it mnemonic = '%.*s'", 387 KIT_SLICE_ARG(t0.mnemonic)); 388 EXPECT(t0.operands.s && strstr(t0.operands.s, "eq"), "it operand 'eq': %.*s", 389 KIT_SLICE_ARG(t0.operands)); 390 EXPECT(arch_format_insn(fmt, &insts[1], &t1) == KIT_OK, "format moveq"); 391 EXPECT(kit_slice_eq_cstr(t1.mnemonic, "moveq.w"), 392 "conditional mnemonic = '%.*s' (want moveq.w)", 393 KIT_SLICE_ARG(t1.mnemonic)); 394 arch_insn_formatter_free(fmt); 395 } 396 397 /* decode_block stops at a terminator (a B.W). */ 398 static void decode_block_terminates(KitCompiler* pub) { 399 Compiler* c = (Compiler*)pub; 400 unsigned char b[12]; 401 KitDecodedInsn insts[4]; 402 u32 n = 0; 403 put_t32(b, 0, arm_add_reg(ARM_R0, ARM_R1, ARM_R2)); 404 put_t32(b, 4, 0xf000b802u); /* b.w +8 (terminator) */ 405 put_t32(b, 8, arm_add_reg(ARM_R3, ARM_R4, ARM_R5)); 406 memset(insts, 0, sizeof insts); 407 EXPECT(arch_decode_block(c, b, sizeof b, 0, insts, 4, &n) == KIT_OK, 408 "block decode"); 409 EXPECT(n == 2, "block stops at b.w: n = %u", (unsigned)n); 410 EXPECT((insts[1].flags & KIT_DECODE_TERMINATOR) != 0, "b.w terminates"); 411 } 412 413 /* The new 16-bit narrow encoders (density pass) round-trip against the existing 414 * decoder. Each asserts the rendered mnemonic + an operand needle; a couple also 415 * pin the raw 16-bit word so a bit-layout regression is caught at the encoder. */ 416 static void decode_narrow_16(KitCompiler* pub) { 417 unsigned char b[4]; 418 419 /* PUSH {r4, r7, lr} = 0xb590 (list8=0x90, bit8=lr); POP {r7, pc} = 0xbd80. */ 420 EXPECT(arm_push16((1u << 4) | (1u << 7), 1u) == 0xb590u, "push16 bits = 0x%x", 421 (unsigned)arm_push16((1u << 4) | (1u << 7), 1u)); 422 put_t16(b, 0, arm_push16((1u << 7), 1u)); /* push {r7, lr} */ 423 expect_text(pub, b, 2, 0, 2, "push", "r7", "push16 r7"); 424 expect_text(pub, b, 2, 0, 2, "push", "lr", "push16 lr"); 425 EXPECT(arm_pop16((1u << 7), 1u) == 0xbd80u, "pop16 bits = 0x%x", 426 (unsigned)arm_pop16((1u << 7), 1u)); 427 put_t16(b, 0, arm_pop16((1u << 7), 1u)); /* pop {r7, pc} */ 428 expect_text(pub, b, 2, 0, 2, "pop", "pc", "pop16 pc"); 429 430 /* LDR/STR [rn, #imm5*scale]: ldr r0,[r1,#4] = 0x6848 (imm5=1, ×4). */ 431 EXPECT(arm_ldst_i5_16(0x6800u, ARM_R0, ARM_R1, 1u) == 0x6848u, "ldr i5 bits"); 432 put_t16(b, 0, arm_ldst_i5_16(0x6800u, ARM_R0, ARM_R1, 1u)); 433 expect_text(pub, b, 2, 0, 2, "ldr", "[r1, #4]", "ldr i5"); 434 put_t16(b, 0, arm_ldst_i5_16(0x6000u, ARM_R2, ARM_R3, 2u)); /* str r2,[r3,#8] */ 435 expect_text(pub, b, 2, 0, 2, "str", "[r3, #8]", "str i5"); 436 put_t16(b, 0, arm_ldst_i5_16(0x7800u, ARM_R0, ARM_R1, 1u)); /* ldrb r0,[r1,#1] */ 437 expect_text(pub, b, 2, 0, 2, "ldrb", "[r1, #1]", "ldrb i5"); 438 put_t16(b, 0, arm_ldst_i5_16(0x8800u, ARM_R0, ARM_R1, 1u)); /* ldrh r0,[r1,#2] */ 439 expect_text(pub, b, 2, 0, 2, "ldrh", "[r1, #2]", "ldrh i5"); 440 441 /* LDR/STR [sp, #imm8*4]: ldr r0,[sp,#4] = 0x9801. */ 442 EXPECT(arm_ldst_sp_16(0x9800u, ARM_R0, 1u) == 0x9801u, "ldr sp bits"); 443 put_t16(b, 0, arm_ldst_sp_16(0x9800u, ARM_R0, 1u)); 444 expect_text(pub, b, 2, 0, 2, "ldr", "[sp, #4]", "ldr sp"); 445 put_t16(b, 0, arm_ldst_sp_16(0x9000u, ARM_R2, 3u)); /* str r2,[sp,#12] */ 446 expect_text(pub, b, 2, 0, 2, "str", "[sp, #12]", "str sp"); 447 448 /* ADD rd, sp, #imm8*4: add r0, sp, #16 = 0xa804. */ 449 put_t16(b, 0, arm_add_sp_imm16(ARM_R0, 4u)); 450 expect_text(pub, b, 2, 0, 2, "add", "sp", "add rd,sp"); 451 452 /* ADD/SUB sp, sp, #imm7*4: sub sp,sp,#16 = 0xb084. */ 453 EXPECT(arm_sub_sp_sp_imm16(4u) == 0xb084u, "sub sp bits"); 454 put_t16(b, 0, arm_sub_sp_sp_imm16(4u)); 455 expect_text(pub, b, 2, 0, 2, "sub", "sp, sp", "sub sp,sp"); 456 put_t16(b, 0, arm_add_sp_sp_imm16(2u)); /* add sp,sp,#8 */ 457 expect_text(pub, b, 2, 0, 2, "add", "sp, sp", "add sp,sp"); 458 459 /* MOVS/ADDS/SUBS rdn, #imm8. */ 460 put_t16(b, 0, arm_movs_imm8(ARM_R0, 5u)); 461 expect_text(pub, b, 2, 0, 2, "movs", "#5", "movs imm8"); 462 put_t16(b, 0, arm_adds_imm8(ARM_R1, 7u)); 463 expect_text(pub, b, 2, 0, 2, "adds", "#7", "adds imm8"); 464 put_t16(b, 0, arm_subs_imm8(ARM_R2, 9u)); 465 expect_text(pub, b, 2, 0, 2, "subs", "#9", "subs imm8"); 466 467 /* ADDS/SUBS rd, rn, #imm3 and rd, rn, rm. */ 468 put_t16(b, 0, arm_adds_imm3(ARM_R0, ARM_R1, 3u)); 469 expect_text(pub, b, 2, 0, 2, "adds", "r0, r1, #3", "adds imm3"); 470 put_t16(b, 0, arm_subs_imm3(ARM_R0, ARM_R1, 2u)); 471 expect_text(pub, b, 2, 0, 2, "subs", "r0, r1, #2", "subs imm3"); 472 put_t16(b, 0, arm_adds_reg16(ARM_R0, ARM_R1, ARM_R2)); 473 expect_text(pub, b, 2, 0, 2, "adds", "r0, r1, r2", "adds reg16"); 474 put_t16(b, 0, arm_subs_reg16(ARM_R3, ARM_R4, ARM_R5)); 475 expect_text(pub, b, 2, 0, 2, "subs", "r3, r4, r5", "subs reg16"); 476 477 /* LSLS/LSRS/ASRS rd, rm, #imm5. */ 478 put_t16(b, 0, arm_lsls_imm16(ARM_R0, ARM_R1, 3u)); 479 expect_text(pub, b, 2, 0, 2, "lsls", "r0, r1, #3", "lsls imm5"); 480 put_t16(b, 0, arm_lsrs_imm16(ARM_R0, ARM_R1, 4u)); 481 expect_text(pub, b, 2, 0, 2, "lsrs", "r0, r1, #4", "lsrs imm5"); 482 put_t16(b, 0, arm_asrs_imm16(ARM_R2, ARM_R3, 5u)); 483 expect_text(pub, b, 2, 0, 2, "asrs", "r2, r3, #5", "asrs imm5"); 484 } 485 486 /* The 32-bit shifted-register operand encoders round-trip. The shift TEXT (lsl 487 * #k) rendering is owned by a concurrent disasm fix, so assert only the base 488 * mnemonic + rd/rn/rm and pin the raw encoding fields (hw1/hw2 + decoded shift) 489 * directly — those are this item's contract. */ 490 static void decode_shifted_reg(KitCompiler* pub) { 491 Compiler* c = (Compiler*)pub; 492 unsigned char b[4]; 493 KitDecodedInsn insn; 494 495 /* add.w r0, r1, r2, lsl #3 -> hw1 0xeb01, hw2 imm3=0(0..2 of sh=3 -> imm2=3), 496 * encoded: arm_add_reg_lsl(r0,r1,r2,3) = 0xeb01 00c2. */ 497 EXPECT(arm_add_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 3u) == 0xeb0100c2u, 498 "add_reg_lsl bits = 0x%08x", 499 (unsigned)arm_add_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 3u)); 500 put_t32(b, 0, arm_add_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 3u)); 501 expect_text(pub, b, 4, 0, 4, "add.w", "r0, r1, r2", "add.w shifted reg"); 502 EXPECT(arm_sub_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 2u) == 0xeba10082u, 503 "sub_reg_lsl bits = 0x%08x", 504 (unsigned)arm_sub_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 2u)); 505 put_t32(b, 0, arm_sub_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 2u)); 506 expect_text(pub, b, 4, 0, 4, "sub.w", "r0, r1, r2", "sub.w shifted reg"); 507 put_t32(b, 0, arm_and_reg_lsl(ARM_R3, ARM_R4, ARM_R5, 1u)); 508 expect_text(pub, b, 4, 0, 4, "and.w", "r3, r4, r5", "and.w shifted reg"); 509 put_t32(b, 0, arm_orr_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 4u)); 510 expect_text(pub, b, 4, 0, 4, "orr.w", "r0, r1, r2", "orr.w shifted reg"); 511 put_t32(b, 0, arm_eor_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 2u)); 512 expect_text(pub, b, 4, 0, 4, "eor.w", "r0, r1, r2", "eor.w shifted reg"); 513 514 /* The structured operand path recovers rd/rn/rm (the shift rider lives in the 515 * encoding fields, pinned above; the textual `lsl #k` render is owned by the 516 * concurrent disasm fix, so it is not asserted here). */ 517 put_t32(b, 0, arm_orr_reg_lsl(ARM_R0, ARM_R1, ARM_R2, 3u)); 518 memset(&insn, 0, sizeof insn); 519 EXPECT(arch_decode_one(c, b, 4, 0, &insn) == KIT_OK, "shifted reg decode"); 520 EXPECT(insn.noperands == 3, "shifted reg noperands = %u", 521 (unsigned)insn.noperands); 522 EXPECT(insn.operands[2].kind == KIT_DECOP_REG && insn.operands[2].reg == 2, 523 "shifted reg rm = r%u", (unsigned)insn.operands[2].reg); 524 } 525 526 /* Undecodable bytes fall back to .inst / .hword. */ 527 static void decode_unknown_fallback(KitCompiler* pub) { 528 unsigned char b[4]; 529 /* A 32-bit-marked but undefined word (top5 = 11111, garbage body). */ 530 put_t32(b, 0, 0xfff0ffffu); 531 expect_text(pub, b, 4, 0, 4, ".inst", "0x", ".inst fallback"); 532 /* A 16-bit undefined halfword (0xDExx is UDF). */ 533 put_t16(b, 0, 0xde01u); 534 /* 0xDE.. matches B<cond> with cond=0xE (AL) which is actually UDF; our table 535 * maps cond 0xE to "" so it renders as a bare "b" — acceptable. We instead 536 * use a clearly-unmapped 16-bit value. */ 537 put_t16(b, 0, 0xb600u); /* CPS/SETEND space, not in the table */ 538 expect_text(pub, b, 2, 0, 2, ".hword", "0x", ".hword fallback"); 539 } 540 541 int main(void) { 542 KitCompiler* c; 543 kit_unit_init(&g_u); 544 c = new_compiler(); 545 decode_movw_movt(c); 546 decode_dp(c); 547 decode_shifts(c); 548 decode_mul_div_ext(c); 549 decode_rev_clz_bitfield(c); 550 decode_ldst(c); 551 decode_pushpop(c); 552 decode_branches(c); 553 decode_cbz_tbb(c); 554 decode_misc16(c); 555 decode_barriers(c); 556 decode_ldrex_strex(c); 557 decode_dsp_sat(c); 558 decode_narrow_16(c); 559 decode_shifted_reg(c); 560 decode_it_block(c); 561 decode_block_terminates(c); 562 decode_unknown_fallback(c); 563 kit_compiler_free(c); 564 kit_unit_summary(&g_u, "arm32_decode_test"); 565 return kit_unit_status(&g_u); 566 }