mirror of
https://github.com/capstone-engine/capstone
synced 2026-08-11 16:26:07 -04:00
AArch64: report NZCV access for MRS/MSR of NZCV (#3002)
MRS Xt, NZCV reads (and MSR NZCV, Xt writes) the same flags every flag-setting instruction implicitly defines, but the generated implicit register lists cannot express it: MRS/MSR are single generic instructions whose system register is an immediate operand, so LLVM's static Uses/Defs do not depend on it. The semantic link is already half-modeled: AArch64_check_updates_flags() sets update_flags for MSR NZCV, yet neither direction surfaces in the detail register lists or cs_regs_access(). Add the aliased NZCV register to the implicit lists when MRS reads or MSR writes it. The 128-bit pair forms MRRS/MSRR are deliberately excluded: NZCV is not a valid 128-bit system register, so those encodings are UNDEFINED rather than flag accesses (an exhaustive 2^32-word cross-check against an external NZCV-liveness model caught exactly this over-match in an earlier revision of the patch). Add detail tests covering both directions, a TPIDR_EL0 control case, and exact-match register lists for MRRS/MSRR.
This commit is contained in:
parent
4eb90672f3
commit
d770dd020c
2 changed files with 106 additions and 0 deletions
|
|
@ -379,6 +379,40 @@ static void AArch64_check_updates_flags(MCInst *MI)
|
|||
#endif // CAPSTONE_DIET
|
||||
}
|
||||
|
||||
/// Surfaces system-register accesses which alias an architectural
|
||||
/// register Capstone models. MRS Xt, NZCV reads (and MSR NZCV, Xt
|
||||
/// writes) the same flags every flag-setting instruction implicitly
|
||||
/// defines, but the generated implicit register lists cannot express
|
||||
/// it: MRS/MSR are single generic instructions whose system register
|
||||
/// is an immediate operand, so LLVM's static Uses/Defs do not depend
|
||||
/// on it. Add the aliased register to the implicit lists so
|
||||
/// cs_regs_access() reports it like any other NZCV reader/writer.
|
||||
/// The 128-bit pair forms MRRS/MSRR are deliberately excluded: NZCV
|
||||
/// is not a valid 128-bit system register, so those encodings are
|
||||
/// UNDEFINED rather than flag accesses.
|
||||
static void AArch64_add_sysreg_alias_access(MCInst *MI)
|
||||
{
|
||||
#ifndef CAPSTONE_DIET
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
const unsigned opcode = MCInst_getOpcode(MI);
|
||||
if (opcode != AArch64_MRS && opcode != AArch64_MSR)
|
||||
return;
|
||||
cs_detail *detail = get_detail(MI);
|
||||
for (int i = 0; i < detail->aarch64.op_count; ++i) {
|
||||
const cs_aarch64_op *op = &detail->aarch64.operands[i];
|
||||
if (op->type != AARCH64_OP_SYSREG)
|
||||
continue;
|
||||
if (op->sysop.sub_type == AARCH64_OP_REG_MRS &&
|
||||
op->sysop.reg.sysreg == AARCH64_SYSREG_NZCV)
|
||||
map_add_implicit_read(MI, AARCH64_REG_NZCV);
|
||||
else if (op->sysop.sub_type == AARCH64_OP_REG_MSR &&
|
||||
op->sysop.reg.sysreg == AARCH64_SYSREG_NZCV)
|
||||
map_add_implicit_write(MI, AARCH64_REG_NZCV);
|
||||
}
|
||||
#endif // CAPSTONE_DIET
|
||||
}
|
||||
|
||||
static aarch64_shifter id_to_shifter(unsigned Opcode)
|
||||
{
|
||||
switch (Opcode) {
|
||||
|
|
@ -934,6 +968,7 @@ void AArch64_printer(MCInst *MI, SStream *O, void * /* MCRegisterInfo* */ info)
|
|||
AArch64_check_post_index_am(MI, O);
|
||||
}
|
||||
AArch64_check_updates_flags(MI);
|
||||
AArch64_add_sysreg_alias_access(MI);
|
||||
map_set_alias_id(MI, O, insn_alias_mnem_map,
|
||||
ARR_SIZE(insn_alias_mnem_map) - 1);
|
||||
int syntax_opt = MI->csh->syntax;
|
||||
|
|
|
|||
|
|
@ -1614,3 +1614,74 @@ test_cases:
|
|||
mem_index: x2
|
||||
access: CS_AC_READ
|
||||
regs_read: [x1, x2]
|
||||
-
|
||||
# MRS/MSR of NZCV access the same flags every flag-setting
|
||||
# instruction implicitly defines, so cs_regs_access() must report
|
||||
# them. Other system registers (TPIDR_EL0 control case) are
|
||||
# unaffected, and the 128-bit pair forms MRRS/MSRR must NOT gain
|
||||
# an NZCV access: NZCV is not a valid 128-bit system register, so
|
||||
# those encodings are UNDEFINED rather than flag accesses.
|
||||
input:
|
||||
bytes: [ 0x00, 0x42, 0x3b, 0xd5, 0x00, 0x42, 0x1b, 0xd5, 0x42, 0xd0, 0x3b, 0xd5, 0x00, 0x42, 0x7b, 0xd5, 0x00, 0x42, 0x5b, 0xd5 ]
|
||||
arch: "CS_ARCH_AARCH64"
|
||||
options: [ "CS_OPT_DETAIL" ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "mrs x0, NZCV"
|
||||
details:
|
||||
aarch64:
|
||||
operands:
|
||||
-
|
||||
type: AARCH64_OP_REG
|
||||
reg: x0
|
||||
access: CS_AC_WRITE
|
||||
-
|
||||
type: AARCH64_OP_SYSREG
|
||||
sub_type: AARCH64_OP_REG_MRS
|
||||
sys_raw_val: 0xda10
|
||||
cc: AArch64CC_Invalid
|
||||
regs_read: [ nzcv ]
|
||||
regs_write: [ x0 ]
|
||||
-
|
||||
asm_text: "msr NZCV, x0"
|
||||
details:
|
||||
aarch64:
|
||||
operands:
|
||||
-
|
||||
type: AARCH64_OP_SYSREG
|
||||
sub_type: AARCH64_OP_REG_MSR
|
||||
sys_raw_val: 0xda10
|
||||
-
|
||||
type: AARCH64_OP_REG
|
||||
reg: x0
|
||||
access: CS_AC_READ
|
||||
cc: AArch64CC_Invalid
|
||||
regs_read: [ x0 ]
|
||||
regs_write: [ nzcv ]
|
||||
-
|
||||
asm_text: "mrs x2, TPIDR_EL0"
|
||||
details:
|
||||
aarch64:
|
||||
operands:
|
||||
-
|
||||
type: AARCH64_OP_REG
|
||||
reg: x2
|
||||
access: CS_AC_WRITE
|
||||
-
|
||||
type: AARCH64_OP_SYSREG
|
||||
sub_type: AARCH64_OP_REG_MRS
|
||||
sys_raw_val: 0xde82
|
||||
cc: AArch64CC_Invalid
|
||||
regs_write: [ x2 ]
|
||||
-
|
||||
asm_text: "mrrs x0, x1, NZCV"
|
||||
details:
|
||||
# Exact-match register lists: x0/x1 only, no NZCV read.
|
||||
regs_write: [ x0, x1 ]
|
||||
-
|
||||
asm_text: "msrr NZCV, x0, x1"
|
||||
details:
|
||||
# Exact-match register lists: x0/x1 only, no NZCV write.
|
||||
regs_read: [ x0, x1 ]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue