Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
- Fix `ZydisPopulateRegisterIds`
- Remove DFV pseudo-registers
- Remove redundant `has_dfv` flag
flobernd committed Nov 2, 2024

Verified

This commit was signed with the committer’s verified signature.
flobernd Florian Bernd
1 parent 87c68a4 commit a13c171
Showing 7 changed files with 6,139 additions and 6,166 deletions.
19 changes: 8 additions & 11 deletions include/Zydis/DecoderTypes.h
Original file line number Diff line number Diff line change
@@ -1256,7 +1256,7 @@ typedef struct ZydisDecodedInstructionAvx_
typedef struct ZydisDecodedInstructionApx_
{
/**
* Signals, if the instruction uses the extended GRP registers (R16..R31).
* Signals, if the instruction uses the extended GP registers (R16..R31).
*/
ZyanBool uses_egpr;
/**
@@ -1267,26 +1267,23 @@ typedef struct ZydisDecodedInstructionApx_
* Signals, if the APX `zero upper` functionality is enabled for the instruction.
*/
ZyanBool has_zu;
/**
* Signals, if the APX `default flags value` functionality is enabled for the instruction.
*/
ZyanBool has_dfv;
/**
* Signals, if the APX push/pop performance-hint (`PPX`) is enabled for the instruction.
*
* This flag is only valid for `push2p` and `pop2p`.
*/
ZyanBool has_ppx;
/**
* The APX default flags value (DFV).
*
* This value is only used, if `has_dfv` is set as well.
* The APX source condition code.
*/
ZydisDefaultFlagsValue default_flags;
ZydisSourceConditionCode scc;
/**
* The AVX-512 APX source condition code.
* The APX default flags value (DFV) that is assigned to the status flags when the source
* condition code `scc` evaluates to `false`.
*
* This value is only used, if `scc` is not `ZYDIS_SCC_NONE`.
*/
ZydisSourceConditionCode scc;
ZydisDefaultFlagsValue default_flags;
} ZydisDecodedInstructionApx;

/**
4 changes: 1 addition & 3 deletions include/Zydis/Internal/SharedData.h
Original file line number Diff line number Diff line change
@@ -92,12 +92,11 @@ typedef enum ZydisSemanticOperandType_
ZYDIS_SEMANTIC_OPTYPE_AGEN,
ZYDIS_SEMANTIC_OPTYPE_MOFFS,
ZYDIS_SEMANTIC_OPTYPE_MIB,
ZYDIS_SEMANTIC_OPTYPE_DFV,

/**
* Maximum value of this enum.
*/
ZYDIS_SEMANTIC_OPTYPE_MAX_VALUE = ZYDIS_SEMANTIC_OPTYPE_DFV,
ZYDIS_SEMANTIC_OPTYPE_MAX_VALUE = ZYDIS_SEMANTIC_OPTYPE_MIB,
/**
* The minimum number of bits required to represent all values of this enum.
*/
@@ -862,7 +861,6 @@ typedef struct ZydisInstructionDefinitionEVEX_
ZyanU8 is_eevex ZYAN_BITFIELD( 1);
ZyanU8 has_apx_nf ZYAN_BITFIELD( 1);
ZyanU8 has_apx_zu ZYAN_BITFIELD( 1);
ZyanU8 has_apx_dfv ZYAN_BITFIELD( 1);
ZyanU8 has_apx_ppx ZYAN_BITFIELD( 1);
} ZydisInstructionDefinitionEVEX;
#endif
9 changes: 2 additions & 7 deletions include/Zydis/Register.h
Original file line number Diff line number Diff line change
@@ -80,12 +80,11 @@ typedef enum ZydisRegisterKind_
ZYDIS_REGKIND_DEBUG,
ZYDIS_REGKIND_MASK,
ZYDIS_REGKIND_BOUND,
ZYDIS_REGKIND_DFV,

/**
* Maximum value of this enum.
*/
ZYDIS_REGKIND_MAX_VALUE = ZYDIS_REGKIND_DFV,
ZYDIS_REGKIND_MAX_VALUE = ZYDIS_REGKIND_BOUND,
/**
* The minimum number of bits required to represent all values of this enum.
*/
@@ -185,15 +184,11 @@ typedef enum ZydisRegisterClass_
* Bound registers.
*/
ZYDIS_REGCLASS_BOUND,
/**
* DFV pseudo registers.
*/
ZYDIS_REGCLASS_DFV,

/**
* Maximum value of this enum.
*/
ZYDIS_REGCLASS_MAX_VALUE = ZYDIS_REGCLASS_DFV,
ZYDIS_REGCLASS_MAX_VALUE = ZYDIS_REGCLASS_BOUND,
/**
* The minimum number of bits required to represent all values of this enum.
*/
60 changes: 30 additions & 30 deletions src/Decoder.c
Original file line number Diff line number Diff line change
@@ -1800,9 +1800,6 @@ static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDe
case ZYDIS_SEMANTIC_OPTYPE_MASK:
register_class = ZYDIS_REGCLASS_MASK;
break;
case ZYDIS_SEMANTIC_OPTYPE_DFV:
register_class = ZYDIS_REGCLASS_DFV;
break;
default:
break;
}
@@ -4503,6 +4500,7 @@ static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,
const ZyanBool is_mod_reg = context->reg_info.is_mod_reg;
const ZyanBool has_sib = !is_mod_reg && (instruction->raw.modrm.rm == 4);
const ZyanBool has_vsib = has_sib && (def_rm == ZYDIS_MEMOP_TYPE_VSIB);
const ZyanBool is_rex2 = (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_REX2);

ZyanU8 id_reg = instruction->raw.modrm.reg;
ZyanU8 id_rm = instruction->raw.modrm.rm;
@@ -4512,7 +4510,7 @@ static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,

if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
{
const ZyanBool supports_rm4 = (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_REX2) ||
const ZyanBool supports_rm4 = is_rex2 ||
(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX);

@@ -4543,39 +4541,39 @@ static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,
// The masking emulates the actual CPU behavior and does not verify if the resulting ids
// are actually valid for the given register kind.

static const ZyanU8 mask_reg[ZYDIS_REGKIND_MAX_VALUE + 1] =
const ZyanU8 non_gpr_mask = (ZyanU8)(1 << (is_rex2 ? 4 : 5)) - 1;

const ZyanU8 mask_reg[ZYDIS_REGKIND_MAX_VALUE + 1] =
{
/* INVALID */ 0,
/* GPR */ (1 << 5) - 1,
/* X87 */ (1 << 3) - 1, // ignore `R4`, ignore `R3`
/* MMX */ (1 << 3) - 1, // ignore `R4`, ignore `R3`
/* VR */ (1 << 5) - 1,
/* TMM */ (1 << 5) - 1,
/* VR */ non_gpr_mask, // ignore `REX2.R4`
/* TMM */ non_gpr_mask, // ignore `REX2.R4`
/* SEGMENT */ (1 << 3) - 1, // ignore `R4`, ignore `R3`
/* TEST */ (1 << 3) - 1, // ignore `R4`, ignore `R3`
/* CONTROL */ (1 << 5) - 1,
/* DEBUG */ (1 << 5) - 1,
/* MASK */ (1 << 5) - 1,
/* BOUND */ (1 << 4) - 1, // ignore `R4`
/* DFV */ 0
/* MASK */ non_gpr_mask, // ignore `REX2.R4`
/* BOUND */ (1 << 4) - 1 // ignore `R4`
};
id_reg &= mask_reg[def_reg];

static const ZyanU8 mask_rm[ZYDIS_REGKIND_MAX_VALUE + 1] =
const ZyanU8 mask_rm[ZYDIS_REGKIND_MAX_VALUE + 1] =
{
/* INVALID */ 0,
/* GPR */ (1 << 5) - 1, // TODO: 4 if APX is not enabled
/* X87 */ (1 << 3) - 1, // ignore `X3|B4`, ignore `B3`
/* MMX */ (1 << 3) - 1, // ignore `X3|B4`, ignore `B3`
/* VR */ (1 << 5) - 1,
/* VR */ non_gpr_mask, // ignore `REX2.B4`
/* TMM */ (1 << 4) - 1, // ignore `X3|B4`
/* SEGMENT */ (1 << 3) - 1, // ignore `X3|B4`, ignore `B3`
/* TEST */ (1 << 3) - 1, // ignore `X3|B4`, ignore `B3`
/* CONTROL */ (1 << 5) - 1,
/* DEBUG */ (1 << 5) - 1,
/* MASK */ (1 << 3) - 1, // ignore `X3|B4`, ignore `B3`
/* BOUND */ (1 << 4) - 1, // ignore `X3|B4`
/* DFV */ 0
/* BOUND */ (1 << 4) - 1 // ignore `X3|B4`
};
id_rm &= (is_mod_reg ? mask_rm[def_rm] : 0xFF);

@@ -4592,24 +4590,29 @@ static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,
/* CONTROL */ 0,
/* DEBUG */ 0,
/* MASK */ (1 << 5) - 1,
/* BOUND */ 0,
/* DFV */ (1 << 4) - 1 // ignore `V4`
/* BOUND */ 0
};
id_vvvv &= mask_vvvv[def_vvvv];
}

// Validate

// `.vvvv` is not allowed, if the instruction does not encode a NDS/NDD operand
if (!def_vvvv && context->vector_unified.vvvv)
if (instruction->apx.scc != ZYDIS_SCC_NONE)
{
return ZYDIS_STATUS_BAD_REGISTER;
}
// EEVEX SCC instructions re-use `vvvv` as the DFV value and `V4` as the MSB of the SCC
// code.

// `.V4` is not allowed, if the instruction does not encode a NDS/NDD or VSIB operand
if (!def_vvvv && !has_vsib && context->vector_unified.V4)
{
return ZYDIS_STATUS_BAD_REGISTER;
// `.vvvv` is not allowed, if the instruction does not encode a NDS/NDD operand.
if (!def_vvvv && context->vector_unified.vvvv)
{
return ZYDIS_STATUS_BAD_REGISTER;
}

// `.V4` is not allowed, if the instruction does not encode a NDS/NDD or VSIB operand
if (!def_vvvv && !has_vsib && context->vector_unified.V4)
{
return ZYDIS_STATUS_BAD_REGISTER;
}
}

static const ZyanU8 available_regs[2][ZYDIS_REGKIND_MAX_VALUE + 1] =
@@ -4627,8 +4630,7 @@ static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,
/* CONTROL */ 8,
/* DEBUG */ 8,
/* MASK */ 8,
/* BOUND */ 4,
/* DFV */ 0
/* BOUND */ 4
},
// 64 bit mode
{
@@ -4646,8 +4648,7 @@ static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,
// check this at runtime we just allow them.
/* DEBUG */ 8,
/* MASK */ 8,
/* BOUND */ 4,
/* DFV */ 16
/* BOUND */ 4
}
};

@@ -5244,9 +5245,8 @@ static ZyanStatus ZydisDecodeInstruction(ZydisDecoderState* state,
instruction->apx.has_nf = evex_definition->has_apx_nf;
instruction->apx.has_zu = evex_definition->has_apx_zu;

if (evex_definition->has_apx_dfv)
if (instruction->apx.scc != ZYDIS_SCC_NONE)
{
instruction->apx.has_dfv = ZYAN_TRUE;
instruction->apx.default_flags = state->context->vector_unified.vvvv;
}
}
12,188 changes: 6,094 additions & 6,094 deletions src/Generated/InstructionDefinitions.inc

Large diffs are not rendered by default.

