mirror of https://github.com/x64dbg/zydis
				
				
				
			More encoder progress, minor refactoring
- Added encoding support for more X86 features (IMMs, SIB, ..) - Added ZYDIS_ARRAY_SIZE macro - Moved ZYDIS_MAX_INSTRUCTION_LENGTH (Decoder.h -> InstructionInfo.h) - Renamed ZydisInstructionEncoder -> ZydisEncoderContext - Various bug-fixes
This commit is contained in:
		
							parent
							
								
									14848083ae
								
							
						
					
					
						commit
						c0f53a3a69
					
				| 
						 | 
				
			
			@ -36,18 +36,6 @@
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
/* Macros                                                                                         */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------- */
 | 
			
		||||
/* Constants                                                                                      */
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
#define ZYDIS_MAX_INSTRUCTION_LENGTH 15
 | 
			
		||||
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
/* Enums and types                                                                                */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,6 +120,12 @@
 | 
			
		|||
#define ZYDIS_ASSERT(condition) assert(condition)
 | 
			
		||||
#define ZYDIS_UNREACHABLE assert(0)
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
/* Utils                                                                                          */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
 | 
			
		||||
#define ZYDIS_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
 | 
			
		||||
#endif /* ZYDIS_DEFINES_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ extern "C" {
 | 
			
		|||
 *
 | 
			
		||||
 * @return  A zydis status code. 
 | 
			
		||||
 */
 | 
			
		||||
ZYDIS_EXPORT ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t bufferLen, 
 | 
			
		||||
ZYDIS_EXPORT ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen, 
 | 
			
		||||
    ZydisInstructionInfo* info);
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,18 @@
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
/* Macros                                                                                         */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------- */
 | 
			
		||||
/* Constants                                                                                      */
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
#define ZYDIS_MAX_INSTRUCTION_LENGTH 15
 | 
			
		||||
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
/* Operand info                                                                                   */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
| 
						 | 
				
			
			@ -315,12 +327,12 @@ typedef struct ZydisOperandInfo_
 | 
			
		|||
                int64_t sqword;
 | 
			
		||||
            } value;
 | 
			
		||||
            /**
 | 
			
		||||
             * @brief   The physical displacement size.
 | 
			
		||||
             * @brief   The physical displacement size, in bits.
 | 
			
		||||
             */
 | 
			
		||||
            uint8_t dataSize;
 | 
			
		||||
            /**
 | 
			
		||||
             * @brief   The offset of the displacement data, relative to the beginning of the 
 | 
			
		||||
             *          instruction.
 | 
			
		||||
             *          instruction, in bytes.
 | 
			
		||||
             */
 | 
			
		||||
            uint8_t dataOffset;
 | 
			
		||||
        } disp;
 | 
			
		||||
| 
						 | 
				
			
			@ -361,12 +373,12 @@ typedef struct ZydisOperandInfo_
 | 
			
		|||
            uint64_t uqword;
 | 
			
		||||
        } value;
 | 
			
		||||
        /**
 | 
			
		||||
         * @brief   The physical immediate size.
 | 
			
		||||
         * @brief   The physical immediate size, in bits.
 | 
			
		||||
         */
 | 
			
		||||
        uint8_t dataSize;
 | 
			
		||||
        /**
 | 
			
		||||
         * @brief   The offset of the immediate data, relative to the beginning of the 
 | 
			
		||||
         *          instruction.
 | 
			
		||||
         *          instruction, in bytes.
 | 
			
		||||
         */
 | 
			
		||||
        uint8_t dataOffset;
 | 
			
		||||
    } imm;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										539
									
								
								src/Encoder.c
								
								
								
								
							
							
						
						
									
										539
									
								
								src/Encoder.c
								
								
								
								
							| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
***************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <Zydis/Encoder.h>
 | 
			
		||||
#include <Zydis/Internal/InstructionTable.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +37,7 @@
 | 
			
		|||
typedef struct ZydisEncoderTableOperand_
 | 
			
		||||
{
 | 
			
		||||
    ZydisOperandEncoding encoding;
 | 
			
		||||
    ZydisSemanticOperandType type;
 | 
			
		||||
} ZydisEncoderTableOperand;
 | 
			
		||||
 | 
			
		||||
typedef uint8_t ZydisModRMMod;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,34 +76,40 @@ typedef struct ZydisEncoderTableEntry_
 | 
			
		|||
/**
 | 
			
		||||
 * @brief   The encoder context struct.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct ZydisInstructionEncoder_
 | 
			
		||||
typedef struct ZydisEncoderContext_
 | 
			
		||||
{
 | 
			
		||||
    uint8_t* buffer;
 | 
			
		||||
    size_t bufferLen;
 | 
			
		||||
    size_t writeOffs;
 | 
			
		||||
    ZydisInstructionInfo* info;
 | 
			
		||||
    const ZydisEncoderTableEntry* matchingEntry;
 | 
			
		||||
} ZydisInstructionEncoder;
 | 
			
		||||
    uint8_t dispBitSize;
 | 
			
		||||
    uint64_t disp;
 | 
			
		||||
    uint8_t immBitSizes[2];
 | 
			
		||||
    uint64_t imms[2];
 | 
			
		||||
} ZydisEncoderContext;
 | 
			
		||||
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
/* Internal helpers                                                                               */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEmitByte(ZydisInstructionEncoder* encoder, uint8_t byte)
 | 
			
		||||
