More clean-up in the encoder

This commit is contained in:
Joel Höner 2017-07-10 14:34:25 +02:00
parent 8fa80f0b86
commit 3498a33944
3 changed files with 171 additions and 197 deletions

View File

@ -63,6 +63,10 @@ enum ZydisStatusCode
* @brief An attempt was made to perform an invalid operation. * @brief An attempt was made to perform an invalid operation.
*/ */
ZYDIS_STATUS_INVALID_OPERATION, ZYDIS_STATUS_INVALID_OPERATION,
/**
* @brief A buffer passed to a function was too small to complete the requested operation.
*/
ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE,
/* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */
/* Decoder */ /* Decoder */
@ -123,15 +127,6 @@ enum ZydisStatusCode
ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION, ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION,
/* ------------------------------------------------------------------------------------------ */
/* Formatter */
/* ------------------------------------------------------------------------------------------ */
/**
* @brief A buffer passed to a function was too small to complete the requested operation.
*/
ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE,
/* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */
/* Misc */ /* Misc */
/* ------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------ */

View File

@ -25,7 +25,8 @@
***************************************************************************************************/ ***************************************************************************************************/
#include <Zydis/Encoder.h> #include <Zydis/Encoder.h>
#include <InstructionTable.h> #include <SharedData.h>
#include <EncoderData.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
@ -34,59 +35,6 @@
/* Internal context and table types */ /* Internal context and table types */
/* ============================================================================================== */ /* ============================================================================================== */
typedef struct ZydisEncoderTableOperand_
{
ZydisOperandEncoding encoding;
ZydisSemanticOperandType type;
} ZydisEncoderTableOperand;
typedef uint8_t ZydisModRMMod;
enum ZydisModRMMods
{
ZYDIS_MODRM_MOD_NONE,
ZYDIS_MODRM_MOD_REGISTER,
ZYDIS_MODRM_MOD_MEMORY,
};
typedef uint8_t ZydisModeConstraint;
enum ZydisModeConstraints
{
ZYDIS_MODE_CONSTR_NONE,
ZYDIS_MODE_CONSTR_EXCLUDE64,
ZYDIS_MODE_CONSTR_REQUIRE64,
};
typedef uint8_t ZydisPrefixBit;
enum ZydisPrefixBits
{
// TODO: Use defines instead?
ZYDIS_PREFBIT_VEX_L = 0x01,
ZYDIS_PREFBIT_REX_W = 0x02,
ZYDIS_PREFBIT_EVEX_L2 = 0x04,
ZYDIS_PREFBIT_EVEX_B = 0x08,
};
typedef struct ZydisEncoderTableEntry_
{
uint16_t mnemonic;
uint8_t opcode;
ZydisInstructionEncoding encoding;
uint8_t operandCount;
ZydisEncoderTableOperand operands[5];
ZydisOpcodeMap map;
ZydisInstructionAttributes attribs;
ZydisModeConstraint modeConstraint;
ZydisPrefixBit prefixBits;
uint8_t mandatoryPrefix; // 0x00 = None
uint8_t modrmReg; // 0xFF = None
const char* cmt;
} ZydisEncoderTableEntry;
#include <Generated/EncoderTable.inc>
struct ZydisPrefixAcceptMapping struct ZydisPrefixAcceptMapping
{ {
uint64_t has; uint64_t has;
@ -124,8 +72,11 @@ typedef struct ZydisEncoderContext_
size_t bufferLen; size_t bufferLen;
size_t writeOffs; size_t writeOffs;
ZydisEncoderRequest* req; ZydisEncoderRequest* req;
const ZydisEncoderTableEntry* matchingEntry; const ZydisEncodableInstruction* matchingInsn;
ZydisBool shouldEmitMandatoryPrefix; const ZydisInstructionDefinition* matchingDef;
uint8_t matchingOperandCount;
const ZydisOperandDefinition* matchingOperands;
ZydisBool emitMandatoryPrefix;
uint8_t mandatoryPrefix; uint8_t mandatoryPrefix;
uint8_t dispBitSize; uint8_t dispBitSize;
uint64_t disp; uint64_t disp;
@ -466,14 +417,15 @@ static ZydisStatus ZydisEmitSIB(ZydisEncoderContext* ctx)
static ZydisStatus ZydisPrepareOpcode(ZydisEncoderContext* ctx) static ZydisStatus ZydisPrepareOpcode(ZydisEncoderContext* ctx)
{ {
ZYDIS_ASSERT(ctx); ZYDIS_ASSERT(ctx);
ZYDIS_ASSERT(ctx->matchingEntry); ZYDIS_ASSERT(ctx->matchingDef);
ZYDIS_ASSERT(ctx->req);
// Put opcode map prefix(es), if required. // Put opcode map prefix(es), if required.
switch (ctx->req->encoding) switch (ctx->req->encoding)
{ {
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT: case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
case ZYDIS_INSTRUCTION_ENCODING_3DNOW: case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
switch (ctx->matchingEntry->map) switch (ctx->matchingInsn->opcodeMap)
{ {
case ZYDIS_OPCODE_MAP_0F: case ZYDIS_OPCODE_MAP_0F:
ctx->opcodeMapPrefix[ctx->opcodeMapPrefixLen++] = 0x0F; ctx->opcodeMapPrefix[ctx->opcodeMapPrefixLen++] = 0x0F;
@ -493,16 +445,16 @@ static ZydisStatus ZydisPrepareOpcode(ZydisEncoderContext* ctx)
} }
break; break;
case ZYDIS_INSTRUCTION_ENCODING_VEX: case ZYDIS_INSTRUCTION_ENCODING_VEX:
ctx->raw.vex.m_mmmm = ctx->matchingEntry->map; ctx->raw.vex.m_mmmm = ctx->matchingInsn->opcodeMap;
ZYDIS_ASSERT(ctx->raw.vex.m_mmmm <= 0x03); ZYDIS_ASSERT(ctx->raw.vex.m_mmmm <= 0x03);
break; break;
case ZYDIS_INSTRUCTION_ENCODING_EVEX: case ZYDIS_INSTRUCTION_ENCODING_EVEX:
ctx->raw.evex.mm = ctx->matchingEntry->map; ctx->raw.evex.mm = ctx->matchingInsn->opcodeMap;
ZYDIS_ASSERT(ctx->raw.evex.mm <= 0x03); ZYDIS_ASSERT(ctx->raw.evex.mm <= 0x03);
break; break;
case ZYDIS_INSTRUCTION_ENCODING_XOP: case ZYDIS_INSTRUCTION_ENCODING_XOP:
ctx->raw.xop.m_mmmm = ctx->raw.xop.m_mmmm =
ctx->matchingEntry->map - ZYDIS_OPCODE_MAP_XOP8 + 0x08; ctx->matchingInsn->opcodeMap - ZYDIS_OPCODE_MAP_XOP8 + 0x08;
ZYDIS_ASSERT(ctx->raw.xop.m_mmmm >= 0x08); ZYDIS_ASSERT(ctx->raw.xop.m_mmmm >= 0x08);
ZYDIS_ASSERT(ctx->raw.xop.m_mmmm <= 0x0B); ZYDIS_ASSERT(ctx->raw.xop.m_mmmm <= 0x0B);
break; break;
@ -513,14 +465,6 @@ static ZydisStatus ZydisPrepareOpcode(ZydisEncoderContext* ctx)
return ZYDIS_STATUS_SUCCESS; return ZYDIS_STATUS_SUCCESS;
} }
static ZydisStatus ZydisSimplifyOperandType(ZydisSemanticOperandType semType,
ZydisOperandType* simpleType)
{
ZYDIS_ASSERT(simpleType);
return ZYDIS_STATUS_SUCCESS;
}
static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx, static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx,
ZydisRegister reg, char topBitLoc) ZydisRegister reg, char topBitLoc)
{ {
@ -543,16 +487,15 @@ static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx,
// No top bit? Quick exit. // No top bit? Quick exit.
if (!topBit) return ZYDIS_STATUS_SUCCESS; if (!topBit) return ZYDIS_STATUS_SUCCESS;
uint8_t* topBitDst = NULL;
switch (ctx->req->encoding) switch (ctx->req->encoding)
{ {
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT: case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
case ZYDIS_INSTRUCTION_ENCODING_3DNOW: case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
switch (topBitLoc) switch (topBitLoc)
{ {
case 'B': topBitDst = &ctx->raw.rex.B; break; case 'B': ctx->raw.rex.B = topBit; break;
case 'R': topBitDst = &ctx->raw.rex.R; break; case 'R': ctx->raw.rex.R = topBit; break;
case 'X': topBitDst = &ctx->raw.rex.X; break; case 'X': ctx->raw.rex.X = topBit; break;
default: ZYDIS_UNREACHABLE; default: ZYDIS_UNREACHABLE;
} }
if (topBit) ctx->req->attributes |= ZYDIS_ATTRIB_HAS_REX; if (topBit) ctx->req->attributes |= ZYDIS_ATTRIB_HAS_REX;
@ -560,27 +503,27 @@ static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx,
case ZYDIS_INSTRUCTION_ENCODING_VEX: case ZYDIS_INSTRUCTION_ENCODING_VEX:
switch (topBitLoc) switch (topBitLoc)
{ {
case 'B': topBitDst = &ctx->raw.vex.B; break; case 'B': ctx->raw.vex.B = topBit; break;
case 'R': topBitDst = &ctx->raw.vex.R; break; case 'R': ctx->raw.vex.R = topBit; break;
case 'X': topBitDst = &ctx->raw.vex.X; break; case 'X': ctx->raw.vex.X = topBit; break;
default: ZYDIS_UNREACHABLE; default: ZYDIS_UNREACHABLE;
} }
break; break;
case ZYDIS_INSTRUCTION_ENCODING_XOP: case ZYDIS_INSTRUCTION_ENCODING_XOP:
switch (topBitLoc) switch (topBitLoc)
{ {
case 'B': topBitDst = &ctx->raw.xop.B; break; case 'B': ctx->raw.xop.B = topBit; break;
case 'R': topBitDst = &ctx->raw.xop.R; break; case 'R': ctx->raw.xop.R = topBit; break;
case 'X': topBitDst = &ctx->raw.xop.X; break; case 'X': ctx->raw.xop.X = topBit; break;
default: ZYDIS_UNREACHABLE; default: ZYDIS_UNREACHABLE;
} }
break; break;
case ZYDIS_INSTRUCTION_ENCODING_EVEX: case ZYDIS_INSTRUCTION_ENCODING_EVEX:
switch (topBitLoc) switch (topBitLoc)
{ {
case 'B': topBitDst = &ctx->raw.evex.B; break; case 'B': ctx->raw.evex.B = topBit; break;
case 'R': topBitDst = &ctx->raw.evex.R; break; case 'R': ctx->raw.evex.R = topBit; break;
case 'X': topBitDst = &ctx->raw.evex.X; break; case 'X': ctx->raw.evex.X = topBit; break;
default: ZYDIS_UNREACHABLE; default: ZYDIS_UNREACHABLE;
} }
break; break;
@ -588,8 +531,6 @@ static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx,
return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO
} }
*topBitDst = topBit;
return ZYDIS_STATUS_SUCCESS; return ZYDIS_STATUS_SUCCESS;
} }
@ -659,11 +600,12 @@ static ZydisStatus ZydisPrepareSegmentPrefix(ZydisEncoderContext* ctx,
} }
static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx,
ZydisEncoderOperand* operand, const ZydisEncoderTableOperand* tableEntry) ZydisEncoderOperand* operand, const ZydisOperandDefinition* operandDef)
{ {
ZYDIS_ASSERT(ctx); ZYDIS_ASSERT(ctx);
ZYDIS_ASSERT(ctx->req);
ZYDIS_ASSERT(operand); ZYDIS_ASSERT(operand);
ZYDIS_ASSERT(tableEntry); ZYDIS_ASSERT(operandDef);
ZYDIS_CHECK(ZydisPrepareSegmentPrefix(ctx, operand->mem.segment, operand->mem.base)); ZYDIS_CHECK(ZydisPrepareSegmentPrefix(ctx, operand->mem.segment, operand->mem.base));
@ -821,33 +763,29 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx,
} }
static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx,
ZydisEncoderOperand* operand, const ZydisEncoderTableOperand* tableEntry) ZydisEncoderOperand* operand, const ZydisOperandDefinition* operandDef)
{ {
ZYDIS_ASSERT(ctx); ZYDIS_ASSERT(ctx);
ZYDIS_ASSERT(operand); ZYDIS_ASSERT(operand);
ZYDIS_ASSERT(tableEntry); ZYDIS_ASSERT(operandDef);
ZYDIS_ASSERT(operandDef->type != ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG);
ZYDIS_ASSERT(operandDef->type != ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_MEM);
ZYDIS_ASSERT(operandDef->type != ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1);
switch (tableEntry->encoding) switch (operandDef->op.encoding)
{ {
case ZYDIS_OPERAND_ENCODING_NONE: case ZYDIS_OPERAND_ENCODING_NONE:
{
// For some encodings, we have to switch on the sem op type. // For some encodings, we have to switch on the sem op type.
// TODO if (operandDef->type == ZYDIS_SEMANTIC_OPTYPE_MOFFS)
//switch (tableEntry->type) {
//{ ZYDIS_CHECK(ZydisPrepareSegmentPrefix(
//case ZYDIS_SEM_OPERAND_TYPE_MOFFS16: ctx, operand->mem.segment, ZYDIS_REGISTER_NONE
//case ZYDIS_SEM_OPERAND_TYPE_MOFFS32: ));
//case ZYDIS_SEM_OPERAND_TYPE_MOFFS64: ctx->imms[0] = operand->mem.disp;
// ZYDIS_CHECK(ZydisPrepareSegmentPrefix( ctx->immBitSizes[0] = operand->mem.dispSize;
// ctx, operand->mem.segment, ZYDIS_REGISTER_NONE }
// )); } break;
// ctx->imms[0] = operand->mem.disp;
// ctx->immBitSizes[0] = operand->mem.dispSize;
// break;
//default:
// // Hidden operand, nothing to encode.
// break;
//}
break;
case ZYDIS_OPERAND_ENCODING_MODRM_REG: case ZYDIS_OPERAND_ENCODING_MODRM_REG:
{ {
ZYDIS_ASSERT(!ctx->raw.modrm.reg); ZYDIS_ASSERT(!ctx->raw.modrm.reg);
@ -864,7 +802,7 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx,
// Memory operand? // Memory operand?
if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY) if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY)
{ {
ZYDIS_CHECK(ZydisPrepareMemoryOperand(ctx, operand, tableEntry)); ZYDIS_CHECK(ZydisPrepareMemoryOperand(ctx, operand, operandDef));
} }
// Nope, register. // Nope, register.
else if (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) else if (operand->type == ZYDIS_OPERAND_TYPE_REGISTER)
@ -937,92 +875,113 @@ static ZydisStatus ZydisPrepareMandatoryPrefixes(ZydisEncoderContext* ctx)
ZYDIS_ASSERT(ctx); ZYDIS_ASSERT(ctx);
// Is a prefix mandatory? 0x00 is a sentinel value for `None` in the table. // Is a prefix mandatory? 0x00 is a sentinel value for `None` in the table.
if (ctx->matchingEntry->mandatoryPrefix != 0x00) uint8_t prefix = ctx->matchingInsn->mandatoryPrefix;
if (prefix != 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->req->encoding) switch (ctx->req->encoding)
{ {
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT: case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
case ZYDIS_INSTRUCTION_ENCODING_3DNOW: case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
ctx->shouldEmitMandatoryPrefix = ZYDIS_TRUE; ctx->emitMandatoryPrefix = ZYDIS_TRUE;
ctx->mandatoryPrefix = ctx->matchingEntry->mandatoryPrefix; ctx->mandatoryPrefix = prefix;
break; break;
case ZYDIS_INSTRUCTION_ENCODING_VEX: case ZYDIS_INSTRUCTION_ENCODING_VEX:
ctx->raw.vex.pp = bitCompressedPrefix; ctx->raw.vex.pp = prefix;
break; break;
case ZYDIS_INSTRUCTION_ENCODING_EVEX: case ZYDIS_INSTRUCTION_ENCODING_EVEX:
ctx->raw.evex.pp = bitCompressedPrefix; ctx->raw.evex.pp = prefix;
break; break;
case ZYDIS_INSTRUCTION_ENCODING_XOP: case ZYDIS_INSTRUCTION_ENCODING_XOP:
ctx->raw.xop.pp = bitCompressedPrefix; ctx->raw.xop.pp = prefix;
break; break;
}
}
return ZYDIS_STATUS_SUCCESS;
}
static ZydisStatus ZydisDeriveEncodingForOp(ZydisOperandDefinition* operand)
{
ZYDIS_ASSERT(operand);
switch (operand->type)
{
default: default:
return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO ZYDIS_UNREACHABLE;
}
} }
return ZYDIS_STATUS_SUCCESS; return ZYDIS_STATUS_SUCCESS;
} }
static ZydisStatus ZydisFindMatchingDef(const ZydisEncoderRequest* req, static ZydisStatus ZydisDetermineInstructionEncoding(ZydisEncoderRequest* ctx)
const ZydisEncoderTableEntry** matchingEntry)
{ {
ZYDIS_ASSERT(ctx);
for (const ZydisEncoderOperand *op = ctx->operands,
*end = ctx->operands + ctx->operandCount
; op < end
; ++op)
{
}
return ZYDIS_STATUS_SUCCESS;
}
static ZydisStatus ZydisFindMatchingDef(
ZydisEncoderContext* ctx, const ZydisEncoderRequest* req)
{
ZYDIS_ASSERT(ctx);
ZYDIS_ASSERT(req); ZYDIS_ASSERT(req);
ZYDIS_ASSERT(matchingEntry);
// Locate entries with matching mnemonic. // Translate requested mode to flags.
// TODO: Do binary search / hash based lookup instead. uint8_t modeFlag;
for (size_t i = 0; i < ZYDIS_ARRAY_SIZE(kEncoderTable); ++i) switch (req->encoding)
{ {
const ZydisEncoderTableEntry* curEntry = &kEncoderTable[i]; case 16: modeFlag = 0x01; break;
if (curEntry->mnemonic != req->mnemonic || case 32: modeFlag = 0x02; break;
curEntry->operandCount != req->operandCount || case 64: modeFlag = 0x04; break;
curEntry->encoding != req->encoding || default: return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO
(req->machineMode == 64 &&
curEntry->modeConstraint == ZYDIS_MODE_CONSTR_EXCLUDE64) ||
(req->machineMode != 64 &&
curEntry->modeConstraint == ZYDIS_MODE_CONSTR_REQUIRE64))
{
continue;
} }
// Check operands. // Walk list of candidates.
for (size_t k = 0; k < curEntry->operandCount; ++k) const ZydisEncodableInstruction* insns = NULL;
uint8_t insnCount = ZydisGetEncodableInstructions(req->mnemonic, &insns);
if (!insnCount) return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO
ZYDIS_ASSERT(insns);
for (uint8_t i = 0; i < insnCount; ++i)
{ {
// TODO: Match operand size. const ZydisEncodableInstruction* candidateInsn = insns + i;
const ZydisEncoderTableOperand* curEncoderOp = &curEntry->operands[k]; if (!(candidateInsn->mode & modeFlag)) goto _nextInsn;
const ZydisEncoderOperand* curReqOp = &req->operands[k];
if (curReqOp->encoding != curEncoderOp->encoding) goto continueTopLevel; const ZydisInstructionDefinition* candidateDef = NULL;
//ZydisOperandType simpleType; ZydisGetInstructionDefinition(
//ZYDIS_CHECK(ZydisSimplifyOperandType(curEncoderOp->type, &simpleType)); candidateInsn->encoding, insns->definitionReference, &candidateDef);
//if (curReqOp->type != simpleType) goto continueTopLevel; ZydisOperandDefinition* candidateOperands = NULL;
if (curReqOp->temp != curEncoderOp->type) goto continueTopLevel; uint8_t defOperandCount = ZydisGetOperandDefinitions(candidateDef, &candidateOperands);
if (req->operandCount > defOperandCount) goto _nextInsn;
const ZydisOperandDefinition* curDefOperand = candidateOperands;
for (uint8_t k = 0; k < req->operandCount; ++k)
{
curDefOperand = candidateOperands + k;
const ZydisEncoderOperand* curReqOperand = req->operands + k;
// Visible operands are always in the front. When we encounter the first hidden
// operand in the definition and haven't exhausted the request operands yet,
// it's safe to assume this isn't the instruction we're looking for.
if (curDefOperand->visibility == ZYDIS_OPERAND_VISIBILITY_HIDDEN) goto _nextInsn;
if (curDefOperand->type != curReqOperand->type) continue;
// blah blah more checks
} }
// Still here? We found our entry! // Make sure we compared either all operands or the remaining operands are hidden.
*matchingEntry = curEntry; if (req->operandCount != defOperandCount &&
(curDefOperand + 1)->visibility != ZYDIS_OPERAND_VISIBILITY_HIDDEN)
{
goto _nextInsn;
}
// Still here? Looks like we found our instruction, then!
ctx->matchingInsn = candidateInsn;
ctx->matchingDef = candidateDef;
ctx->matchingOperandCount = req->operandCount;
return ZYDIS_STATUS_SUCCESS; return ZYDIS_STATUS_SUCCESS;
continueTopLevel: _nextInsn:
; ;
} }
@ -1035,10 +994,29 @@ static ZydisStatus ZydisFindMatchingDef(const ZydisEncoderRequest* req,
/* Implementation of public functions */ /* Implementation of public functions */
/* ============================================================================================== */ /* ============================================================================================== */
#ifdef ZYDIS_ENABLE_FEATURE_DECODER
ZydisStatus ZydisEncoderDecodedInstructionToRequest(
const ZydisDecodedInstruction* in, ZydisEncoderRequest* out)
{
ZYDIS_ASSERT(in);
ZYDIS_ASSERT(out);
(void) in; (void) out;
// TODO
return ZYDIS_STATUS_SUCCESS;
}
#endif
ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen, ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
ZydisEncoderRequest* request) ZydisEncoderRequest* request)
{ {
if (!request || !bufferLen) return ZYDIS_STATUS_INVALID_PARAMETER; if (!request || !bufferLen || request->operandCount > ZYDIS_ARRAY_SIZE(request->operands))
{
return ZYDIS_STATUS_INVALID_PARAMETER;
}
if (!buffer || !*bufferLen) return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; if (!buffer || !*bufferLen) return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE;
ZydisEncoderContext ctx; ZydisEncoderContext ctx;
@ -1054,25 +1032,26 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
// Search matching instruction, collect information about what needs to be // Search matching instruction, collect information about what needs to be
// encoded, what prefixes are required, etc. // encoded, what prefixes are required, etc.
ZYDIS_CHECK(ZydisFindMatchingDef(request, &ctx.matchingEntry)); ZYDIS_CHECK(ZydisFindMatchingDef(&ctx, request));
ctx.raw.opcode = ctx.matchingEntry->opcode; ctx.raw.opcode = ctx.matchingInsn->opcode;
// Check compatibility of requested prefixes to found instruction. // Check compatibility of requested prefixes to found instruction.
if (ctx.req->attributes) // TODO
{ //if (ctx.req->attributes)
for (size_t i = 0; i < ZYDIS_ARRAY_SIZE(prefixAcceptMap); ++i) //{
{ // for (size_t i = 0; i < ZYDIS_ARRAY_SIZE(prefixAcceptMap); ++i)
if (ctx.req->attributes & prefixAcceptMap[i].has && // {
!(ctx.matchingEntry->attribs & prefixAcceptMap[i].accepts)) // if (ctx.req->attributes & prefixAcceptMap[i].has &&
{ // !(ctx.matchingDef->attribs & prefixAcceptMap[i].accepts))
// TODO: Better status. // {
return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // // TODO: Better status.
} // return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION;
} // }
} // }
//}
// Determine required prefixes. // Determine required prefixes.
switch (ctx.matchingEntry->encoding) switch (ctx.matchingInsn->encoding)
{ {
case ZYDIS_INSTRUCTION_ENCODING_EVEX: case ZYDIS_INSTRUCTION_ENCODING_EVEX:
request->attributes |= ZYDIS_ATTRIB_HAS_EVEX; request->attributes |= ZYDIS_ATTRIB_HAS_EVEX;
@ -1088,11 +1067,11 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
} }
// Prepare prefix bits. // Prepare prefix bits.
ZydisPrefixBit pb = ctx.matchingEntry->prefixBits; ctx.raw.evex.B = ctx.matchingInsn->evexB;
ctx.raw.evex.B = (pb & ZYDIS_PREFBIT_EVEX_B ) ? 1 : 0; ctx.raw.evex.L = ctx.matchingInsn->vectorLength & 0x01;
ctx.raw.evex.L2 = (pb & ZYDIS_PREFBIT_EVEX_L2) ? 1 : 0; ctx.raw.evex.L2 = ctx.matchingInsn->vectorLength & 0x02;
ctx.raw.vex.L = (pb & ZYDIS_PREFBIT_VEX_L ) ? 1 : 0; ctx.raw.vex.L = ctx.matchingInsn->vectorLength & 0x01;
if (pb & ZYDIS_PREFBIT_REX_W) if (ctx.matchingInsn->rexW)
{ {
ctx.raw.rex.W = 1; ctx.raw.rex.W = 1;
request->attributes |= ZYDIS_ATTRIB_HAS_REX; request->attributes |= ZYDIS_ATTRIB_HAS_REX;
@ -1103,9 +1082,9 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
ZYDIS_CHECK(ZydisPrepareOpcode(&ctx)); ZYDIS_CHECK(ZydisPrepareOpcode(&ctx));
// Some instructions have additional opcode bits encoded in ModRM.reg. // Some instructions have additional opcode bits encoded in ModRM.reg.
if (ctx.matchingEntry->modrmReg != 0xFF) if (ctx.matchingInsn->modrmReg != 0xFF)
{ {
ctx.raw.modrm.reg = ctx.matchingEntry->modrmReg; ctx.raw.modrm.reg = ctx.matchingInsn->modrmReg;
} }
// Analyze and prepare operands. // Analyze and prepare operands.
@ -1115,14 +1094,14 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
return ZYDIS_STATUS_INVALID_PARAMETER; return ZYDIS_STATUS_INVALID_PARAMETER;
} }
for (size_t i = 0; i < ctx.matchingEntry->operandCount; ++i) //for (size_t i = 0; i < ctx.matchingDef->operandCount; ++i)
{ //{
ZYDIS_CHECK(ZydisPrepareOperand( // ZYDIS_CHECK(ZydisPrepareOperand(
&ctx, &request->operands[i], // &ctx, &request->operands[i],
&ctx.matchingEntry->operands[i] // &ctx.matchingDef->operands[i]
)); // ));
} //}
//
// Do actual encoding work. // Do actual encoding work.
ZYDIS_CHECK(ZydisEmitLegacyPrefixes(&ctx)); ZYDIS_CHECK(ZydisEmitLegacyPrefixes(&ctx));
if (request->attributes & ZYDIS_ATTRIB_HAS_REX ) ZYDIS_CHECK(ZydisEmitREX (&ctx)); if (request->attributes & ZYDIS_ATTRIB_HAS_REX ) ZYDIS_CHECK(ZydisEmitREX (&ctx));
@ -1130,7 +1109,7 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
if (request->attributes & ZYDIS_ATTRIB_HAS_EVEX ) ZYDIS_CHECK(ZydisEmitEVEX (&ctx)); if (request->attributes & ZYDIS_ATTRIB_HAS_EVEX ) ZYDIS_CHECK(ZydisEmitEVEX (&ctx));
if (request->attributes & ZYDIS_ATTRIB_HAS_XOP ) ZYDIS_CHECK(ZydisEmitXOP (&ctx)); if (request->attributes & ZYDIS_ATTRIB_HAS_XOP ) ZYDIS_CHECK(ZydisEmitXOP (&ctx));
if (ctx.shouldEmitMandatoryPrefix) ZYDIS_CHECK(ZydisEmitByte(&ctx, ctx.mandatoryPrefix)); if (ctx.emitMandatoryPrefix) ZYDIS_CHECK(ZydisEmitByte(&ctx, ctx.mandatoryPrefix));
for (uint8_t i = 0; i < ctx.opcodeMapPrefixLen; ++i) for (uint8_t i = 0; i < ctx.opcodeMapPrefixLen; ++i)
{ {

View File

@ -139,7 +139,7 @@ typedef struct ZydisOperandDefinition_
ZydisInternalElementType elementType ZYDIS_BITFIELD(5); ZydisInternalElementType elementType ZYDIS_BITFIELD(5);
union union
{ {
uint8_t encoding; ZydisOperandEncoding encoding;
struct struct
{ {
uint8_t type ZYDIS_BITFIELD(3); uint8_t type ZYDIS_BITFIELD(3);