aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp')
-rw-r--r--lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp97
1 files changed, 72 insertions, 25 deletions
diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
index 843d037ad3cd..1ac304f3be03 100644
--- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
+++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
@@ -103,6 +103,9 @@ static int modRMRequired(OpcodeType type,
case XOPA_MAP:
decision = &XOPA_MAP_SYM;
break;
+ case THREEDNOW_MAP:
+ decision = &THREEDNOW_MAP_SYM;
+ break;
}
return decision->opcodeDecisions[insnContext].modRMDecisions[opcode].
@@ -147,6 +150,9 @@ static InstrUID decode(OpcodeType type,
case XOPA_MAP:
dec = &XOPA_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
break;
+ case THREEDNOW_MAP:
+ dec = &THREEDNOW_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode];
+ break;
}
switch (dec->modrm_type) {
@@ -292,6 +298,9 @@ static bool isREX(struct InternalInstruction *insn, uint8_t prefix) {
static void setPrefixPresent(struct InternalInstruction *insn, uint8_t prefix) {
uint8_t nextByte;
switch (prefix) {
+ case 0xf0:
+ insn->hasLockPrefix = true;
+ break;
case 0xf2:
case 0xf3:
if (lookAtByte(insn, &nextByte))
@@ -623,6 +632,8 @@ static int readPrefixes(struct InternalInstruction* insn) {
return 0;
}
+static int readModRM(struct InternalInstruction* insn);
+
/*
* readOpcode - Reads the opcode (excepting the ModR/M byte in the case of
* extended or escape opcodes).
@@ -715,6 +726,17 @@ static int readOpcode(struct InternalInstruction* insn) {
return -1;
insn->opcodeType = THREEBYTE_3A;
+ } else if (current == 0x0f) {
+ dbgprintf(insn, "Found a 3dnow escape prefix (0x%hhx)", current);
+
+ // Consume operands before the opcode to comply with the 3DNow encoding
+ if (readModRM(insn))
+ return -1;
+
+ if (consumeByte(insn, &current))
+ return -1;
+
+ insn->opcodeType = THREEDNOW_MAP;
} else {
dbgprintf(insn, "Didn't find a three-byte escape prefix");
@@ -735,8 +757,6 @@ static int readOpcode(struct InternalInstruction* insn) {
return 0;
}
-static int readModRM(struct InternalInstruction* insn);
-
/*
* getIDWithAttrMask - Determines the ID of an instruction, consuming
* the ModR/M byte as appropriate for extended and escape opcodes,
@@ -947,6 +967,7 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
attrMask |= ATTR_ADSIZE;
break;
}
+
}
if (insn->rexPrefix & 0x08) {
@@ -1039,13 +1060,15 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
}
/*
- * Absolute moves need special handling.
+ * Absolute moves, umonitor, and movdir64b need special handling.
* -For 16-bit mode because the meaning of the AdSize and OpSize prefixes are
* inverted w.r.t.
* -For 32-bit mode we need to ensure the ADSIZE prefix is observed in
* any position.
*/
- if (insn->opcodeType == ONEBYTE && ((insn->opcode & 0xFC) == 0xA0)) {
+ if ((insn->opcodeType == ONEBYTE && ((insn->opcode & 0xFC) == 0xA0)) ||
+ (insn->opcodeType == TWOBYTE && (insn->opcode == 0xAE)) ||
+ (insn->opcodeType == THREEBYTE_38 && insn->opcode == 0xF8)) {
/* Make sure we observed the prefixes in any position. */
if (insn->hasAdSize)
attrMask |= ATTR_ADSIZE;
@@ -1053,8 +1076,13 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) {
attrMask |= ATTR_OPSIZE;
/* In 16-bit, invert the attributes. */
- if (insn->mode == MODE_16BIT)
- attrMask ^= ATTR_ADSIZE | ATTR_OPSIZE;
+ if (insn->mode == MODE_16BIT) {
+ attrMask ^= ATTR_ADSIZE;
+
+ /* The OpSize attribute is only valid with the absolute moves. */
+ if (insn->opcodeType == ONEBYTE && ((insn->opcode & 0xFC) == 0xA0))
+ attrMask ^= ATTR_OPSIZE;
+ }
if (getIDWithAttrMask(&instructionID, insn, attrMask))
return -1;
@@ -1279,7 +1307,7 @@ static int readDisplacement(struct InternalInstruction* insn) {
* @return - 0 if the information was successfully read; nonzero otherwise.
*/
static int readModRM(struct InternalInstruction* insn) {
- uint8_t mod, rm, reg;
+ uint8_t mod, rm, reg, evexrm;
dbgprintf(insn, "readModRM()");
@@ -1316,16 +1344,18 @@ static int readModRM(struct InternalInstruction* insn) {
reg |= rFromREX(insn->rexPrefix) << 3;
rm |= bFromREX(insn->rexPrefix) << 3;
- if (insn->vectorExtensionType == TYPE_EVEX) {
+
+ evexrm = 0;
+ if (insn->vectorExtensionType == TYPE_EVEX && insn->mode == MODE_64BIT) {
reg |= r2FromEVEX2of4(insn->vectorExtensionPrefix[1]) << 4;
- rm |= xFromEVEX2of4(insn->vectorExtensionPrefix[1]) << 4;
+ evexrm = xFromEVEX2of4(insn->vectorExtensionPrefix[1]) << 4;
}
insn->reg = (Reg)(insn->regBase + reg);
switch (insn->addressSize) {
- case 2:
- insn->eaBaseBase = EA_BASE_BX_SI;
+ case 2: {
+ EABase eaBaseBase = EA_BASE_BX_SI;
switch (mod) {
case 0x0:
@@ -1335,19 +1365,19 @@ static int readModRM(struct InternalInstruction* insn) {
if (readDisplacement(insn))
return -1;
} else {
- insn->eaBase = (EABase)(insn->eaBaseBase + rm);
+ insn->eaBase = (EABase)(eaBaseBase + rm);
insn->eaDisplacement = EA_DISP_NONE;
}
break;
case 0x1:
- insn->eaBase = (EABase)(insn->eaBaseBase + rm);
+ insn->eaBase = (EABase)(eaBaseBase + rm);
insn->eaDisplacement = EA_DISP_8;
insn->displacementSize = 1;
if (readDisplacement(insn))
return -1;
break;
case 0x2:
- insn->eaBase = (EABase)(insn->eaBaseBase + rm);
+ insn->eaBase = (EABase)(eaBaseBase + rm);
insn->eaDisplacement = EA_DISP_16;
if (readDisplacement(insn))
return -1;
@@ -1359,9 +1389,10 @@ static int readModRM(struct InternalInstruction* insn) {
break;
}
break;
+ }
case 4:
- case 8:
- insn->eaBaseBase = (insn->addressSize == 4 ? EA_BASE_EAX : EA_BASE_RAX);
+ case 8: {
+ EABase eaBaseBase = (insn->addressSize == 4 ? EA_BASE_EAX : EA_BASE_RAX);
switch (mod) {
case 0x0:
@@ -1383,7 +1414,7 @@ static int readModRM(struct InternalInstruction* insn) {
return -1;
break;
default:
- insn->eaBase = (EABase)(insn->eaBaseBase + rm);
+ insn->eaBase = (EABase)(eaBaseBase + rm);
break;
}
break;
@@ -1399,7 +1430,7 @@ static int readModRM(struct InternalInstruction* insn) {
return -1;
break;
default:
- insn->eaBase = (EABase)(insn->eaBaseBase + rm);
+ insn->eaBase = (EABase)(eaBaseBase + rm);
if (readDisplacement(insn))
return -1;
break;
@@ -1407,16 +1438,17 @@ static int readModRM(struct InternalInstruction* insn) {
break;
case 0x3:
insn->eaDisplacement = EA_DISP_NONE;
- insn->eaBase = (EABase)(insn->eaRegBase + rm);
+ insn->eaBase = (EABase)(insn->eaRegBase + rm + evexrm);
break;
}
break;
+ }
} /* switch (insn->addressSize) */
return 0;
}
-#define GENERIC_FIXUP_FUNC(name, base, prefix) \
+#define GENERIC_FIXUP_FUNC(name, base, prefix, mask) \
static uint16_t name(struct InternalInstruction *insn, \
OperandType type, \
uint8_t index, \
@@ -1430,6 +1462,9 @@ static int readModRM(struct InternalInstruction* insn) {
case TYPE_Rv: \
return base + index; \
case TYPE_R8: \
+ index &= mask; \
+ if (index > 0xf) \
+ *valid = 0; \
if (insn->rexPrefix && \
index >= 4 && index <= 7) { \
return prefix##_SPL + (index - 4); \
@@ -1437,10 +1472,19 @@ static int readModRM(struct InternalInstruction* insn) {
return prefix##_AL + index; \
} \
case TYPE_R16: \
+ index &= mask; \
+ if (index > 0xf) \
+ *valid = 0; \
return prefix##_AX + index; \
case TYPE_R32: \
+ index &= mask; \
+ if (index > 0xf) \
+ *valid = 0; \
return prefix##_EAX + index; \
case TYPE_R64: \
+ index &= mask; \
+ if (index > 0xf) \
+ *valid = 0; \
return prefix##_RAX + index; \
case TYPE_ZMM: \
return prefix##_ZMM0 + index; \
@@ -1449,6 +1493,7 @@ static int readModRM(struct InternalInstruction* insn) {
case TYPE_XMM: \
return prefix##_XMM0 + index; \
case TYPE_VK: \
+ index &= 0xf; \
if (index > 7) \
*valid = 0; \
return prefix##_K0 + index; \
@@ -1488,8 +1533,8 @@ static int readModRM(struct InternalInstruction* insn) {
* field is valid for the register class; 0 if not.
* @return - The proper value.
*/
-GENERIC_FIXUP_FUNC(fixupRegValue, insn->regBase, MODRM_REG)
-GENERIC_FIXUP_FUNC(fixupRMValue, insn->eaRegBase, EA_REG)
+GENERIC_FIXUP_FUNC(fixupRegValue, insn->regBase, MODRM_REG, 0x1f)
+GENERIC_FIXUP_FUNC(fixupRMValue, insn->eaRegBase, EA_REG, 0xf)
/*
* fixupReg - Consults an operand specifier to determine which of the
@@ -1670,7 +1715,7 @@ static int readVVVV(struct InternalInstruction* insn) {
return -1;
if (insn->mode != MODE_64BIT)
- vvvv &= 0x7;
+ vvvv &= 0xf; // Can only clear bit 4. Bit 3 must be cleared later.
insn->vvvv = static_cast<Reg>(vvvv);
return 0;
@@ -1731,10 +1776,10 @@ static int readOperands(struct InternalInstruction* insn) {
// If sibIndex was set to SIB_INDEX_NONE, index offset is 4.
if (insn->sibIndex == SIB_INDEX_NONE)
- insn->sibIndex = (SIBIndex)4;
+ insn->sibIndex = (SIBIndex)(insn->sibIndexBase + 4);
// If EVEX.v2 is set this is one of the 16-31 registers.
- if (insn->vectorExtensionType == TYPE_EVEX &&
+ if (insn->vectorExtensionType == TYPE_EVEX && insn->mode == MODE_64BIT &&
v2FromEVEX4of4(insn->vectorExtensionPrefix[3]))
insn->sibIndex = (SIBIndex)(insn->sibIndex + 16);
@@ -1835,6 +1880,8 @@ static int readOperands(struct InternalInstruction* insn) {
needVVVV = 0; /* Mark that we have found a VVVV operand. */
if (!hasVVVV)
return -1;
+ if (insn->mode != MODE_64BIT)
+ insn->vvvv = static_cast<Reg>(insn->vvvv & 0x7);
if (fixupReg(insn, &Op))
return -1;
break;