static ZydisStatus ZydisEmitByte(ZydisEncoderContext* ctx, uint8_t byte)
 | 
			
		||||
{
 | 
			
		||||
    if (encoder->writeOffs + 1 >= encoder->bufferLen)
 | 
			
		||||
    if (ctx->writeOffs + 1 >= ctx->bufferLen)
 | 
			
		||||
    {
 | 
			
		||||
        return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    encoder->buffer[encoder->writeOffs++] = byte;
 | 
			
		||||
    ctx->buffer[ctx->writeOffs++] = byte;
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEmitImm(ZydisInstructionEncoder* encoder, uint64_t imm, int bits)
 | 
			
		||||
static ZydisStatus ZydisEmitImm(ZydisEncoderContext* ctx, uint64_t imm, int bits)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(bits == 8 || bits == 16 || bits == 32 || bits == 64);
 | 
			
		||||
    if (encoder->writeOffs + bits / 8 >= encoder->bufferLen)
 | 
			
		||||
    size_t newWriteOffs = ctx->writeOffs + bits / 8;
 | 
			
		||||
    if (newWriteOffs >= ctx->bufferLen ||
 | 
			
		||||
        newWriteOffs > ZYDIS_MAX_INSTRUCTION_LENGTH)
 | 
			
		||||
    {
 | 
			
		||||
        return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -109,117 +117,118 @@ static ZydisStatus ZydisEmitImm(ZydisInstructionEncoder* encoder, uint64_t imm,
 | 
			
		|||
    // TODO: bswap on big-endian
 | 
			
		||||
    switch (bits)
 | 
			
		||||
    {
 | 
			
		||||
    case 8:  *(uint8_t* )&encoder->buffer[encoder->writeOffs++] = (uint8_t )imm; break;
 | 
			
		||||
    case 16: *(uint16_t*)&encoder->buffer[encoder->writeOffs++] = (uint16_t)imm; break;
 | 
			
		||||
    case 32: *(uint32_t*)&encoder->buffer[encoder->writeOffs++] = (uint32_t)imm; break;
 | 
			
		||||
    case 64: *(uint64_t*)&encoder->buffer[encoder->writeOffs++] = (uint64_t)imm; break;
 | 
			
		||||
    case 8:  *(uint8_t* )&ctx->buffer[ctx->writeOffs] = (uint8_t )imm; break;
 | 
			
		||||
    case 16: *(uint16_t*)&ctx->buffer[ctx->writeOffs] = (uint16_t)imm; break;
 | 
			
		||||
    case 32: *(uint32_t*)&ctx->buffer[ctx->writeOffs] = (uint32_t)imm; break;
 | 
			
		||||
    case 64: *(uint64_t*)&ctx->buffer[ctx->writeOffs] = (uint64_t)imm; break;
 | 
			
		||||
    default: ZYDIS_UNREACHABLE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ctx->writeOffs = newWriteOffs;
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeLegacyPrefixes(ZydisInstructionEncoder* encoder)
 | 
			
		||||
static ZydisStatus ZydisEmitLegacyPrefixes(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    ZydisInstructionAttributes attribs = encoder->info->attributes;
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZydisInstructionAttributes attribs = ctx->info->attributes;
 | 
			
		||||
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_LOCK) 
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0xF0));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0xF0));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & (ZYDIS_ATTRIB_HAS_REP | ZYDIS_ATTRIB_HAS_REPE | ZYDIS_ATTRIB_HAS_XRELEASE)) 
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0xF3));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0xF3));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & (ZYDIS_ATTRIB_HAS_REPNE | ZYDIS_ATTRIB_HAS_BOUND | ZYDIS_ATTRIB_HAS_XACQUIRE))
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0xF2));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0xF2));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & (ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN | ZYDIS_ATTRIB_HAS_SEGMENT_CS))
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x2E));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x2E));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & (ZYDIS_ATTRIB_HAS_BRANCH_TAKEN | ZYDIS_ATTRIB_HAS_SEGMENT_DS))
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x3E));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x3E));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_SEGMENT_SS)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x36));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x36));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_SEGMENT_ES)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x26));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x26));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_SEGMENT_FS)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x64));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x64));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_SEGMENT_GS)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x65));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x65));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_OPERANDSIZE)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x66));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x66));
 | 
			
		||||
    }
 | 
			
		||||
    if (attribs & ZYDIS_ATTRIB_HAS_ADDRESSSIZE)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x67));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x67));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeREX(ZydisInstructionEncoder *encoder)
 | 
			
		||||
static ZydisStatus ZydisEmitREX(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder, 
 | 
			
		||||
        ctx, 
 | 
			
		||||
        0x40 |
 | 
			
		||||
        (encoder->info->details.rex.W & 0x01) << 3 |
 | 
			
		||||
        (encoder->info->details.rex.R & 0x01) << 2 |
 | 
			
		||||
        (encoder->info->details.rex.X & 0x01) << 1 |
 | 
			
		||||
        (encoder->info->details.rex.B & 0x01) << 0
 | 
			
		||||
        (ctx->info->details.rex.W & 0x01) << 3 |
 | 
			
		||||
        (ctx->info->details.rex.R & 0x01) << 2 |
 | 
			
		||||
        (ctx->info->details.rex.X & 0x01) << 1 |
 | 
			
		||||
        (ctx->info->details.rex.B & 0x01) << 0
 | 
			
		||||
    ));
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeVEX(ZydisInstructionEncoder *encoder)
 | 
			
		||||
