mirror of https://github.com/x64dbg/zydis
Fixed mandatory prefixes, added prefix compatibility checks
This commit is contained in:
parent
cb98db80ea
commit
1faec66a66
|
@ -77,12 +77,41 @@ typedef struct ZydisEncoderTableEntry_
|
||||||
uint8_t operandCount;
|
uint8_t operandCount;
|
||||||
ZydisEncoderTableOperand operands[5];
|
ZydisEncoderTableOperand operands[5];
|
||||||
ZydisOpcodeMap map;
|
ZydisOpcodeMap map;
|
||||||
ZydisInstructionAttributes mandatoryAttribs;
|
ZydisInstructionAttributes attribs;
|
||||||
ZydisModRMMod modRmMod;
|
ZydisModRMMod modRmMod;
|
||||||
ZydisModeConstraint modeConstraint;
|
ZydisModeConstraint modeConstraint;
|
||||||
ZydisPrefixBit prefixBits;
|
ZydisPrefixBit prefixBits;
|
||||||
|
uint8_t mandatoryPrefix; // 0x00 = None
|
||||||
} ZydisEncoderTableEntry;
|
} ZydisEncoderTableEntry;
|
||||||
|
|
||||||
|
struct ZydisPrefixAcceptMapping
|
||||||
|
{
|
||||||
|
uint64_t has;
|
||||||
|
uint64_t accepts;
|
||||||
|
} static const prefixAcceptMap[] =
|
||||||
|
{
|
||||||
|
{ ZYDIS_ATTRIB_HAS_LOCK, ZYDIS_ATTRIB_ACCEPTS_LOCK },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_REP, ZYDIS_ATTRIB_ACCEPTS_REP },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_REPE, ZYDIS_ATTRIB_ACCEPTS_REPE },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_REPZ, ZYDIS_ATTRIB_ACCEPTS_REPZ },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_REPNE, ZYDIS_ATTRIB_ACCEPTS_REPNE },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_REPNZ, ZYDIS_ATTRIB_ACCEPTS_REPNZ },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_BOUND, ZYDIS_ATTRIB_ACCEPTS_BOUND },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_XACQUIRE, ZYDIS_ATTRIB_ACCEPTS_XACQUIRE },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_XRELEASE, ZYDIS_ATTRIB_ACCEPTS_XRELEASE },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN, ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_BRANCH_TAKEN, ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_CS, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_SS, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_DS, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_ES, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_FS, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_GS, ZYDIS_ATTRIB_ACCEPTS_SEGMENT },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_OPERANDSIZE, ZYDIS_ATTRIB_ACCEPTS_OPERANDSIZE },
|
||||||
|
{ ZYDIS_ATTRIB_HAS_ADDRESSSIZE, ZYDIS_ATTRIB_ACCEPTS_ADDRESSSIZE },
|
||||||
|
};
|
||||||
|
|
||||||
#include <Zydis/Internal/EncoderTable.inc>
|
#include <Zydis/Internal/EncoderTable.inc>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,6 +124,8 @@ typedef struct ZydisEncoderContext_
|
||||||
size_t writeOffs;
|
size_t writeOffs;
|
||||||
ZydisInstructionInfo* info;
|
ZydisInstructionInfo* info;
|
||||||
const ZydisEncoderTableEntry* matchingEntry;
|
const ZydisEncoderTableEntry* matchingEntry;
|
||||||
|
ZydisBool shouldEmitMandatoryPrefix;
|
||||||
|
uint8_t mandatoryPrefix;
|
||||||
uint8_t dispBitSize;
|
uint8_t dispBitSize;
|
||||||
uint64_t disp;
|
uint64_t disp;
|
||||||
uint8_t immBitSizes[2];
|
uint8_t immBitSizes[2];
|
||||||
|
@ -219,9 +250,9 @@ static ZydisStatus ZydisEmitVEX(ZydisEncoderContext* ctx)
|
||||||
ZYDIS_ASSERT(ctx);
|
ZYDIS_ASSERT(ctx);
|
||||||
|
|
||||||
// Can we use short 2-byte VEX encoding?
|
// Can we use short 2-byte VEX encoding?
|
||||||
if (ctx->info->details.vex.X == 1 &&
|
if (ctx->info->details.vex.X == 1 &&
|
||||||
ctx->info->details.vex.B == 1 &&
|
ctx->info->details.vex.B == 1 &&
|
||||||
ctx->info->details.vex.W == 0 &&
|
ctx->info->details.vex.W == 0 &&
|
||||||
ctx->info->details.vex.m_mmmm == 1)
|
ctx->info->details.vex.m_mmmm == 1)
|
||||||
{
|
{
|
||||||
ZYDIS_CHECK(ZydisEmitByte(ctx, 0xC5));
|
ZYDIS_CHECK(ZydisEmitByte(ctx, 0xC5));
|
||||||
|
@ -424,7 +455,6 @@ static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx,
|
||||||
ZydisRegister reg, char topBitLoc)
|
ZydisRegister reg, char topBitLoc)
|
||||||
{
|
{
|
||||||
int16_t regID = ZydisRegisterGetId(reg);
|
int16_t regID = ZydisRegisterGetId(reg);
|
||||||
//ZydisRegisterClass clazz = ZydisRegisterGetClass(reg);
|
|
||||||
if (regID == -1) return ZYDIS_STATUS_INVALID_PARAMETER;
|
if (regID == -1) return ZYDIS_STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
uint8_t lowerBits = (regID & 0x07) >> 0;
|
uint8_t lowerBits = (regID & 0x07) >> 0;
|
||||||
|
@ -779,6 +809,42 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx,
|
||||||
return ZYDIS_STATUS_SUCCESS;
|
return ZYDIS_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ZydisStatus ZydisPrepareMandatoryPrefixes(ZydisEncoderContext* ctx)
|
||||||
|
{
|
||||||
|
// Is a prefix mandatory? 0x00 is a sentinel value for `None` in the table.
|
||||||
|
if (ctx->matchingEntry->mandatoryPrefix != 0x00)
|
||||||
|
{
|
||||||
|
uint8_t bitCompressedPrefix = 0x00;
|
||||||
|
switch (ctx->matchingEntry->mandatoryPrefix)
|
||||||
|
{
|
||||||
|
case 0x66: bitCompressedPrefix = 0x01; break;
|
||||||
|
case 0xF3: bitCompressedPrefix = 0x02; break;
|
||||||
|
case 0xF2: bitCompressedPrefix = 0x03; break;
|
||||||
|
default: ZYDIS_UNREACHABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx->info->encoding)
|
||||||
|
{
|
||||||
|
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
|
||||||
|
case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
|
||||||
|
ctx->shouldEmitMandatoryPrefix = ZYDIS_TRUE;
|
||||||
|
ctx->mandatoryPrefix = ctx->matchingEntry->mandatoryPrefix;
|
||||||
|
break;
|
||||||
|
case ZYDIS_INSTRUCTION_ENCODING_VEX:
|
||||||
|
ctx->info->details.vex.pp = bitCompressedPrefix;
|
||||||
|
break;
|
||||||
|
case ZYDIS_INSTRUCTION_ENCODING_EVEX:
|
||||||
|
ctx->info->details.evex.pp = bitCompressedPrefix;
|
||||||
|
break;
|
||||||
|
case ZYDIS_INSTRUCTION_ENCODING_XOP:
|
||||||
|
ctx->info->details.xop.pp = bitCompressedPrefix;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZYDIS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static ZydisStatus ZydisDeriveEncodingForOp(ZydisOperandDefinition* operand)
|
static ZydisStatus ZydisDeriveEncodingForOp(ZydisOperandDefinition* operand)
|
||||||
{
|
{
|
||||||
switch (operand->type)
|
switch (operand->type)
|
||||||
|
@ -863,9 +929,20 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
|
||||||
// encoded, what prefixes are required, etc.
|
// encoded, what prefixes are required, etc.
|
||||||
ZYDIS_CHECK(ZydisFindMatchingDef(info, &ctx.matchingEntry));
|
ZYDIS_CHECK(ZydisFindMatchingDef(info, &ctx.matchingEntry));
|
||||||
info->opcode = ctx.matchingEntry->opcode;
|
info->opcode = ctx.matchingEntry->opcode;
|
||||||
info->attributes |= ctx.matchingEntry->mandatoryAttribs;
|
|
||||||
|
|
||||||
// TODO: Check compatibility of requested prefixes to found instruction.
|
// Check compatibility of requested prefixes to found instruction.
|
||||||
|
if (ctx.info->attributes)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ZYDIS_ARRAY_SIZE(prefixAcceptMap); ++i)
|
||||||
|
{
|
||||||
|
if (ctx.info->attributes & prefixAcceptMap[i].has &&
|
||||||
|
!(ctx.matchingEntry->attribs & prefixAcceptMap[i].accepts))
|
||||||
|
{
|
||||||
|
// TODO: Better status.
|
||||||
|
return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Determine required prefixes.
|
// Determine required prefixes.
|
||||||
switch (ctx.matchingEntry->encoding)
|
switch (ctx.matchingEntry->encoding)
|
||||||
|
@ -887,6 +964,7 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
|
||||||
info->details.evex.L2 = (pb & ZYDIS_PREFBIT_EVEX_L2) ? 1 : 0;
|
info->details.evex.L2 = (pb & ZYDIS_PREFBIT_EVEX_L2) ? 1 : 0;
|
||||||
info->details.vex.L = (pb & ZYDIS_PREFBIT_VEX_L ) ? 1 : 0;
|
info->details.vex.L = (pb & ZYDIS_PREFBIT_VEX_L ) ? 1 : 0;
|
||||||
info->details.rex.W = (pb & ZYDIS_PREFBIT_REX_W ) ? 1 : 0;
|
info->details.rex.W = (pb & ZYDIS_PREFBIT_REX_W ) ? 1 : 0;
|
||||||
|
ZYDIS_CHECK(ZydisPrepareMandatoryPrefixes(&ctx));
|
||||||
|
|
||||||
// Prepare opcode.
|
// Prepare opcode.
|
||||||
ZYDIS_CHECK(ZydisPrepareOpcode(&ctx));
|
ZYDIS_CHECK(ZydisPrepareOpcode(&ctx));
|
||||||
|
@ -912,6 +990,8 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
|
||||||
if (info->attributes & ZYDIS_ATTRIB_HAS_VEX ) ZYDIS_CHECK(ZydisEmitVEX (&ctx));
|
if (info->attributes & ZYDIS_ATTRIB_HAS_VEX ) ZYDIS_CHECK(ZydisEmitVEX (&ctx));
|
||||||
if (info->attributes & ZYDIS_ATTRIB_HAS_EVEX ) ZYDIS_CHECK(ZydisEmitEVEX (&ctx));
|
if (info->attributes & ZYDIS_ATTRIB_HAS_EVEX ) ZYDIS_CHECK(ZydisEmitEVEX (&ctx));
|
||||||
if (info->attributes & ZYDIS_ATTRIB_HAS_XOP ) ZYDIS_CHECK(ZydisEmitXOP (&ctx));
|
if (info->attributes & ZYDIS_ATTRIB_HAS_XOP ) ZYDIS_CHECK(ZydisEmitXOP (&ctx));
|
||||||
|
|
||||||
|
if (ctx.shouldEmitMandatoryPrefix) ZYDIS_CHECK(ZydisEmitByte(&ctx, ctx.mandatoryPrefix));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < ctx.opcodeMapPrefixLen; ++i)
|
for (uint8_t i = 0; i < ctx.opcodeMapPrefixLen; ++i)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue