Reimplemented decoding of 3DNOW instructions and improved EVEX decoding

This commit is contained in:
flobernd 2017-06-13 22:04:29 +02:00
parent 702f6b8d53
commit 6caa68b674
7 changed files with 4654 additions and 3294 deletions

View File

@ -711,14 +711,14 @@ enum ZydisVectorLengths
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisEVEXTupleType datatype.
* @brief Defines the @c ZydisTupleType datatype.
*/
typedef uint8_t ZydisEVEXTupleType;
typedef uint8_t ZydisTupleType;
/**
* @brief Values that represent EVEX tuple-types.
*/
enum ZydisEVEXTupleTypes
enum ZydisTupleTypes
{
ZYDIS_TUPLETYPE_INVALID,
/**
@ -779,6 +779,31 @@ enum ZydisEVEXTupleTypes
ZYDIS_TUPLETYPE_DUP
};
/* ---------------------------------------------------------------------------------------------- */
/* AVX mask mode */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisMaskMode datatype.
*/
typedef uint8_t ZydisMaskMode;
/**
* @brief Values that represent AVX mask-modes.
*/
enum ZydisMaskModes
{
ZYDIS_MASKMODE_INVALID,
/**
* @brief Merge mode. This is the default mode for all EVEX-instructions.
*/
ZYDIS_MASKMODE_MERGE,
/**
* @brief The zeroing mode is enabled for this instruction.
*/
ZYDIS_MASKMODE_ZERO
};
/* ---------------------------------------------------------------------------------------------- */
/* AVX broadcast-mode */
/* ---------------------------------------------------------------------------------------------- */
@ -800,6 +825,55 @@ enum ZydisBroadcastModes
ZYDIS_BROADCAST_MODE_1_TO_16
};
/* ---------------------------------------------------------------------------------------------- */
/* AVX rounding-mode */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisRoundingMode datatype.
*/
typedef uint8_t ZydisRoundingMode;
/**
* @brief Values that represent AVX rounding-modes.
*/
enum ZydisRoundingModes
{
ZYDIS_RNDMODE_INVALID,
/**
* @brief Round to nearest.
*/
ZYDIS_RNDMODE_RN,
/**
* @brief Round down.
*/
ZYDIS_RNDMODE_RD,
/**
* @brief Round up.
*/
ZYDIS_RNDMODE_RU,
/**
* @brief Round towards zero.
*/
ZYDIS_RNDMODE_RZ,
/**
* @brief Round to nearest and suppress all exceptions.
*/
ZYDIS_RNDMODE_RN_SAE,
/**
* @brief Round down and suppress all exceptions.
*/
ZYDIS_RNDMODE_RD_SAE,
/**
* @brief Round up and suppress all exceptions.
*/
ZYDIS_RNDMODE_RU_SAE,
/**
* @brief Round towards zero and suppress all exceptions.
*/
ZYDIS_RNDMODE_RZ_SAE
};
/* ---------------------------------------------------------------------------------------------- */
/* Instruction info */
/* ---------------------------------------------------------------------------------------------- */
@ -874,11 +948,34 @@ typedef struct ZydisInstructionInfo_
*/
struct
{
/**
* @brief The AVX vector-length.
*/
ZydisVectorLength vectorLength;
ZydisEVEXTupleType tupleType;
/**
* @brief The AVX tuple-type (EVEX only).
*/
ZydisTupleType tupleType;
/**
* @brief The AVX element-size.
*/
uint8_t elementSize;
/**
* @brief The scale-factor for compressed 8-bit displacement values.
*/
uint8_t compressedDisp8Scale;
/**
* @brief The AVX mask-mode.
*/
ZydisMaskMode maskMode;
/**
* @brief The AVX broadcast-mode.
*/
ZydisBroadcastMode broadcastMode;
/**
* @brief The AVX rounding-mode.
*/
ZydisRoundingMode roundingMode;
} avx;
/**
* @brief Extended info about different instruction-parts like ModRM, SIB or

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -151,10 +151,14 @@ enum ZydisInstructionTreeNodeTypes
* @brief Reference to an EVEX.b filter.
*/
ZYDIS_NODETYPE_FILTER_EVEX_B = 0x11,
/**
* @brief Reference to an EVEX.z filter.
*/
ZYDIS_NODETYPE_FILTER_EVEX_Z = 0x12,
/**
* @brief Reference to an MVEX.E filter.
*/
ZYDIS_NODETYPE_FILTER_MVEX_E = 0x12,
ZYDIS_NODETYPE_FILTER_MVEX_E = 0x13,
};
/* ---------------------------------------------------------------------------------------------- */
@ -230,6 +234,61 @@ typedef struct ZydisOperandDefinition_
/* Instruction definition */
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisEVEXFunctionality datatype.
*/
typedef uint8_t ZydisEVEXFunctionality;
/**
* @brief Values that represent EVEX-functionalities.
*/
enum ZydisEVEXFunctionalities
{
ZYDIS_EVEX_FUNC_INVALID,
/**
* @brief @c EVEX.b enables broadcast functionality.
*/
ZYDIS_EVEX_FUNC_BC,
/**
* @brief @c EVEX.b enables embedded-rounding functionality.
*/
ZYDIS_EVEX_FUNC_RC,
/**
* @brief @c EVEX.b enables sae functionality.
*/
ZYDIS_EVEX_FUNC_SAE
};
/* ---------------------------------------------------------------------------------------------- */
/**
* @brief Defines the @c ZydisMaskPolicy datatype.
*/
typedef uint8_t ZydisMaskPolicy;
/**
* @brief Values that represent AVX mask policies.
*/
enum ZydisMaskPolicies
{
ZYDIS_MASK_POLICY_INVALID,
/**
* @brief The instruction accepts mask-registers other than the default-mask (K0), but
* does not require them.
*/
ZYDIS_MASK_POLICY_ALLOWED,
/**
* @brief The instruction requires a mask-register other than the default-mask (K0).
*/
ZYDIS_MASK_POLICY_REQUIRED,
/**
* @brief The instruction does not allow a mask-register other than the default-mask (K0).
*/
ZYDIS_MASK_POLICY_FORBIDDEN
};
/* ---------------------------------------------------------------------------------------------- */
#define ZYDIS_INSTRUCTION_DEFINITION_BASE \
ZydisInstructionMnemonic mnemonic : 11; \
uint8_t operandCount : 4; \
@ -277,8 +336,10 @@ typedef struct ZydisInstructionDefinitionVEX_
typedef struct ZydisInstructionDefinitionEVEX_
{
ZYDIS_INSTRUCTION_DEFINITION_BASE;
ZydisEVEXTupleType tupleType : 4;
ZydisTupleType tupleType : 4;
uint8_t elementSize : 7;
ZydisEVEXFunctionality functionality : 2;
ZydisMaskPolicy maskPolicy : 2;
} ZydisInstructionDefinitionEVEX;
typedef struct ZydisInstructionDefinitionMVEX_

View File

@ -117,13 +117,6 @@ enum ZydisStatusCode
ZYDIS_STATUS_INVALID_MASK,
ZYDIS_STATUS_INVALID_VSIB,
/* ------------------------------------------------------------------------------------------ */
/* Encoder */
/* ------------------------------------------------------------------------------------------ */
// TODO:
ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION,
/* ------------------------------------------------------------------------------------------ */
/* Formatter */
/* ------------------------------------------------------------------------------------------ */

View File

@ -1791,15 +1791,111 @@ static void ZydisSetAVXInformation(ZydisDecoderContext* context,
(const ZydisInstructionDefinitionEVEX*)definition;
info->avx.tupleType = def->tupleType;
info->avx.elementSize = def->elementSize;
ZYDIS_ASSERT((def->elementSize == 8) || (def->elementSize == 16) ||
(def->elementSize == 32) || (def->elementSize == 64));
switch (info->avx.tupleType)
if (info->avx.tupleType)
{
case ZYDIS_TUPLETYPE_FV:
switch (info->details.evex.b)
ZYDIS_ASSERT(info->details.modrm.mod != 3);
ZYDIS_ASSERT((def->elementSize == 8) || (def->elementSize == 16) ||
(def->elementSize == 32) || (def->elementSize == 64));
info->avx.elementSize = def->elementSize;
// Compressed disp8 scale and broadcast-factor
switch (info->avx.tupleType)
{
case 0:
case ZYDIS_TUPLETYPE_FV:
switch (info->details.evex.b)
{
case 0:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 16;
break;
case 256:
info->avx.compressedDisp8Scale = 32;
break;
case 512:
info->avx.compressedDisp8Scale = 64;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case 1:
ZYDIS_ASSERT(def->functionality == ZYDIS_EVEX_FUNC_BC);
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 4;
switch (info->avx.vectorLength)
{
case 128:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_4;
break;
case 256:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_8;
break;
case 512:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_16;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
info->avx.compressedDisp8Scale = 8;
switch (info->avx.vectorLength)
{
case 128:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_2;
break;
case 256:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_4;
break;
case 512:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_HV:
ZYDIS_ASSERT(info->avx.elementSize == 32);
switch (info->details.evex.b)
{
case 0:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 8;
break;
case 256:
info->avx.compressedDisp8Scale = 16;
break;
case 512:
info->avx.compressedDisp8Scale = 32;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case 1:
info->avx.compressedDisp8Scale = 4;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_FVM:
switch (info->avx.vectorLength)
{
case 128:
@ -1815,58 +1911,77 @@ static void ZydisSetAVXInformation(ZydisDecoderContext* context,
ZYDIS_UNREACHABLE;
}
break;
case 1:
switch (context->cache.W)
case ZYDIS_TUPLETYPE_T1S:
info->avx.compressedDisp8Scale = info->avx.elementSize / 8;
break;
case ZYDIS_TUPLETYPE_T1F:
switch (info->avx.elementSize)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
case 32:
info->avx.compressedDisp8Scale = 4;
switch (info->avx.vectorLength)
{
case 128:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_4;
break;
case 256:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_8;
break;
case 512:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_16;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
case 64:
info->avx.compressedDisp8Scale = 8;
switch (info->avx.vectorLength)
{
case 128:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_2;
break;
case 256:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_4;
break;
case 512:
info->avx.broadcastMode = ZYDIS_BROADCAST_MODE_1_TO_8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_HV:
ZYDIS_ASSERT(info->avx.elementSize == 32);
switch (info->details.evex.b)
{
case 0:
case ZYDIS_TUPLETYPE_GSCAT:
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 4;
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
info->avx.compressedDisp8Scale = 8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T2:
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 8;
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
ZYDIS_ASSERT((info->avx.vectorLength == 256) || (info->avx.vectorLength == 512));
info->avx.compressedDisp8Scale = 16;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T4:
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
ZYDIS_ASSERT((info->avx.vectorLength == 256) || (info->avx.vectorLength == 512));
info->avx.compressedDisp8Scale = 16;
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
ZYDIS_ASSERT(info->avx.vectorLength == 512);
info->avx.compressedDisp8Scale = 32;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T8:
ZYDIS_ASSERT(!context->cache.W);
ZYDIS_ASSERT(info->avx.vectorLength == 512);
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 32;
break;
case ZYDIS_TUPLETYPE_HVM:
switch (info->avx.vectorLength)
{
case 128:
@ -1882,171 +1997,74 @@ static void ZydisSetAVXInformation(ZydisDecoderContext* context,
ZYDIS_UNREACHABLE;
}
break;
case 1:
info->avx.compressedDisp8Scale = 4;
case ZYDIS_TUPLETYPE_QVM:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 4;
break;
case 256:
info->avx.compressedDisp8Scale = 8;
break;
case 512:
info->avx.compressedDisp8Scale = 16;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_FVM:
switch (info->avx.vectorLength)
{
case 128:
case ZYDIS_TUPLETYPE_OVM:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 2;
break;
case 256:
info->avx.compressedDisp8Scale = 4;
break;
case 512:
info->avx.compressedDisp8Scale = 8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_M128:
info->avx.compressedDisp8Scale = 16;
break;
case 256:
info->avx.compressedDisp8Scale = 32;
break;
case 512:
info->avx.compressedDisp8Scale = 64;
case ZYDIS_TUPLETYPE_DUP:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 8;
break;
case 256:
info->avx.compressedDisp8Scale = 32;
break;
case 512:
info->avx.compressedDisp8Scale = 64;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T1S:
info->avx.compressedDisp8Scale = info->avx.elementSize / 8;
break;
case ZYDIS_TUPLETYPE_T1F:
switch (info->avx.elementSize)
{
case 32:
info->avx.compressedDisp8Scale = 4;
break;
case 64:
info->avx.compressedDisp8Scale = 8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_GSCAT:
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 4;
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
info->avx.compressedDisp8Scale = 8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T2:
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 8;
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
ZYDIS_ASSERT((info->avx.vectorLength == 256) || (info->avx.vectorLength == 512));
info->avx.compressedDisp8Scale = 16;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T4:
switch (context->cache.W)
{
case 0:
ZYDIS_ASSERT(info->avx.elementSize == 32);
ZYDIS_ASSERT((info->avx.vectorLength == 256) || (info->avx.vectorLength == 512));
info->avx.compressedDisp8Scale = 16;
break;
case 1:
ZYDIS_ASSERT(info->avx.elementSize == 64);
ZYDIS_ASSERT(info->avx.vectorLength == 512);
info->avx.compressedDisp8Scale = 32;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_T8:
ZYDIS_ASSERT(!context->cache.W);
ZYDIS_ASSERT(info->avx.vectorLength == 512);
ZYDIS_ASSERT(info->avx.elementSize == 32);
info->avx.compressedDisp8Scale = 32;
break;
case ZYDIS_TUPLETYPE_HVM:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 8;
break;
case 256:
info->avx.compressedDisp8Scale = 16;
break;
case 512:
info->avx.compressedDisp8Scale = 32;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_QVM:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 4;
break;
case 256:
info->avx.compressedDisp8Scale = 8;
break;
case 512:
info->avx.compressedDisp8Scale = 16;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_OVM:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 2;
break;
case 256:
info->avx.compressedDisp8Scale = 4;
break;
case 512:
info->avx.compressedDisp8Scale = 8;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
case ZYDIS_TUPLETYPE_M128:
info->avx.compressedDisp8Scale = 16;
break;
case ZYDIS_TUPLETYPE_DUP:
switch (info->avx.vectorLength)
{
case 128:
info->avx.compressedDisp8Scale = 8;
break;
case 256:
info->avx.compressedDisp8Scale = 32;
break;
case 512:
info->avx.compressedDisp8Scale = 64;
break;
default:
ZYDIS_UNREACHABLE;
}
break;
default:
ZYDIS_UNREACHABLE;
} else
{
// TODO: Add tuple type
ZYDIS_ASSERT(info->details.modrm.mod == 3);
}
// TODO: Set Mask Mode
// Rounding mode
if (def->functionality == ZYDIS_EVEX_FUNC_RC)
{
info->avx.roundingMode = ZYDIS_RNDMODE_RN_SAE + context->cache.LL;
}
// Mask mode
info->avx.maskMode = ZYDIS_MASKMODE_MERGE + info->details.evex.z;
}
}
@ -2566,6 +2584,17 @@ static ZydisStatus ZydisNodeHandlerEvexB(ZydisInstructionInfo* info, uint16_t* i
return ZYDIS_STATUS_SUCCESS;
}
static ZydisStatus ZydisNodeHandlerEvexZ(ZydisInstructionInfo* info, uint16_t* index)
{
ZYDIS_ASSERT(info);
ZYDIS_ASSERT(index);
ZYDIS_ASSERT(info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
ZYDIS_ASSERT(info->details.evex.isDecoded);
*index = info->details.evex.z;
return ZYDIS_STATUS_SUCCESS;
}
static ZydisStatus ZydisNodeHandlerMvexE(ZydisInstructionInfo* info, uint16_t* index)
{
ZYDIS_ASSERT(info);
@ -2655,7 +2684,10 @@ static ZydisStatus ZydisDecodeInstruction(ZydisDecoderContext* context, ZydisIns
break;
case ZYDIS_NODETYPE_FILTER_EVEX_B:
status = ZydisNodeHandlerEvexB(info, &index);
break;
break;
case ZYDIS_NODETYPE_FILTER_EVEX_Z:
status = ZydisNodeHandlerEvexZ(info, &index);
break;
case ZYDIS_NODETYPE_FILTER_MVEX_E:
status = ZydisNodeHandlerMvexE(info, &index);
break;
@ -2674,7 +2706,18 @@ static ZydisStatus ZydisDecodeInstruction(ZydisDecoderContext* context, ZydisIns
if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
{
ZYDIS_CHECK(ZydisInputNext(context, info, &info->opcode));
// TODO: Load new instruction definition
node = ZydisInstructionTreeGetRootNode();
node = ZydisInstructionTreeGetChildNode(node, 0x0F);
node = ZydisInstructionTreeGetChildNode(node, 0x0F);
node = ZydisInstructionTreeGetChildNode(node, info->opcode);
if (node->type == ZYDIS_NODETYPE_INVALID)
{
return ZYDIS_STATUS_DECODING_ERROR;
}
ZYDIS_ASSERT(node->type == ZYDIS_NODETYPE_FILTER_MODRM_MOD_COMPACT);
node = ZydisInstructionTreeGetChildNode(
node, (info->details.modrm.mod == 0x3) ? 0 : 1);
ZydisGetInstructionDefinition(node, &definition);
}
info->mnemonic = definition->mnemonic;

View File

@ -229,6 +229,13 @@ extern const ZydisInstructionTreeNode filtersREXB[][2];
*/
extern const ZydisInstructionTreeNode filtersEVEXB[][2];
/**
* @brief Contains all EVEX.z filters.
*
* Indexed by the numeric value of the EVEX.z field.
*/
extern const ZydisInstructionTreeNode filtersEVEXZ[][2];
/**
* @brief Contains all MVEX.E filters.
*
@ -383,6 +390,9 @@ const ZydisInstructionTreeNode* ZydisInstructionTreeGetChildNode(
case ZYDIS_NODETYPE_FILTER_EVEX_B:
ZYDIS_ASSERT(index < 2);
return &filtersEVEXB[parent->value][index];
case ZYDIS_NODETYPE_FILTER_EVEX_Z:
ZYDIS_ASSERT(index < 2);
return &filtersEVEXZ[parent->value][index];
case ZYDIS_NODETYPE_FILTER_MVEX_E:
ZYDIS_ASSERT(index < 2);
return &filtersMVEXE[parent->value][index];