static ZydisStatus ZydisEmitVEX(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
 | 
			
		||||
    // Write opcode.
 | 
			
		||||
    uint8_t opcode = encoder->info->details.vex.data[0];
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(encoder, opcode));
 | 
			
		||||
    uint8_t opcode = ctx->info->details.vex.data[0];
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(ctx, opcode));
 | 
			
		||||
 | 
			
		||||
    // Write prefix' "operands".
 | 
			
		||||
    switch (opcode)
 | 
			
		||||
    {
 | 
			
		||||
    case 0xC4:
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
            encoder, 
 | 
			
		||||
            (encoder->info->details.vex.R      & 0x01) << 7 | 
 | 
			
		||||
            (encoder->info->details.vex.X      & 0x01) << 6 |
 | 
			
		||||
            (encoder->info->details.vex.B      & 0x01) << 5 |
 | 
			
		||||
            (encoder->info->details.vex.m_mmmm & 0x1F) << 0
 | 
			
		||||
            ctx, 
 | 
			
		||||
            (ctx->info->details.vex.R      & 0x01) << 7 | 
 | 
			
		||||
            (ctx->info->details.vex.X      & 0x01) << 6 |
 | 
			
		||||
            (ctx->info->details.vex.B      & 0x01) << 5 |
 | 
			
		||||
            (ctx->info->details.vex.m_mmmm & 0x1F) << 0
 | 
			
		||||
        ));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
            encoder, 
 | 
			
		||||
            (encoder->info->details.vex.W      & 0x01) << 7 | 
 | 
			
		||||
            (encoder->info->details.vex.vvvv   & 0x0F) << 3 |
 | 
			
		||||
            (encoder->info->details.vex.L      & 0x01) << 2 |
 | 
			
		||||
            (encoder->info->details.vex.pp     & 0x03) << 0 
 | 
			
		||||
            ctx, 
 | 
			
		||||
            (ctx->info->details.vex.W      & 0x01) << 7 | 
 | 
			
		||||
            (ctx->info->details.vex.vvvv   & 0x0F) << 3 |
 | 
			
		||||
            (ctx->info->details.vex.L      & 0x01) << 2 |
 | 
			
		||||
            (ctx->info->details.vex.pp     & 0x03) << 0 
 | 
			
		||||
        ));
 | 
			
		||||
        break;
 | 
			
		||||
    case 0xC5:
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
            encoder, 
 | 
			
		||||
            (encoder->info->details.vex.R      & 0x01) << 7 | 
 | 
			
		||||
            (encoder->info->details.vex.vvvv   & 0x0F) << 3 |
 | 
			
		||||
            (encoder->info->details.vex.L      & 0x01) << 2 |
 | 
			
		||||
            (encoder->info->details.vex.pp     & 0x03) << 0 
 | 
			
		||||
            ctx, 
 | 
			
		||||
            (ctx->info->details.vex.R      & 0x01) << 7 | 
 | 
			
		||||
            (ctx->info->details.vex.vvvv   & 0x0F) << 3 |
 | 
			
		||||
            (ctx->info->details.vex.L      & 0x01) << 2 |
 | 
			
		||||
            (ctx->info->details.vex.pp     & 0x03) << 0 
 | 
			
		||||
        ));
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
| 
						 | 
				
			
			@ -229,103 +238,99 @@ static ZydisStatus ZydisEncodeVEX(ZydisInstructionEncoder *encoder)
 | 
			
		|||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeEVEX(ZydisInstructionEncoder *encoder)
 | 
			
		||||
static ZydisStatus ZydisEmitEVEX(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(encoder, 0x62));
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(ctx, 0x62));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder, 
 | 
			
		||||
        (encoder->info->details.evex.R    & 0x01) << 7 |
 | 
			
		||||
        (encoder->info->details.evex.X    & 0x01) << 6 |
 | 
			
		||||
        (encoder->info->details.evex.B    & 0x01) << 5 |
 | 
			
		||||
        (encoder->info->details.evex.R2   & 0x01) << 4 |
 | 
			
		||||
        (encoder->info->details.evex.mm   & 0x03) << 0
 | 
			
		||||
        ctx, 
 | 
			
		||||
        (ctx->info->details.evex.R    & 0x01) << 7 |
 | 
			
		||||
        (ctx->info->details.evex.X    & 0x01) << 6 |
 | 
			
		||||
        (ctx->info->details.evex.B    & 0x01) << 5 |
 | 
			
		||||
        (ctx->info->details.evex.R2   & 0x01) << 4 |
 | 
			
		||||
        (ctx->info->details.evex.mm   & 0x03) << 0
 | 
			
		||||
    ));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder, 
 | 
			
		||||
        (encoder->info->details.evex.W    & 0x01) << 7 |
 | 
			
		||||
        (encoder->info->details.evex.vvvv & 0x0F) << 3 |
 | 
			
		||||
        (encoder->info->details.evex.pp   & 0x03) << 0
 | 
			
		||||
        ctx, 
 | 
			
		||||
        (ctx->info->details.evex.W    & 0x01) << 7 |
 | 
			
		||||
        (ctx->info->details.evex.vvvv & 0x0F) << 3 |
 | 
			
		||||
        (ctx->info->details.evex.pp   & 0x03) << 0
 | 
			
		||||
    ));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder,
 | 
			
		||||
        (encoder->info->details.evex.z    & 0x01) << 7 |
 | 
			
		||||
        (encoder->info->details.evex.L2   & 0x01) << 6 |
 | 
			
		||||
        (encoder->info->details.evex.L    & 0x01) << 5 |
 | 
			
		||||
        (encoder->info->details.evex.b    & 0x01) << 4 |
 | 
			
		||||
        (encoder->info->details.evex.V2   & 0x01) << 3 |
 | 
			
		||||
        (encoder->info->details.evex.aaa  & 0x07) << 0
 | 
			
		||||
    ));
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeXOP(ZydisInstructionEncoder* encoder)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(encoder, 0x8F));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder,
 | 
			
		||||
        (encoder->info->details.xop.R      & 0x01) << 7 |
 | 
			
		||||
        (encoder->info->details.xop.X      & 0x01) << 6 |
 | 
			
		||||
        (encoder->info->details.xop.B      & 0x01) << 5 |
 | 
			
		||||
        (encoder->info->details.xop.m_mmmm & 0x1F) << 0 
 | 
			
		||||
    ));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder,
 | 
			
		||||
        (encoder->info->details.xop.W      & 0x01) << 7 |
 | 
			
		||||
        (encoder->info->details.xop.vvvv   & 0x0F) << 3 |
 | 
			
		||||
        (encoder->info->details.xop.L      & 0x01) << 2 |
 | 
			
		||||
        (encoder->info->details.xop.pp     & 0x03) << 0 
 | 
			
		||||
    ));
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeModRM(ZydisInstructionEncoder* encoder)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder,
 | 
			
		||||
        (encoder->info->details.modrm.mod & 0x03) << 6 |
 | 
			
		||||
        (encoder->info->details.modrm.reg & 0x07) << 3 |
 | 
			
		||||
        (encoder->info->details.modrm.rm  & 0x07) << 0
 | 
			
		||||
        ctx,
 | 
			
		||||
        (ctx->info->details.evex.z    & 0x01) << 7 |
 | 
			
		||||
        (ctx->info->details.evex.L2   & 0x01) << 6 |
 | 
			
		||||
        (ctx->info->details.evex.L    & 0x01) << 5 |
 | 
			
		||||
        (ctx->info->details.evex.b    & 0x01) << 4 |
 | 
			
		||||
        (ctx->info->details.evex.V2   & 0x01) << 3 |
 | 
			
		||||
        (ctx->info->details.evex.aaa  & 0x07) << 0
 | 
			
		||||
    ));
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeSIB(ZydisInstructionEncoder* encoder)
 | 
			
		||||
static ZydisStatus ZydisEmitXOP(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(ctx, 0x8F));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        encoder,
 | 
			
		||||
        (encoder->info->details.sib.scale & 0x03) << 6 |
 | 
			
		||||
        (encoder->info->details.sib.index & 0x07) << 3 |
 | 
			
		||||
        (encoder->info->details.sib.base  & 0x07) << 0
 | 
			
		||||
        ctx,
 | 
			
		||||
        (ctx->info->details.xop.R      & 0x01) << 7 |
 | 
			
		||||
        (ctx->info->details.xop.X      & 0x01) << 6 |
 | 
			
		||||
        (ctx->info->details.xop.B      & 0x01) << 5 |
 | 
			
		||||
        (ctx->info->details.xop.m_mmmm & 0x1F) << 0 
 | 
			
		||||
    ));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        ctx,
 | 
			
		||||
        (ctx->info->details.xop.W      & 0x01) << 7 |
 | 
			
		||||
        (ctx->info->details.xop.vvvv   & 0x0F) << 3 |
 | 
			
		||||
        (ctx->info->details.xop.L      & 0x01) << 2 |
 | 
			
		||||
        (ctx->info->details.xop.pp     & 0x03) << 0 
 | 
			
		||||
    ));
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEncodeOpcode(ZydisInstructionEncoder* encoder)
 | 
			
		||||
static ZydisStatus ZydisEmitModRM(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(encoder);
 | 
			
		||||
    ZYDIS_ASSERT(encoder->matchingEntry);
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        ctx,
 | 
			
		||||
        (ctx->info->details.modrm.mod & 0x03) << 6 |
 | 
			
		||||
        (ctx->info->details.modrm.reg & 0x07) << 3 |
 | 
			
		||||
        (ctx->info->details.modrm.rm  & 0x07) << 0
 | 
			
		||||
    ));
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEmitSIB(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(
 | 
			
		||||
        ctx,
 | 
			
		||||
        (ctx->info->details.sib.scale & 0x03) << 6 |
 | 
			
		||||
        (ctx->info->details.sib.index & 0x07) << 3 |
 | 
			
		||||
        (ctx->info->details.sib.base  & 0x07) << 0
 | 
			
		||||
    ));
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisEmitOpcode(ZydisEncoderContext* ctx)
 | 
			
		||||
{
 | 
			
		||||
    ZYDIS_ASSERT(ctx);
 | 
			
		||||
    ZYDIS_ASSERT(ctx->matchingEntry);
 | 
			
		||||
 | 
			
		||||
    // Put opcode extension prefix(es), if required.
 | 
			
		||||
    switch (encoder->matchingEntry->map)
 | 
			
		||||
    switch (ctx->matchingEntry->map)
 | 
			
		||||
    {
 | 
			
		||||
    case ZYDIS_OPCODE_MAP_0F:
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x0F));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x0F));
 | 
			
		||||
        break;
 | 
			
		||||
    case ZYDIS_OPCODE_MAP_0F38:
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x0F));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x38));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x0F));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x38));
 | 
			
		||||
        break;
 | 
			
		||||
    case ZYDIS_OPCODE_MAP_0F3A:
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x0F));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(encoder, 0x3A));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x0F));
 | 
			
		||||
        ZYDIS_CHECK(ZydisEmitByte(ctx, 0x3A));
 | 
			
		||||
        break;
 | 
			
		||||
    case ZYDIS_OPCODE_MAP_XOP8:
 | 
			
		||||
    case ZYDIS_OPCODE_MAP_XOP9:
 | 
			
		||||
| 
						 | 
				
			
			@ -339,29 +344,75 @@ static ZydisStatus ZydisEncodeOpcode(ZydisInstructionEncoder* encoder)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Emit actual opcode.
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(encoder, encoder->matchingEntry->opcode));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitByte(ctx, ctx->info->opcode));
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisPrepareOperand(ZydisInstructionEncoder* encoder,
 | 
			
		||||
    ZydisOperandInfo* operand)
 | 
			
		||||
static ZydisStatus ZydisSimplifyOperandType(ZydisSemanticOperandType semType,
 | 
			
		||||
    ZydisOperandType* simpleType)
 | 
			
		||||
{
 | 
			
		||||
    switch (operand->encoding)
 | 
			
		||||
    // TODO: Better mapping, this is just for testing.
 | 
			
		||||
    switch (semType)
 | 
			
		||||
    {
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_GPR8:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_GPR16:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_GPR32:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_GPR64:
 | 
			
		||||
        *simpleType = ZYDIS_OPERAND_TYPE_REGISTER;
 | 
			
		||||
        break;
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_IMM8:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_IMM16:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_IMM32:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_IMM64:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_REL8:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_REL16:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_REL32:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_REL64:
 | 
			
		||||
        *simpleType = ZYDIS_OPERAND_TYPE_IMMEDIATE;
 | 
			
		||||
        break;
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_MEM8:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_MEM16:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_MEM32:
 | 
			
		||||
    case ZYDIS_SEM_OPERAND_TYPE_MEM64:
 | 
			
		||||
        *simpleType = ZYDIS_OPERAND_TYPE_MEMORY;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx,
 | 
			
		||||
    ZydisRegister reg, uint8_t useRM)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t* regRM = useRM ? &ctx->info->details.modrm.rm 
 | 
			
		||||
                           : &ctx->info->details.modrm.reg;
 | 
			
		||||
    uint8_t* rexRB = useRM ? &ctx->info->details.rex.B 
 | 
			
		||||
                           : &ctx->info->details.rex.R;
 | 
			
		||||
 | 
			
		||||
    int16_t regID = ZydisRegisterGetId(reg);
 | 
			
		||||
    if (regID == -1) return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
 | 
			
		||||
    *regRM = regID & 0x07;
 | 
			
		||||
    *rexRB = (regID & 0x08) >> 3;
 | 
			
		||||
    ctx->info->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
 | 
			
		||||
    if (*rexRB) ctx->info->attributes |= ZYDIS_ATTRIB_HAS_REX;
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx,
 | 
			
		||||
    ZydisOperandInfo* operand, const ZydisEncoderTableOperand* tableEntry)
 | 
			
		||||
{
 | 
			
		||||
    switch (tableEntry->encoding)
 | 
			
		||||
    {
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_NONE:
 | 
			
		||||
        break; // Nothing to do.
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_REG:
 | 
			
		||||
    {
 | 
			
		||||
        int16_t reg = ZydisRegisterGetId(operand->reg);
 | 
			
		||||
        if (reg == -1) return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
        encoder->info->details.modrm.reg = reg & 0x07;
 | 
			
		||||
        encoder->info->details.rex.R = (reg & 0x08) >> 3;
 | 
			
		||||
        encoder->info->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
 | 
			
		||||
        if (encoder->info->details.rex.R)
 | 
			
		||||
        {
 | 
			
		||||
            encoder->info->attributes |= ZYDIS_ATTRIB_HAS_REX;
 | 
			
		||||
        }
 | 
			
		||||
        ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, ZYDIS_FALSE));
 | 
			
		||||
    } break;
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_RM:
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_RM_CD2:
 | 
			
		||||
