From 3aa2fd93baf97427533d82d9d8f56fc21c21bd2a Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Tue, 1 Sep 2026 17:05:53 -0700 Subject: [PATCH] AArch64: keep the Rm operand of the register-form shifts The register-form variable shifts -- LSLV/LSRV/ASRV/RORV, printed lsl/lsr/asr/ror with a register amount -- were generated with only two detail operands. add_non_alias_details() folds the shift amount Rm into the preceding operand's shift.value (with an AARCH64_SFT_*_REG type) to describe the shift, and then called AArch64_dec_op_count(), dropping Rm from the operand list entirely: ror w0, w1, w2 op_count: 2 operands[0].type: REG = w0 access: WRITE operands[1].type: REG = w1 access: READ shift: ROR_REG w2 A consumer walking the operand list therefore never saw w2, the shift amount and a genuine read. cs_regs_access() still reported it -- the shift-value harvest at the bottom of AArch64_reg_access() reads shift.value back as a register -- so, exactly as with the STLUR Rt bug (#3046), only the operand view was broken. Drop the dec_op_count() so Rm stays in the list as the third operand it prints as. The shift annotation on operand 1 is kept, so no information is lost; AArch64_reg_access() de-duplicates the restored operand against the shift-value read via arr_exist(), so the reported register lists do not change. The printed text is rendered from the MCInst and was never affected. Extends the four existing per-mnemonic regression cases (and their three duplicates) with the restored operand, and adds the 64-bit forms as new coverage. Co-Authored-By: Claude Fable 5 --- arch/AArch64/AArch64Mapping.c | 6 +- tests/details/aarch64.yaml | 144 ++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/arch/AArch64/AArch64Mapping.c b/arch/AArch64/AArch64Mapping.c index 482f6dae36..260220a3a6 100644 --- a/arch/AArch64/AArch64Mapping.c +++ b/arch/AArch64/AArch64Mapping.c @@ -454,12 +454,14 @@ static void add_non_alias_details(MCInst *MI) AARCH64_OP_REG); // The shift by register instructions don't set the shift value properly. - // Correct it here. + // Correct it here. Rm stays in the operand list: it prints as + // a third operand and is read. Only AArch64_reg_access knows + // to interpret shift.value as a register, and it de-duplicates + // against the operand's own read. uint64_t shift = AArch64_get_detail_op(MI, -1)->reg; cs_aarch64_op *op1 = AArch64_get_detail_op(MI, -2); op1->shift.type = id_to_shifter(Opcode); op1->shift.value = shift; - AArch64_dec_op_count(MI); break; case AArch64_FCMPDri: case AArch64_FCMPEDri: diff --git a/tests/details/aarch64.yaml b/tests/details/aarch64.yaml index f11791ca03..1af6b0d730 100644 --- a/tests/details/aarch64.yaml +++ b/tests/details/aarch64.yaml @@ -992,6 +992,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_ROR_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1017,6 +1021,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_LSR_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1042,6 +1050,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_ASR_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1067,6 +1079,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_LSL_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1092,6 +1108,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_ROR_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1117,6 +1137,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_LSR_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1142,6 +1166,10 @@ test_cases: access: CS_AC_READ shift_type: AARCH64_SFT_ASR_REG shift_value: 210 # Absolute number of W3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: w3 + access: CS_AC_READ regs_read: [ w2, w3 ] regs_write: [ w1 ] - @@ -1812,3 +1840,119 @@ test_cases: asm_text: "sysl x0, #0, c0, c0, #0" details: regs_write: [ x0 ] + - + input: + bytes: [0x41,0x20,0xc3,0x9a] + arch: "CS_ARCH_AARCH64" + options: [ CS_OPT_DETAIL ] + address: 0x0 + expected: + insns: + - + asm_text: "lsl x1, x2, x3" + details: + aarch64: + operands: + - + type: AARCH64_OP_REG + reg: x1 + access: CS_AC_WRITE + - + type: AARCH64_OP_REG + reg: x2 + access: CS_AC_READ + shift_type: AARCH64_SFT_LSL_REG + shift_value: 241 # Absolute number of X3 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: x3 + access: CS_AC_READ + regs_read: [ x2, x3 ] + regs_write: [ x1 ] + - + input: + bytes: [0xa4,0x24,0xc6,0x9a] + arch: "CS_ARCH_AARCH64" + options: [ CS_OPT_DETAIL ] + address: 0x0 + expected: + insns: + - + asm_text: "lsr x4, x5, x6" + details: + aarch64: + operands: + - + type: AARCH64_OP_REG + reg: x4 + access: CS_AC_WRITE + - + type: AARCH64_OP_REG + reg: x5 + access: CS_AC_READ + shift_type: AARCH64_SFT_LSR_REG + shift_value: 244 # Absolute number of X6 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: x6 + access: CS_AC_READ + regs_read: [ x5, x6 ] + regs_write: [ x4 ] + - + input: + bytes: [0x07,0x29,0xc9,0x9a] + arch: "CS_ARCH_AARCH64" + options: [ CS_OPT_DETAIL ] + address: 0x0 + expected: + insns: + - + asm_text: "asr x7, x8, x9" + details: + aarch64: + operands: + - + type: AARCH64_OP_REG + reg: x7 + access: CS_AC_WRITE + - + type: AARCH64_OP_REG + reg: x8 + access: CS_AC_READ + shift_type: AARCH64_SFT_ASR_REG + shift_value: 247 # Absolute number of X9 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: x9 + access: CS_AC_READ + regs_read: [ x8, x9 ] + regs_write: [ x7 ] + - + input: + bytes: [0x6a,0x2d,0xcc,0x9a] + arch: "CS_ARCH_AARCH64" + options: [ CS_OPT_DETAIL ] + address: 0x0 + expected: + insns: + - + asm_text: "ror x10, x11, x12" + details: + aarch64: + operands: + - + type: AARCH64_OP_REG + reg: x10 + access: CS_AC_WRITE + - + type: AARCH64_OP_REG + reg: x11 + access: CS_AC_READ + shift_type: AARCH64_SFT_ROR_REG + shift_value: 250 # Absolute number of X12 enum value. Might change with an update. + - + type: AARCH64_OP_REG + reg: x12 + access: CS_AC_READ + regs_read: [ x11, x12 ] + regs_write: [ x10 ]