capstone-engine / capstone

Capstone disassembly/disassembler framework for ARM, ARM64 (ARMv8), Alpha, BPF, Ethereum VM, HPPA, LoongArch, M68K, M680X, Mips, MOS65XX, PPC, RISC-V(rv32G/rv64G), SH, Sparc, SystemZ, TMS320C64X, TriCore, Webassembly, XCore and X86.
http://www.capstone-engine.org
7.54k stars 1.55k forks source link

x86: incorrect disassembly around FSTCW, FSTSW instructions #1611

Open minexew opened 4 years ago

minexew commented 4 years ago

Env:

Repro:

import capstone
md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32)
md.detail = True

# case 1
# expected: fstcw  WORD PTR [ebp-0x4] (based on Objdump disassembly which round-trips with GNU as)
for insn in md.disasm(b"\x9B\xD9\x7D\xFC", 0):
    print(insn.address, insn.mnemonic, insn.op_str)

print()

# case 2
# expected: fstsw  WORD PTR [ebp-0x2]
for insn in md.disasm(b"\x9B\xDD\x7D\xFE", 0):
    print(insn.address, insn.mnemonic, insn.op_str)

Output:

0 wait
1 fnstcw word ptr [ebp - 4]

0 wait
1 fnstsw dword ptr [ebp - 2]
tzoz commented 4 years ago

The operand size for case 2 is wrong indeed, but FSTCW is equivalent to FWAIT/WAIT followed by FNSTCW. The same applies to FSTSW.

minexew commented 4 years ago

Technically it is, but the Intel reference manual, GMU binutils and nasm-ndisasm all follow this convention. Why be different?

tzoz commented 4 years ago

Probably because it is less complicated to parse them as separate instructions while still being technically correct.