16 changes: 0 additions & 16 deletions src/Generated/RegisterLookup.inc
Original file line number Diff line number Diff line change
@@ -326,22 +326,6 @@ static const ZydisRegisterLookupItem REG_LOOKUP[] =
/* BND3 */ { ZYDIS_REGCLASS_BOUND, 3, 128, 128 },
/* BNDCFG */ { ZYDIS_REGCLASS_INVALID, -1, 64, 64 },
/* BNDSTATUS */ { ZYDIS_REGCLASS_INVALID, -1, 64, 64 },
/* DFV0 */ { ZYDIS_REGCLASS_DFV, 0, 4, 4 },
/* DFV1 */ { ZYDIS_REGCLASS_DFV, 1, 4, 4 },
/* DFV2 */ { ZYDIS_REGCLASS_DFV, 2, 4, 4 },
/* DFV3 */ { ZYDIS_REGCLASS_DFV, 3, 4, 4 },
/* DFV4 */ { ZYDIS_REGCLASS_DFV, 4, 4, 4 },
/* DFV5 */ { ZYDIS_REGCLASS_DFV, 5, 4, 4 },
/* DFV6 */ { ZYDIS_REGCLASS_DFV, 6, 4, 4 },
/* DFV7 */ { ZYDIS_REGCLASS_DFV, 7, 4, 4 },
/* DFV8 */ { ZYDIS_REGCLASS_DFV, 8, 4, 4 },
/* DFV9 */ { ZYDIS_REGCLASS_DFV, 9, 4, 4 },
/* DFV10 */ { ZYDIS_REGCLASS_DFV, 10, 4, 4 },
/* DFV11 */ { ZYDIS_REGCLASS_DFV, 11, 4, 4 },
/* DFV12 */ { ZYDIS_REGCLASS_DFV, 12, 4, 4 },
/* DFV13 */ { ZYDIS_REGCLASS_DFV, 13, 4, 4 },
/* DFV14 */ { ZYDIS_REGCLASS_DFV, 14, 4, 4 },
/* DFV15 */ { ZYDIS_REGCLASS_DFV, 15, 4, 4 },
/* MXCSR */ { ZYDIS_REGCLASS_INVALID, -1, 32, 32 },
/* PKRU */ { ZYDIS_REGCLASS_INVALID, -1, 32, 32 },
/* XCR0 */ { ZYDIS_REGCLASS_INVALID, -1, 64, 64 },
9 changes: 4 additions & 5 deletions tools/ZydisInfo.c
Original file line number Diff line number Diff line change
@@ -876,8 +876,11 @@ static void PrintAPXInfo(const ZydisDecodedInstruction* instruction)
PrintSectionHeader("APX");

PRINT_VALUE_B("USES_EGPR", "%s", instruction->apx.uses_egpr ? "Y" : "N");
PRINT_VALUE_B("HAS_NF", "%s", instruction->apx.has_nf ? "Y" : "N");
PRINT_VALUE_B("HAS_ZU", "%s", instruction->apx.has_zu ? "Y" : "N");
PRINT_VALUE_B("SCC", "%s", strings_scc[instruction->apx.scc]);

if (instruction->apx.has_dfv)
if (instruction->apx.scc != ZYDIS_SCC_NONE)
{
PrintValueLabel("DFV");
ZYAN_FPUTS(CVT100_OUT(COLOR_VALUE_B), ZYAN_STDOUT);
@@ -897,10 +900,6 @@ static void PrintAPXInfo(const ZydisDecodedInstruction* instruction)

ZYAN_PUTS(CVT100_OUT(COLOR_DEFAULT));
}

PRINT_VALUE_B("HAS_NF", "%s", instruction->apx.has_nf ? "Y" : "N");
PRINT_VALUE_B("HAS_ZU", "%s", instruction->apx.has_zu ? "Y" : "N");
PRINT_VALUE_B("SCC", "%s", strings_scc[instruction->apx.scc]);
}

/**

0 comments on commit a13c171

Please sign in to comment.