capstone-engine / capstone

Capstone disassembly/disassembler framework for ARM, ARM64 (ARMv8), Alpha, BPF, Ethereum VM, HPPA, M68K, M680X, Mips, MOS65XX, PPC, RISC-V(rv32G/rv64G), SH, Sparc, SystemZ, TMS320C64X, TriCore, Webassembly, XCore and X86.

Home Page:http://www.capstone-engine.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[X86] Incorrect explicit read/modified registers for vcmpunordss and others

mur47x111 opened this issue · comments

cstool/cstool -d -s x64 "62 f1 76 08 c2 c9 03" may yield different results:

        op_count: 3
                operands[0].type: REG = k1
                operands[0].size: 2
                operands[1].type: REG = xmm1
                operands[1].size: 16
                operands[2].type: REG = xmm1
                operands[2].size: 16
...
        op_count: 3
                operands[0].type: REG = k1
                operands[0].size: 2
                operands[1].type: REG = xmm1
                operands[1].size: 16
                operands[2].type: REG = xmm1
                operands[2].size: 16
        Registers read: xmm1
...
        op_count: 3
                operands[0].type: REG = k1
                operands[0].size: 2
                operands[1].type: REG = xmm1
                operands[1].size: 16
                operands[2].type: REG = xmm1
                operands[2].size: 16
        Registers read: xmm1
        Registers modified: xmm1

This is due to incorrect operand access values specified for instructions such as vcmpunordss. IIUC, operand access values are maintained in capstone/arch/X86/X86MappingInsnOp.inc and copied to the new X86MappingInsnOp.inc generated by tablegen, see

def print_entry(arch, insn_id, mnem, mapping, mnem_can_be_wrong):
insn = "%s_%s" %(arch, insn_id)
# first, try to find this entry in old MappingInsn.inc file
for i in range(len(mapping)):
if mapping[i].startswith('{') and '/*' in mapping[i]:
#print(mapping[i])
tmp = mapping[i].split('/*')
tmp = tmp[1].strip()
tmp = tmp.split(',')
#print("insn2 = |%s|" %tmp.strip())
if tmp[0].strip() == insn:
if not mnem_can_be_wrong:
print('''
{\t/* %s, %s_INS_%s: %s */
\t%s
\t%s
},'''% (insn, arch, mnem, mnem.lower(), mapping[i + 1].strip(), mapping[i + 2].strip()))
else:
print('''
{\t/* %s, %s
\t%s
\t%s
},'''% (insn, ''.join(tmp[1:]).strip(), mapping[i + 1].strip(), mapping[i + 2].strip()))
return
print('''
{\t/* %s, %s_INS_%s: %s */
\t0,
\t{ 0 }
},'''% (insn, arch, mnem, mnem.lower()))
. New instructions are associated with default access value { 0 }. X86IntelInstPrinter or X86ATTInstPrinter uses a stack allocated array for storing the access values. This array is never initialized and only the first element is set to 0. When requesting access value for second/third operands in such instructions, it then fetches random values stored in the un-initialized array, and thus yield random results.

closed with #2259