| 
						 | 
				
			
			@ -372,68 +423,129 @@ static ZydisStatus ZydisPrepareOperand(ZydisInstructionEncoder* encoder,
 | 
			
		|||
    case ZYDIS_OPERAND_ENCODING_RM_CD64:
 | 
			
		||||
    {
 | 
			
		||||
        // Memory operand?
 | 
			
		||||
        if (operand->reg == ZYDIS_REGISTER_NONE)
 | 
			
		||||
        if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY)
 | 
			
		||||
        {
 | 
			
		||||
            int32_t divisor = 1;
 | 
			
		||||
            switch (operand->encoding)
 | 
			
		||||
            // Has base register?
 | 
			
		||||
            if (operand->mem.base != ZYDIS_REGISTER_NONE)
 | 
			
		||||
            {
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM:      divisor = 1;  break;
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM_CD2:  divisor = 2;  break;
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM_CD4:  divisor = 4;  break;
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM_CD8:  divisor = 8;  break;
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM_CD16: divisor = 16; break;
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM_CD32: divisor = 32; break;
 | 
			
		||||
                case ZYDIS_OPERAND_ENCODING_RM_CD64: divisor = 64; break;
 | 
			
		||||
                default: ZYDIS_UNREACHABLE;
 | 
			
		||||
                ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, ZYDIS_TRUE));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // TODO: Does rm=0x05 work with sbyte disps?
 | 
			
		||||
                ctx->info->details.modrm.rm = 0x05 /* memory */;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Has compressed disp encoding and is compression possible?
 | 
			
		||||
            int32_t* sdword = &operand->mem.disp.value.sdword;
 | 
			
		||||
            encoder->info->details.modrm.mod = 0x02 /* 32 bit disp */;
 | 
			
		||||
            if (divisor != 1 &&
 | 
			
		||||
                *sdword % divisor == 0 &&
 | 
			
		||||
                *sdword / divisor <= INT8_MAX &&
 | 
			
		||||
                *sdword / divisor >= INT8_MIN)
 | 
			
		||||
            // SIB byte required?
 | 
			
		||||
            if (operand->mem.index || operand->mem.scale)
 | 
			
		||||
            {
 | 
			
		||||
                encoder->info->details.modrm.mod = 0x01 /* 8 bit disp */;
 | 
			
		||||
                *sdword /= divisor;
 | 
			
		||||
                switch (operand->mem.scale)
 | 
			
		||||
                {
 | 
			
		||||
                case 1: ctx->info->details.sib.index = 0x01; break;
 | 
			
		||||
                case 2: ctx->info->details.sib.index = 0x02; break;
 | 
			
		||||
                case 4: ctx->info->details.sib.index = 0x03; break;
 | 
			
		||||
                case 8: ctx->info->details.sib.index = 0x04; break;
 | 
			
		||||
                default: return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // TODO: base, index
 | 
			
		||||
 | 
			
		||||
                ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SIB;
 | 
			
		||||
            }
 | 
			
		||||
            // Nope, regular encoding. Does it fit a byte anyway?
 | 
			
		||||
            else if (*sdword <= INT8_MAX && *sdword >= INT8_MIN)
 | 
			
		||||
 | 
			
		||||
            // Has displacement?
 | 
			
		||||
            if (operand->mem.disp.value.sdword)
 | 
			
		||||
            {
 | 
			
		||||
                encoder->info->details.modrm.mod = 0x01 /* 8 bit disp */;
 | 
			
		||||
                int32_t divisor = 1;
 | 
			
		||||
                switch (tableEntry->encoding)
 | 
			
		||||
                {
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM:                    break;
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM_CD2:  divisor = 2;  break;
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM_CD4:  divisor = 4;  break;
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM_CD8:  divisor = 8;  break;
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM_CD16: divisor = 16; break;
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM_CD32: divisor = 32; break;
 | 
			
		||||
                    case ZYDIS_OPERAND_ENCODING_RM_CD64: divisor = 64; break;
 | 
			
		||||
                    default: ZYDIS_UNREACHABLE;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Has compressed disp encoding and is compression possible?
 | 
			
		||||
                int32_t* sdword = &operand->mem.disp.value.sdword;
 | 
			
		||||
                if (divisor != 1 &&
 | 
			
		||||
                    *sdword % divisor == 0 &&
 | 
			
		||||
                    *sdword / divisor <= INT8_MAX &&
 | 
			
		||||
                    *sdword / divisor >= INT8_MIN)
 | 
			
		||||
                {
 | 
			
		||||
                    ctx->dispBitSize = 8;
 | 
			
		||||
                    ctx->info->details.modrm.mod = 0x01 /* 8 bit disp */;
 | 
			
		||||
                    *sdword /= divisor;
 | 
			
		||||
                }
 | 
			
		||||
                // Nope, regular encoding. Does it fit a byte anyway?
 | 
			
		||||
                else if (*sdword <= INT8_MAX && *sdword >= INT8_MIN)
 | 
			
		||||
                {
 | 
			
		||||
                    ctx->dispBitSize = 8;
 | 
			
		||||
                    ctx->info->details.modrm.mod = 0x01 /* 8 bit disp */;
 | 
			
		||||
                }
 | 
			
		||||
                // No compression possible, emit as 32 bit.
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    ctx->dispBitSize = 32;
 | 
			
		||||
                    ctx->info->details.modrm.mod = 0x02 /* 32 bit disp */;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ctx->disp = *sdword;
 | 
			
		||||
            }
 | 
			
		||||
            // No displacement.
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                ctx->info->details.modrm.mod = 0x00 /* no disp */;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Nope, register.
 | 
			
		||||
        else
 | 
			
		||||
        else if (operand->type == ZYDIS_OPERAND_TYPE_REGISTER)
 | 
			
		||||
        {
 | 
			
		||||
            int16_t reg = ZydisRegisterGetId(operand->reg);
 | 
			
		||||
            if (reg == -1) return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
            encoder->info->details.modrm.reg = reg & 0x07;
 | 
			
		||||
            encoder->info->details.rex.B = (reg & 0x08) >> 3;
 | 
			
		||||
            encoder->info->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
 | 
			
		||||
            if (encoder->info->details.rex.B)
 | 
			
		||||
            {
 | 
			
		||||
                encoder->info->attributes |= ZYDIS_ATTRIB_HAS_REX;
 | 
			
		||||
            }
 | 
			
		||||
            encoder->info->details.modrm.mod = 0x03;
 | 
			
		||||
            ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, ZYDIS_TRUE));
 | 
			
		||||
            ctx->info->details.modrm.mod = 0x03 /* reg */;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ctx->info->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_OPCODE:
 | 
			
		||||
        break; // TODO
 | 
			
		||||
    {
 | 
			
		||||
        int16_t reg = ZydisRegisterGetId(operand->reg);
 | 
			
		||||
        if (reg == -1) return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
        ctx->info->opcode += reg & 0x0F;
 | 
			
		||||
        ctx->info->details.rex.R = (reg & 0x08) >> 3;
 | 
			
		||||
        if (ctx->info->details.rex.B) ctx->info->attributes |= ZYDIS_ATTRIB_HAS_REX;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_VVVV:
 | 
			
		||||
        break; // TODO
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_AAA:
 | 
			
		||||
        break; // TODO
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_IMM8_LO:
 | 
			
		||||
    {
 | 
			
		||||
        ctx->immBitSizes[0] = 8;
 | 
			
		||||
        ctx->imms[0] |= operand->imm.value.ubyte & 0x0F;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_IMM8_HI:
 | 
			
		||||
    {
 | 
			
		||||
        ctx->immBitSizes[0] = 8;
 | 
			
		||||
        ctx->imms[0] |= (operand->imm.value.ubyte & 0x0F) << 4;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_IMM8:
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_IMM16:
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_IMM32:
 | 
			
		||||
    case ZYDIS_OPERAND_ENCODING_IMM64:
 | 
			
		||||
        // Nothing to do here, we put those in a later stage.
 | 
			
		||||
        // TODO: moffs
 | 
			
		||||
        break; 
 | 
			
		||||
    {
 | 
			
		||||
        uint8_t immIdx = ctx->immBitSizes[0] ? 1 : 0;
 | 
			
		||||
        ctx->immBitSizes[immIdx] = operand->imm.dataSize;
 | 
			
		||||
        ctx->imms[immIdx] = operand->imm.value.uqword;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
        ZYDIS_UNREACHABLE;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -441,6 +553,17 @@ static ZydisStatus ZydisPrepareOperand(ZydisInstructionEncoder* encoder,
 | 
			
		|||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisDeriveEncodingForOp(ZydisOperandDefinition* operand)
 | 
			
		||||
{
 | 
			
		||||
    switch (operand->type)
 | 
			
		||||
    {
 | 
			
		||||
    default:
 | 
			
		||||
        return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZydisStatus ZydisFindMatchingDef(const ZydisInstructionInfo* info,
 | 
			
		||||
    const ZydisEncoderTableEntry** matchingEntry)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -449,7 +572,7 @@ static ZydisStatus ZydisFindMatchingDef(const ZydisInstructionInfo* info,
 | 
			
		|||
 | 
			
		||||
    // Locate entries with matching mnemonic.
 | 
			
		||||
    // TODO: do binary search / hash based lookup instead
 | 
			
		||||
    for (size_t i = 0; i < sizeof(kEncoderTable) / sizeof(kEncoderTable[0]); ++i)
 | 
			
		||||
    for (size_t i = 0; i < ZYDIS_ARRAY_SIZE(kEncoderTable); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        const ZydisEncoderTableEntry* curEntry = &kEncoderTable[i];
 | 
			
		||||
        if (curEntry->mnemonic != info->mnemonic ||
 | 
			
		||||
| 
						 | 
				
			
			@ -468,7 +591,10 @@ static ZydisStatus ZydisFindMatchingDef(const ZydisInstructionInfo* info,
 | 
			
		|||
        {
 | 
			
		||||
            const ZydisEncoderTableOperand* curEncoderOp = &curEntry->operands[k];
 | 
			
		||||
            const ZydisOperandInfo* curReqOp = &info->operands[k];
 | 
			
		||||
            if (curEncoderOp->encoding != curReqOp->encoding) goto continueTopLevel;
 | 
			
		||||
            if (curReqOp->encoding != curEncoderOp->encoding) goto continueTopLevel;
 | 
			
		||||
            ZydisOperandType simpleType;
 | 
			
		||||
            ZYDIS_CHECK(ZydisSimplifyOperandType(curEncoderOp->type, &simpleType));
 | 
			
		||||
            if (curReqOp->type != simpleType) goto continueTopLevel;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Still here? We found our entry!
 | 
			
		||||
| 
						 | 
				
			
			@ -486,45 +612,60 @@ static ZydisStatus ZydisFindMatchingDef(const ZydisInstructionInfo* info,
 | 
			
		|||
/* Implementation of public functions                                                             */
 | 
			
		||||
/* ============================================================================================== */
 | 
			
		||||
 | 
			
		||||
ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t bufferLen,
 | 
			
		||||
ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen,
 | 
			
		||||
    ZydisInstructionInfo* info)
 | 
			
		||||
{
 | 
			
		||||
    if (!info) return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
    if (!buffer || !bufferLen) return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE;
 | 
			
		||||
    if (!info || !bufferLen) return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
    if (!buffer || !*bufferLen) return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE;
 | 
			
		||||
 | 
			
		||||
    ZydisInstructionEncoder encoder;
 | 
			
		||||
    memset(&encoder, 0, sizeof(encoder));
 | 
			
		||||
    ZydisEncoderContext ctx;
 | 
			
		||||
    memset(&ctx, 0, sizeof(ctx));
 | 
			
		||||
    memset(&info->details, 0, sizeof(info->details));
 | 
			
		||||
    encoder.buffer = (uint8_t*)buffer;
 | 
			
		||||
    encoder.bufferLen = bufferLen;
 | 
			
		||||
    encoder.writeOffs = 0;
 | 
			
		||||
    encoder.info = info;
 | 
			
		||||
    ctx.buffer = (uint8_t*)buffer;
 | 
			
		||||
    ctx.bufferLen = *bufferLen;
 | 
			
		||||
    ctx.writeOffs = 0;
 | 
			
		||||
    ctx.info = info;
 | 
			
		||||
    *bufferLen = 0;
 | 
			
		||||
 | 
			
		||||
    // Mask out attributes that can't be set explicitly by user.
 | 
			
		||||
    info->attributes &= ZYDIS_USER_ENCODABLE_ATTRIB_MASK;
 | 
			
		||||
 | 
			
		||||
    // Search matching instruction, collect information about what needs to be
 | 
			
		||||
    // encoded, what prefixes are required etc..
 | 
			
		||||
    ZYDIS_CHECK(ZydisFindMatchingDef(info, &encoder.matchingEntry));
 | 
			
		||||
    info->opcode = encoder.matchingEntry->opcode;
 | 
			
		||||
    info->attributes |= encoder.matchingEntry->mandatoryAttribs;
 | 
			
		||||
    // encoded, what prefixes are required, etc.
 | 
			
		||||
    ZYDIS_CHECK(ZydisFindMatchingDef(info, &ctx.matchingEntry));
 | 
			
		||||
    info->opcode = ctx.matchingEntry->opcode;
 | 
			
		||||
    info->attributes |= ctx.matchingEntry->mandatoryAttribs;
 | 
			
		||||
 | 
			
		||||
    // Analyze and prepare operands.
 | 
			
		||||
    for (size_t i = 0; i < encoder.matchingEntry->operandCount; ++i)
 | 
			
		||||
    if (info->operandCount > ZYDIS_ARRAY_SIZE(info->operands))
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisPrepareOperand(&encoder, &info->operands[i]));
 | 
			
		||||
        // TODO: Better status?
 | 
			
		||||
        return ZYDIS_STATUS_INVALID_PARAMETER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < ctx.matchingEntry->operandCount; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        ZYDIS_CHECK(ZydisPrepareOperand(
 | 
			
		||||
            &ctx, &info->operands[i], 
 | 
			
		||||
            &ctx.matchingEntry->operands[i]
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Do actual encoding work.
 | 
			
		||||
    ZYDIS_CHECK(ZydisEncodeLegacyPrefixes(&encoder));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_REX  ) ZYDIS_CHECK(ZydisEncodeREX  (&encoder));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_VEX  ) ZYDIS_CHECK(ZydisEncodeVEX  (&encoder));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_EVEX ) ZYDIS_CHECK(ZydisEncodeEVEX (&encoder));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_XOP  ) ZYDIS_CHECK(ZydisEncodeXOP  (&encoder));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEncodeOpcode(&encoder));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_MODRM) ZYDIS_CHECK(ZydisEncodeModRM(&encoder));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_SIB  ) ZYDIS_CHECK(ZydisEncodeSIB  (&encoder));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitLegacyPrefixes(&ctx));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_REX  ) ZYDIS_CHECK(ZydisEmitREX  (&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_XOP  ) ZYDIS_CHECK(ZydisEmitXOP  (&ctx));
 | 
			
		||||
    ZYDIS_CHECK(ZydisEmitOpcode(&ctx));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_MODRM) ZYDIS_CHECK(ZydisEmitModRM(&ctx));
 | 
			
		||||
    if (info->attributes & ZYDIS_ATTRIB_HAS_SIB  ) ZYDIS_CHECK(ZydisEmitSIB  (&ctx));
 | 
			
		||||
 | 
			
		||||
    if (ctx.dispBitSize)    ZYDIS_CHECK(ZydisEmitImm(&ctx, ctx.disp, ctx.dispBitSize));
 | 
			
		||||
    if (ctx.immBitSizes[0]) ZYDIS_CHECK(ZydisEmitImm(&ctx, ctx.imms[0], ctx.immBitSizes[0]));
 | 
			
		||||
    if (ctx.immBitSizes[1]) ZYDIS_CHECK(ZydisEmitImm(&ctx, ctx.imms[1], ctx.immBitSizes[1]));
 | 
			
		||||
 | 
			
		||||
    *bufferLen = ctx.writeOffs;
 | 
			
		||||
    return ZYDIS_STATUS_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,24 +88,30 @@ int main(int argc, char** argv)
 | 
			
		|||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //char printBuffer[256];
 | 
			
		||||
            //ZydisFormatterFormatInstruction(
 | 
			
		||||
            //    &formatter, &info, printBuffer, sizeof(printBuffer)
 | 
			
		||||
            //);
 | 
			
		||||
            //puts(printBuffer);
 | 
			
		||||
            readOffs += info.length;
 | 
			
		||||
            char printBuffer[256];
 | 
			
		||||
            ZydisFormatterFormatInstruction(
 | 
			
		||||
                &formatter, &info, printBuffer, sizeof(printBuffer)
 | 
			
		||||
            );
 | 
			
		||||
            puts(printBuffer);
 | 
			
		||||
 | 
			
		||||
            // TODO: Remove
 | 
			
		||||
            // DEBUG CODE START
 | 
			
		||||
            //uint8_t encBuffer[15];
 | 
			
		||||
            //ZydisStatus encStatus = ZydisEncoderEncodeInstruction(
 | 
			
		||||
            //    encBuffer, sizeof(encBuffer), &info
 | 
			
		||||
            //);
 | 
			
		||||
            //if (!ZYDIS_SUCCESS(encStatus)) {
 | 
			
		||||
            //    //__asm int 3;
 | 
			
		||||
            //    *(volatile int*)0 = 0;
 | 
			
		||||
            //}
 | 
			
		||||
            uint8_t encBuffer[15];
 | 
			
		||||
            size_t encBufferSize = sizeof(encBuffer);
 | 
			
		||||
            ZydisStatus encStatus = ZydisEncoderEncodeInstruction(
 | 
			
		||||
                encBuffer, &encBufferSize, &info
 | 
			
		||||
            );
 | 
			
		||||
            ZYDIS_ASSERT(ZYDIS_SUCCESS(encStatus));
 | 
			
		||||
            for (size_t i = 0; i < encBufferSize; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                printf("%02X ", encBuffer[i]);
 | 
			
		||||
            }
 | 
			
		||||
            putchar('\n');
 | 
			
		||||
            ZYDIS_ASSERT(encBufferSize == info.length);
 | 
			
		||||
            ZYDIS_ASSERT(!memcmp(encBuffer, readBuf + readOffs, encBufferSize));
 | 
			
		||||
            // DEBUG CODE END
 | 
			
		||||
            
 | 
			
		||||
            readOffs += info.length;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (readOffs < sizeof(readBuf))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue