diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c index 66badd95c32..48c16977133 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c @@ -987,6 +987,25 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { if (getIDWithAttrMask(&instructionID, insn, attrMask)) return -1; + /* + * JCXZ/JECXZ need special handling for 16-bit mode because the meaning + * of the AdSize prefix is inverted w.r.t. 32-bit mode. + */ + if (insn->mode == MODE_16BIT && insn->opcode == 0xE3) { + const struct InstructionSpecifier *spec; + spec = specifierForUID(instructionID); + + /* + * Check for Ii8PCRel instructions. We could alternatively do a + * string-compare on the names, but this is probably cheaper. + */ + if (x86OperandSets[spec->operands][0].type == TYPE_REL8) { + attrMask ^= ATTR_ADSIZE; + if (getIDWithAttrMask(&instructionID, insn, attrMask)) + return -1; + } + } + /* The following clauses compensate for limitations of the tables. */ if ((insn->mode == MODE_16BIT || insn->prefixPresent[0x66]) && diff --git a/test/MC/Disassembler/X86/x86-16.txt b/test/MC/Disassembler/X86/x86-16.txt index 83be869fa26..93974d433e3 100644 --- a/test/MC/Disassembler/X86/x86-16.txt +++ b/test/MC/Disassembler/X86/x86-16.txt @@ -297,10 +297,10 @@ # CHECK: lcalll $2, $4660 0x66 0x9a 0x34 0x12 0x00 0x00 0x02 0x00 -# CHECKX: jcxz +# CHECK: jcxz 0xe3 0x00 -# CHECKX: jecxz +# CHECK: jecxz 0x67 0xe3 0x00 # CHECK: iretw