Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/zydis/Zydis/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 180 kB image not shown  

Quelle  Decoder.c   Sprache: C

 
/***************************************************************************************************

  Zyan Disassembler Library (Zydis)

  Original Author : Florian Bernd

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.

***************************************************************************************************/


// ReSharper disable CppClangTidyClangDiagnosticImplicitFallthrough
// ReSharper disable CppClangTidyClangDiagnosticSwitchEnum
// ReSharper disable CppClangTidyClangDiagnosticCoveredSwitchDefault

// Temporarily disabled due to a LLVM issue:
// ReSharper disable CppClangTidyBugproneNarrowingConversions

#include "zydis/Zycore/LibC.h"
#include "zydis/Zydis/Decoder.h"
#include "zydis/Zydis/Status.h"
#include "zydis/Zydis/Internal/DecoderData.h"
#include "zydis/Zydis/Internal/SharedData.h"

/* ============================================================================================== */
/* Internal enums and types                                                                       */
/* ============================================================================================== */

/* ---------------------------------------------------------------------------------------------- */
/* Decoder context                                                                                */
/* ---------------------------------------------------------------------------------------------- */

/**
 * Defines the `ZydisDecoderState` struct.
 */

typedef struct ZydisDecoderState_
{
    /**
     * A pointer to the `ZydisDecoder` instance.
     */

    const ZydisDecoder* decoder;
    /**
     * A pointer to the `ZydisDecoderContext` struct.
     */

    ZydisDecoderContext* context;
    /**
     * The input buffer.
     */

    const ZyanU8* buffer;
    /**
     * The input buffer length.
     */

    ZyanUSize buffer_len;
    /**
     * Prefix information.
     */

    struct
    {
        /**
         * Signals, if the instruction has a `LOCK` prefix (`F0`).
         *
         * This prefix originally belongs to group 1, but separating it from the other ones makes
         * parsing easier for us later.
         */

        ZyanBool has_lock;
        /**
         * The effective prefix of group 1 (either `F2` or `F3`).
         */

        ZyanU8 group1;
        /**
         * The effective prefix of group 2 (`2E`, `36`, `3E`, `26`, `64` or `65`).
         */

        ZyanU8 group2;
        /**
         * The effective segment prefix.
         */

        ZyanU8 effective_segment;
        /**
         * The prefix that should be treated as the mandatory-prefix, if the
         * current instruction needs one.
         *
         * The last `F3`/`F2` prefix has precedence over previous ones and
         * `F3`/`F2` in general have precedence over `66`.
         */

        ZyanU8 mandatory_candidate;
        /**
         * The offset of the effective `LOCK` prefix.
         */

        ZyanU8 offset_lock;
        /**
         * The offset of the effective prefix in group 1.
         */

        ZyanU8 offset_group1;
        /**
         * The offset of the effective prefix in group 2.
         */

        ZyanU8 offset_group2;
        /**
         * The offset of the operand-size override prefix (`66`).
         *
         * This is the only prefix in group 3.
         */

        ZyanU8 offset_osz_override;
        /**
         * The offset of the address-size override prefix (`67`).
         *
         * This is the only prefix in group 4.
         */

        ZyanU8 offset_asz_override;
        /**
         * The offset of the effective segment prefix.
         */

        ZyanU8 offset_segment;
        /**
         * The offset of the mandatory-candidate prefix.
         */

        ZyanU8 offset_mandatory;
        /**
         * The offset of a possible `CET` `no-lock` prefix.
         */

        ZyanI8 offset_notrack;
    } prefixes;
} ZydisDecoderState;

/* ---------------------------------------------------------------------------------------------- */
/* Register encoding                                                                              */
/* ---------------------------------------------------------------------------------------------- */

/**
 * Defines the `ZydisRegisterEncoding` enum.
 */

typedef enum ZydisRegisterEncoding_
{
    ZYDIS_REG_ENCODING_INVALID,
    /**
     * The register-id is encoded as part of the opcode (bits [3..0]).
     *
     * Possible extension by:
     * - `REX.B`
     */

    ZYDIS_REG_ENCODING_OPCODE,
    /**
     * The register-id is encoded in `modrm.reg`.
     *
     * Possible extension by:
     * - `.R`
     * - `.R'` (vector only, EVEX/MVEX)
     */

    ZYDIS_REG_ENCODING_REG,
    /**
     * The register-id is encoded in `.vvvv`.
     *
     * Possible extension by:
     * - `.v'` (vector only, EVEX/MVEX).
     */

    ZYDIS_REG_ENCODING_NDSNDD,
    /**
     * The register-id is encoded in `modrm.rm`.
     *
     * Possible extension by:
     * - `.B`
     * - `.X` (vector only, EVEX/MVEX)`
     */

    ZYDIS_REG_ENCODING_RM,
    /**
     * The register-id is encoded in `modrm.rm` or `sib.base` (if `SIB` is present).
     *
     * Possible extension by:
     * - `.B`
     */

    ZYDIS_REG_ENCODING_BASE,
    /**
     * The register-id is encoded in `sib.index`.
     *
     * Possible extension by:
     * - `.X`
     */

    ZYDIS_REG_ENCODING_INDEX,
    /**
     * The register-id is encoded in `sib.index`.
     *
     * Possible extension by:
     * - `.X`
     * - `.V'` (vector only, EVEX/MVEX)
     */

    ZYDIS_REG_ENCODING_VIDX,
    /**
     * The register-id is encoded in an additional 8-bit immediate value.
     *
     * Bits [7:4] in 64-bit mode with possible extension by bit [3] (vector only), bits [7:5] for
     * all other modes.
     */

    ZYDIS_REG_ENCODING_IS4,
    /**
     * The register-id is encoded in `EVEX.aaa/MVEX.kkk`.
     */

    ZYDIS_REG_ENCODING_MASK,

    /**
     * Maximum value of this enum.
     */

    ZYDIS_REG_ENCODING_MAX_VALUE = ZYDIS_REG_ENCODING_MASK,
    /**
     * The minimum number of bits required to represent all values of this enum.
     */

    ZYDIS_REG_ENCODING_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REG_ENCODING_MAX_VALUE)
} ZydisRegisterEncoding;

/* ---------------------------------------------------------------------------------------------- */

/* ============================================================================================== */
/* Internal functions                                                                             */
/* ============================================================================================== */

/* ---------------------------------------------------------------------------------------------- */
/* Input helper functions                                                                         */
/* ---------------------------------------------------------------------------------------------- */

/**
 * Reads one byte from the current read-position of the input data-source.
 *
 * @param   state       A pointer to the `ZydisDecoderState` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   value       A pointer to the memory that receives the byte from the input data-source.
 *
 * @return  A zyan status code.
 *
 * This function may fail, if the `ZYDIS_MAX_INSTRUCTION_LENGTH` limit got exceeded, or no more
 * data is available.
 */

static ZyanStatus ZydisInputPeek(ZydisDecoderState* state,
    ZydisDecodedInstruction* instruction, ZyanU8* value)
{
    ZYAN_ASSERT(state);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(value);

    if (instruction->length >= ZYDIS_MAX_INSTRUCTION_LENGTH)
    {
        return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
    }

    if (state->buffer_len > 0)
    {
        *value = state->buffer[0];
        return ZYAN_STATUS_SUCCESS;
    }

    return ZYDIS_STATUS_NO_MORE_DATA;
}

/**
 * Increases the read-position of the input data-source by one byte.
 *
 * @param   state       A pointer to the `ZydisDecoderState` instance
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 *
 * This function is supposed to get called ONLY after a successful call of `ZydisInputPeek`.
 *
 * This function increases the `length` field of the `ZydisDecodedInstruction` struct by one.
 */

static void ZydisInputSkip(ZydisDecoderState* state, ZydisDecodedInstruction* instruction)
{
    ZYAN_ASSERT(state);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(instruction->length < ZYDIS_MAX_INSTRUCTION_LENGTH);

    ++instruction->length;
    ++state->buffer;
    --state->buffer_len;
}

/**
 * Reads one byte from the current read-position of the input data-source and increases
 *          the read-position by one byte afterwards.
 *
 * @param   state       A pointer to the `ZydisDecoderState` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   value       A pointer to the memory that receives the byte from the input data-source.
 *
 * @return  A zyan status code.
 *
 * This function acts like a subsequent call of `ZydisInputPeek` and `ZydisInputSkip`.
 */

static ZyanStatus ZydisInputNext(ZydisDecoderState* state,
    ZydisDecodedInstruction* instruction, ZyanU8* value)
{
    ZYAN_ASSERT(state);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(value);

    if (instruction->length >= ZYDIS_MAX_INSTRUCTION_LENGTH)
    {
        return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
    }

    if (state->buffer_len > 0)
    {
        *value = state->buffer++[0];
        ++instruction->length;
        --state->buffer_len;
        return ZYAN_STATUS_SUCCESS;
    }

    return ZYDIS_STATUS_NO_MORE_DATA;
}

/**
 * Reads a variable amount of bytes from the current read-position of the input
 *          data-source and increases the read-position by specified amount of bytes afterwards.
 *
 * @param   state           A pointer to the `ZydisDecoderState` struct.
 * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
 * @param   value           A pointer to the memory that receives the byte from the input
 *                          data-source.
 * @param   number_of_bytes The number of bytes to read from the input data-source.
 *
 * @return  A zyan status code.
 *
 * This function acts like a subsequent call of `ZydisInputPeek` and `ZydisInputSkip`.
 */

static ZyanStatus ZydisInputNextBytes(ZydisDecoderState* state,
    ZydisDecodedInstruction* instruction, ZyanU8* value, ZyanU8 number_of_bytes)
{
    ZYAN_ASSERT(state);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(value);

    if (instruction->length + number_of_bytes > ZYDIS_MAX_INSTRUCTION_LENGTH)
    {
        return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
    }

    if (state->buffer_len >= number_of_bytes)
    {
        instruction->length += number_of_bytes;

        ZYAN_MEMCPY(value, state->buffer, number_of_bytes);
        state->buffer += number_of_bytes;
        state->buffer_len -= number_of_bytes;

        return ZYAN_STATUS_SUCCESS;
    }

    return ZYDIS_STATUS_NO_MORE_DATA;
}

/* ---------------------------------------------------------------------------------------------- */
/* Decode functions                                                                               */
/* ---------------------------------------------------------------------------------------------- */

/**
 * Decodes the `REX`-prefix.
 *
 * @param   context     A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   data        The `REX` byte.
 */

static void ZydisDecodeREX(ZydisDecoderContext* context, ZydisDecodedInstruction* instruction,
    ZyanU8 data)
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT((data & 0xF0) == 0x40);

    instruction->attributes |= ZYDIS_ATTRIB_HAS_REX;
    instruction->raw.rex.W   = (data >> 3) & 0x01;
    instruction->raw.rex.R   = (data >> 2) & 0x01;
    instruction->raw.rex.X   = (data >> 1) & 0x01;
    instruction->raw.rex.B   = (data >> 0) & 0x01;

    // Update internal fields
    context->vector_unified.W = instruction->raw.rex.W;
    context->vector_unified.R = instruction->raw.rex.R;
    context->vector_unified.X = instruction->raw.rex.X;
    context->vector_unified.B = instruction->raw.rex.B;
}

/**
 * Decodes the `XOP`-prefix.
 *
 * @param   context     A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   data        The `XOP` bytes.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisDecodeXOP(ZydisDecoderContext* context,
    ZydisDecodedInstruction* instruction, const ZyanU8 data[3])
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(data[0] == 0x8F);
    ZYAN_ASSERT(((data[1] >> 0) & 0x1F) >= 8);
    ZYAN_ASSERT(instruction->raw.xop.offset == instruction->length - 3);

    if (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
    {
        // XOP is invalid in 16-bit real mode
        return ZYDIS_STATUS_DECODING_ERROR;
    }

    instruction->attributes |= ZYDIS_ATTRIB_HAS_XOP;
    instruction->raw.xop.R       = (data[1] >> 7) & 0x01;
    instruction->raw.xop.X       = (data[1] >> 6) & 0x01;
    instruction->raw.xop.B       = (data[1] >> 5) & 0x01;
    instruction->raw.xop.m_mmmm  = (data[1] >> 0) & 0x1F;

    if ((instruction->raw.xop.m_mmmm < 0x08) || (instruction->raw.xop.m_mmmm > 0x0A))
    {
        // Invalid according to the AMD documentation
        return ZYDIS_STATUS_INVALID_MAP;
    }

    instruction->raw.xop.W    = (data[2] >> 7) & 0x01;
    instruction->raw.xop.vvvv = (data[2] >> 3) & 0x0F;
    instruction->raw.xop.L    = (data[2] >> 2) & 0x01;
    instruction->raw.xop.pp   = (data[2] >> 0) & 0x03;

    // Update internal fields
    context->vector_unified.W    = instruction->raw.xop.W;
    context->vector_unified.R    = 0x01 & ~instruction->raw.xop.R;
    context->vector_unified.X    = 0x01 & ~instruction->raw.xop.X;
    context->vector_unified.B    = 0x01 & ~instruction->raw.xop.B;
    context->vector_unified.L    = instruction->raw.xop.L;
    context->vector_unified.LL   = instruction->raw.xop.L;
    context->vector_unified.vvvv = (0x0F & ~instruction->raw.xop.vvvv);

    return ZYAN_STATUS_SUCCESS;
}

/**
 * Decodes the `VEX`-prefix.
 *
 * @param   context     A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   data        The `VEX` bytes.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisDecodeVEX(ZydisDecoderContext* context,
    ZydisDecodedInstruction* instruction, const ZyanU8 data[3])
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT((data[0] == 0xC4) || (data[0] == 0xC5));

    if (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
    {
        // VEX is invalid in 16-bit real mode
        return ZYDIS_STATUS_DECODING_ERROR;
    }

    instruction->attributes |= ZYDIS_ATTRIB_HAS_VEX;
    switch (data[0])
    {
    case 0xC4:
        ZYAN_ASSERT(instruction->raw.vex.offset == instruction->length - 3);
        instruction->raw.vex.size    = 3;
        instruction->raw.vex.R       = (data[1] >> 7) & 0x01;
        instruction->raw.vex.X       = (data[1] >> 6) & 0x01;
        instruction->raw.vex.B       = (data[1] >> 5) & 0x01;
        instruction->raw.vex.m_mmmm  = (data[1] >> 0) & 0x1F;
        instruction->raw.vex.W       = (data[2] >> 7) & 0x01;
        instruction->raw.vex.vvvv    = (data[2] >> 3) & 0x0F;
        instruction->raw.vex.L       = (data[2] >> 2) & 0x01;
        instruction->raw.vex.pp      = (data[2] >> 0) & 0x03;
        break;
    case 0xC5:
        ZYAN_ASSERT(instruction->raw.vex.offset == instruction->length - 2);
        instruction->raw.vex.size    = 2;
        instruction->raw.vex.R       = (data[1] >> 7) & 0x01;
        instruction->raw.vex.X       = 1;
        instruction->raw.vex.B       = 1;
        instruction->raw.vex.m_mmmm  = 1;
        instruction->raw.vex.W       = 0;
        instruction->raw.vex.vvvv    = (data[1] >> 3) & 0x0F;
        instruction->raw.vex.L       = (data[1] >> 2) & 0x01;
        instruction->raw.vex.pp      = (data[1] >> 0) & 0x03;
        break;
    default:
        ZYAN_UNREACHABLE;
    }

    // Map 0 is only valid for some KNC instructions
#ifdef ZYDIS_DISABLE_KNC
    if ((instruction->raw.vex.m_mmmm == 0) || (instruction->raw.vex.m_mmmm > 0x03))
#else
    if (instruction->raw.vex.m_mmmm > 0x03)
#endif
    {
        // Invalid according to the intel documentation
        return ZYDIS_STATUS_INVALID_MAP;
    }

    // Update internal fields
    context->vector_unified.W    = instruction->raw.vex.W;
    context->vector_unified.R    = 0x01 & ~instruction->raw.vex.R;
    context->vector_unified.X    = 0x01 & ~instruction->raw.vex.X;
    context->vector_unified.B    = 0x01 & ~instruction->raw.vex.B;
    context->vector_unified.L    = instruction->raw.vex.L;
    context->vector_unified.LL   = instruction->raw.vex.L;
    context->vector_unified.vvvv = (0x0F & ~instruction->raw.vex.vvvv);

    return ZYAN_STATUS_SUCCESS;
}

#ifndef ZYDIS_DISABLE_AVX512
/**
 * Decodes the `EVEX`-prefix.
 *
 * @param   context     A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   data        The `EVEX` bytes.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisDecodeEVEX(ZydisDecoderContext* context,
    ZydisDecodedInstruction* instruction, const ZyanU8 data[4])
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(data[0] == 0x62);
    ZYAN_ASSERT(instruction->raw.evex.offset == instruction->length - 4);

    if (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
    {
        // EVEX is invalid in 16-bit real mode
        return ZYDIS_STATUS_DECODING_ERROR;
    }

    instruction->attributes |= ZYDIS_ATTRIB_HAS_EVEX;
    instruction->raw.evex.R         = (data[1] >> 7) & 0x01;
    instruction->raw.evex.X         = (data[1] >> 6) & 0x01;
    instruction->raw.evex.B         = (data[1] >> 5) & 0x01;
    instruction->raw.evex.R2        = (data[1] >> 4) & 0x01;

    if (data[1] & 0x08)
    {
        // Invalid according to the intel documentation
        return ZYDIS_STATUS_MALFORMED_EVEX;
    }

    instruction->raw.evex.mmm       = (data[1] >> 0) & 0x07;

    if ((instruction->raw.evex.mmm == 0x00) ||
        (instruction->raw.evex.mmm == 0x04) ||
        (instruction->raw.evex.mmm == 0x07))
    {
        // Invalid according to the intel documentation
        return ZYDIS_STATUS_INVALID_MAP;
    }

    instruction->raw.evex.W         = (data[2] >> 7) & 0x01;
    instruction->raw.evex.vvvv      = (data[2] >> 3) & 0x0F;

    ZYAN_ASSERT(((data[2] >> 2) & 0x01) == 0x01);

    instruction->raw.evex.pp        = (data[2] >> 0) & 0x03;
    instruction->raw.evex.z         = (data[3] >> 7) & 0x01;
    instruction->raw.evex.L2        = (data[3] >> 6) & 0x01;
    instruction->raw.evex.L         = (data[3] >> 5) & 0x01;
    instruction->raw.evex.b         = (data[3] >> 4) & 0x01;
    instruction->raw.evex.V2        = (data[3] >> 3) & 0x01;

    if (!instruction->raw.evex.V2 &&
        (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64))
    {
        return ZYDIS_STATUS_MALFORMED_EVEX;
    }

    instruction->raw.evex.aaa       = (data[3] >> 0) & 0x07;

    if (instruction->raw.evex.z && !instruction->raw.evex.aaa)
    {
        return ZYDIS_STATUS_INVALID_MASK; // TODO: Dedicated status code
    }

    // Update internal fields
    context->vector_unified.W    = instruction->raw.evex.W;
    context->vector_unified.R    = 0x01 & ~instruction->raw.evex.R;
    context->vector_unified.X    = 0x01 & ~instruction->raw.evex.X;
    context->vector_unified.B    = 0x01 & ~instruction->raw.evex.B;
    context->vector_unified.LL   = (data[3] >> 5) & 0x03;
    context->vector_unified.R2   = 0x01 & ~instruction->raw.evex.R2;
    context->vector_unified.V2   = 0x01 & ~instruction->raw.evex.V2;
    context->vector_unified.vvvv = 0x0F & ~instruction->raw.evex.vvvv;
    context->vector_unified.mask = instruction->raw.evex.aaa;

    if (!instruction->raw.evex.V2 && (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64))
    {
        return ZYDIS_STATUS_MALFORMED_EVEX;
    }
    if (!instruction->raw.evex.b && (context->vector_unified.LL == 3))
    {
        // LL = 3 is only valid for instructions with embedded rounding control
        return ZYDIS_STATUS_MALFORMED_EVEX;
    }

    return ZYAN_STATUS_SUCCESS;
}
#endif

#ifndef ZYDIS_DISABLE_KNC
/**
 * Decodes the `MVEX`-prefix.
 *
 * @param   context     A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   data        The `MVEX` bytes.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisDecodeMVEX(ZydisDecoderContext* context,
    ZydisDecodedInstruction* instruction, const ZyanU8 data[4])
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(data[0] == 0x62);
    ZYAN_ASSERT(instruction->raw.mvex.offset == instruction->length - 4);

    if (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
    {
        // MVEX is only valid in 64-bit mode
        return ZYDIS_STATUS_DECODING_ERROR;
    }

    instruction->attributes |= ZYDIS_ATTRIB_HAS_MVEX;
    instruction->raw.mvex.R    = (data[1] >> 7) & 0x01;
    instruction->raw.mvex.X    = (data[1] >> 6) & 0x01;
    instruction->raw.mvex.B    = (data[1] >> 5) & 0x01;
    instruction->raw.mvex.R2   = (data[1] >> 4) & 0x01;
    instruction->raw.mvex.mmmm = (data[1] >> 0) & 0x0F;

    if (instruction->raw.mvex.mmmm > 0x03)
    {
        // Invalid according to the intel documentation
        return ZYDIS_STATUS_INVALID_MAP;
    }

    instruction->raw.mvex.W    = (data[2] >> 7) & 0x01;
    instruction->raw.mvex.vvvv = (data[2] >> 3) & 0x0F;

    ZYAN_ASSERT(((data[2] >> 2) & 0x01) == 0x00);

    instruction->raw.mvex.pp   = (data[2] >> 0) & 0x03;
    instruction->raw.mvex.E    = (data[3] >> 7) & 0x01;
    instruction->raw.mvex.SSS  = (data[3] >> 4) & 0x07;
    instruction->raw.mvex.V2   = (data[3] >> 3) & 0x01;
    instruction->raw.mvex.kkk  = (data[3] >> 0) & 0x07;

    // Update internal fields
    context->vector_unified.W    = instruction->raw.mvex.W;
    context->vector_unified.R    = 0x01 & ~instruction->raw.mvex.R;
    context->vector_unified.X    = 0x01 & ~instruction->raw.mvex.X;
    context->vector_unified.B    = 0x01 & ~instruction->raw.mvex.B;
    context->vector_unified.R2   = 0x01 & ~instruction->raw.mvex.R2;
    context->vector_unified.V2   = 0x01 & ~instruction->raw.mvex.V2;
    context->vector_unified.LL   = 2;
    context->vector_unified.vvvv = 0x0F & ~instruction->raw.mvex.vvvv;
    context->vector_unified.mask = instruction->raw.mvex.kkk;

    return ZYAN_STATUS_SUCCESS;
}
#endif

/**
 * Decodes the `ModRM`-byte.
 *
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   data        The `ModRM` byte.
 */

static void ZydisDecodeModRM(ZydisDecodedInstruction* instruction, ZyanU8 data)
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM));
    ZYAN_ASSERT(instruction->raw.modrm.offset == instruction->length - 1);

    instruction->attributes   |= ZYDIS_ATTRIB_HAS_MODRM;
    instruction->raw.modrm.mod = (data >> 6) & 0x03;
    instruction->raw.modrm.reg = (data >> 3) & 0x07;
    instruction->raw.modrm.rm  = (data >> 0) & 0x07;
}

/**
 * Decodes the `SIB`-byte.
 *
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct
 * @param   data        The `SIB` byte.
 */

static void ZydisDecodeSIB(ZydisDecodedInstruction* instruction, ZyanU8 data)
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM);
    ZYAN_ASSERT(instruction->raw.modrm.rm == 4);
    ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB));
    ZYAN_ASSERT(instruction->raw.sib.offset == instruction->length - 1);

    instruction->attributes    |= ZYDIS_ATTRIB_HAS_SIB;
    instruction->raw.sib.scale = (data >> 6) & 0x03;
    instruction->raw.sib.index = (data >> 3) & 0x07;
    instruction->raw.sib.base  = (data >> 0) & 0x07;
}

/* ---------------------------------------------------------------------------------------------- */

/**
 * Reads a displacement value.
 *
 * @param   state       A pointer to the `ZydisDecoderState` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   size        The physical size of the displacement value.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisReadDisplacement(ZydisDecoderState* state,
    ZydisDecodedInstruction* instruction, ZyanU8 size)
{
    ZYAN_ASSERT(state);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(instruction->raw.disp.size == 0);

    instruction->raw.disp.size = size;
    instruction->raw.disp.offset = instruction->length;

    switch (size)
    {
    case 8:
    {
        ZyanU8 value;
        ZYAN_CHECK(ZydisInputNext(state, instruction, &value));
        instruction->raw.disp.value = *(ZyanI8*)&value;
        break;
    }
    case 16:
    {
        ZyanU16 value;
        ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 2));
        instruction->raw.disp.value = *(ZyanI16*)&value;
        break;
    }
    case 32:
    {
        ZyanU32 value;
        ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 4));
        instruction->raw.disp.value = *(ZyanI32*)&value;
        break;
    }
    case 64:
    {
        ZyanU64 value;
        ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 8));
        instruction->raw.disp.value = *(ZyanI64*)&value;
        break;
    }
    default:
        ZYAN_UNREACHABLE;
    }

    // TODO: Fix endianess on big-endian systems

    return ZYAN_STATUS_SUCCESS;
}

/**
 * Reads an immediate value.
 *
 * @param   state       A pointer to the `ZydisDecoderState` struct.
 * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
 * @param   id          The immediate id (either `0` or `1`).
 * @param   size        The physical size of the immediate value.
 * @param   is_signed   Signals, if the immediate value is signed.
 * @param   is_relative Signals, if the immediate value is a relative offset.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisReadImmediate(ZydisDecoderState* state,
    ZydisDecodedInstruction* instruction, ZyanU8 id, ZyanU8 size, ZyanBool is_signed,
    ZyanBool is_relative)
{
    ZYAN_ASSERT(state);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT((id == 0) || (id == 1));
    ZYAN_ASSERT(is_signed || !is_relative);
    ZYAN_ASSERT(instruction->raw.imm[id].size == 0);

    instruction->raw.imm[id].size = size;
    instruction->raw.imm[id].offset = instruction->length;
    instruction->raw.imm[id].is_signed = is_signed;
    instruction->raw.imm[id].is_relative = is_relative;
    switch (size)
    {
    case 8:
    {
        ZyanU8 value;
        ZYAN_CHECK(ZydisInputNext(state, instruction, &value));
        if (is_signed)
        {
            instruction->raw.imm[id].value.s = (ZyanI8)value;
        } else
        {
            instruction->raw.imm[id].value.u = value;
        }
        break;
    }
    case 16:
    {
        ZyanU16 value;
        ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 2));
        if (is_signed)
        {
            instruction->raw.imm[id].value.s = (ZyanI16)value;
        } else
        {
            instruction->raw.imm[id].value.u = value;
        }
        break;
    }
    case 32:
    {
        ZyanU32 value;
        ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 4));
        if (is_signed)
        {
            instruction->raw.imm[id].value.s = (ZyanI32)value;
        } else
        {
            instruction->raw.imm[id].value.u = value;
        }
        break;
    }
    case 64:
    {
        ZyanU64 value;
        ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 8));
        if (is_signed)
        {
            instruction->raw.imm[id].value.s = (ZyanI64)value;
        } else
        {
            instruction->raw.imm[id].value.u = value;
        }
        break;
    }
    default:
        ZYAN_UNREACHABLE;
    }

    // TODO: Fix endianess on big-endian systems

    return ZYAN_STATUS_SUCCESS;
}

/* ---------------------------------------------------------------------------------------------- */
/* Semantic instruction decoding                                                                  */
/* ---------------------------------------------------------------------------------------------- */

#ifndef ZYDIS_MINIMAL_MODE
/**
 * Calculates the register-id for a specific register-encoding and register-class.
 *
 * @param   context         A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction     A pointer to the ` ZydisDecodedInstruction` struct.
 * @param   encoding        The register-encoding.
 * @param   register_class  The register-class.
 *
 * @return  A zyan status code.
 *
 * This function calculates the register-id by combining different fields and flags of previously
 * decoded structs.
 */

static ZyanU8 ZydisCalcRegisterId(const ZydisDecoderContext* context,
    const ZydisDecodedInstruction* instruction, ZydisRegisterEncoding encoding,
    ZydisRegisterClass register_class)
{
    ZYAN_ASSERT(context);
    ZYAN_ASSERT(instruction);

    // TODO: Combine OPCODE and IS4 in `ZydisPopulateRegisterIds` and get rid of this
    // TODO: function entirely

    switch (encoding)
    {
    case ZYDIS_REG_ENCODING_REG:
        return context->reg_info.id_reg;
    case ZYDIS_REG_ENCODING_NDSNDD:
        return context->reg_info.id_ndsndd;
    case ZYDIS_REG_ENCODING_RM:
        return context->reg_info.id_rm;
    case ZYDIS_REG_ENCODING_BASE:
        return context->reg_info.id_base;
    case ZYDIS_REG_ENCODING_INDEX:
    case ZYDIS_REG_ENCODING_VIDX:
        return context->reg_info.id_index;
    case ZYDIS_REG_ENCODING_OPCODE:
    {
        ZYAN_ASSERT((register_class == ZYDIS_REGCLASS_GPR8) ||
                    (register_class == ZYDIS_REGCLASS_GPR16) ||
                    (register_class == ZYDIS_REGCLASS_GPR32) ||
                    (register_class == ZYDIS_REGCLASS_GPR64));
        ZyanU8 value = (instruction->opcode & 0x0F);
        if (value > 7)
        {
            value = value - 8;
        }
        if (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
        {
            return value;
        }
        return value | (context->vector_unified.B << 3);
    }
    case ZYDIS_REG_ENCODING_IS4:
    {
        if (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
        {
            return (instruction->raw.imm[0].value.u >> 4) & 0x07;
        }
        ZyanU8 value = (instruction->raw.imm[0].value.u >> 4) & 0x0F;
        // We have to check the instruction-encoding, because the extension by bit [3] is only
        // valid for EVEX and MVEX instructions
        if ((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
            (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
        {
            switch (register_class)
            {
            case ZYDIS_REGCLASS_XMM:
            case ZYDIS_REGCLASS_YMM:
            case ZYDIS_REGCLASS_ZMM:
                value |= ((instruction->raw.imm[0].value.u & 0x08) << 1);
            default:
                break;
            }
        }
        return value;
    }
    case ZYDIS_REG_ENCODING_MASK:
        return context->vector_unified.mask;
    default:
        ZYAN_UNREACHABLE;
    }
}
#endif

#ifndef ZYDIS_MINIMAL_MODE
/**
 * Sets the operand-size and element-specific information for the given operand.
 *
 * @param   context         A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
 * @param   operand         A pointer to the `ZydisDecodedOperand` struct.
 * @param   definition      A pointer to the `ZydisOperandDefinition` struct.
 */

static void ZydisSetOperandSizeAndElementInfo(const ZydisDecoderContext* context,
    const ZydisDecodedInstruction* instruction, ZydisDecodedOperand* operand,
    const ZydisOperandDefinition* definition)
{
    ZYAN_ASSERT(context);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(operand);
    ZYAN_ASSERT(definition);

    // Operand size
    switch (operand->type)
    {
    case ZYDIS_OPERAND_TYPE_REGISTER:
    {
        if (definition->size[context->eosz_index])
        {
            operand->size = definition->size[context->eosz_index] * 8;
        } else
        {
            operand->size = ZydisRegisterGetWidth(instruction->machine_mode,
                operand->reg.value);
        }
        operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
        operand->element_size = operand->size;
        break;
    }
    case ZYDIS_OPERAND_TYPE_MEMORY:
        switch (instruction->encoding)
        {
        case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
        case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
        case ZYDIS_INSTRUCTION_ENCODING_XOP:
        case ZYDIS_INSTRUCTION_ENCODING_VEX:
            if (operand->mem.type == ZYDIS_MEMOP_TYPE_AGEN)
            {
                ZYAN_ASSERT(definition->size[context->eosz_index] == 0);
                operand->size = instruction->address_width;
                operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
            } else
            {
                ZYAN_ASSERT(definition->size[context->eosz_index] ||
                    (instruction->meta.category == ZYDIS_CATEGORY_AMX_TILE));
                operand->size = definition->size[context->eosz_index] * 8;
            }
            break;
        case ZYDIS_INSTRUCTION_ENCODING_EVEX:
#ifndef ZYDIS_DISABLE_AVX512
            if (definition->size[context->eosz_index])
            {
                // Operand size is hardcoded
                operand->size = definition->size[context->eosz_index] * 8;
            } else
            {
                // Operand size depends on the tuple-type, the element-size and the number of
                // elements
                ZYAN_ASSERT(instruction->avx.vector_length);
                ZYAN_ASSERT(context->evex.element_size);
                switch (context->evex.tuple_type)
                {
                case ZYDIS_TUPLETYPE_FV:
                    if (instruction->avx.broadcast.mode)
                    {
                        operand->size = context->evex.element_size;
                    } else
                    {
                        operand->size = instruction->avx.vector_length;
                    }
                    break;
                case ZYDIS_TUPLETYPE_HV:
                    if (instruction->avx.broadcast.mode)
                    {
                        operand->size = context->evex.element_size;
                    } else
                    {
                        operand->size = (ZyanU16)instruction->avx.vector_length / 2;
                    }
                    break;
                case ZYDIS_TUPLETYPE_QUARTER:
                    if (instruction->avx.broadcast.mode)
                    {
                        operand->size = context->evex.element_size;
                    }
                    else
                    {
                        operand->size = (ZyanU16)instruction->avx.vector_length / 4;
                    }
                    break;
                default:
                    ZYAN_UNREACHABLE;
                }
            }
            ZYAN_ASSERT(operand->size);
#else
            ZYAN_UNREACHABLE;
#endif
            break;
        case ZYDIS_INSTRUCTION_ENCODING_MVEX:
#ifndef ZYDIS_DISABLE_KNC
            if (definition->size[context->eosz_index])
            {
                // Operand size is hardcoded
                operand->size = definition->size[context->eosz_index] * 8;
            } else
            {
                ZYAN_ASSERT(definition->element_type == ZYDIS_IELEMENT_TYPE_VARIABLE);
                ZYAN_ASSERT(instruction->avx.vector_length == 512);

                switch (instruction->avx.conversion.mode)
                {
                case ZYDIS_CONVERSION_MODE_INVALID:
                    operand->size = 512;
                    switch (context->mvex.functionality)
                    {
                    case ZYDIS_MVEX_FUNC_SF_32:
                    case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
                    case ZYDIS_MVEX_FUNC_UF_32:
                    case ZYDIS_MVEX_FUNC_DF_32:
                        operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT32;
                        operand->element_size = 32;
                        break;
                    case ZYDIS_MVEX_FUNC_SF_32_BCST:
                        operand->size = 256;
                        operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT32;
                        operand->element_size = 32;
                        break;
                    case ZYDIS_MVEX_FUNC_SI_32:
                    case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
                    case ZYDIS_MVEX_FUNC_UI_32:
                    case ZYDIS_MVEX_FUNC_DI_32:
                        operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
                        operand->element_size = 32;
                        break;
                    case ZYDIS_MVEX_FUNC_SI_32_BCST:
                        operand->size = 256;
                        operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
                        operand->element_size = 32;
                        break;
                    case ZYDIS_MVEX_FUNC_SF_64:
                    case ZYDIS_MVEX_FUNC_UF_64:
                    case ZYDIS_MVEX_FUNC_DF_64:
                        operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT64;
                        operand->element_size = 64;
                        break;
                    case ZYDIS_MVEX_FUNC_SI_64:
                    case ZYDIS_MVEX_FUNC_UI_64:
                    case ZYDIS_MVEX_FUNC_DI_64:
                        operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
                        operand->element_size = 64;
                        break;
                    default:
                        ZYAN_UNREACHABLE;
                    }
                    break;
                case ZYDIS_CONVERSION_MODE_FLOAT16:
                    operand->size = 256;
                    operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT16;
                    operand->element_size = 16;
                    break;
                case ZYDIS_CONVERSION_MODE_SINT16:
                    operand->size = 256;
                    operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
                    operand->element_size = 16;
                    break;
                case ZYDIS_CONVERSION_MODE_UINT16:
                    operand->size = 256;
                    operand->element_type = ZYDIS_ELEMENT_TYPE_UINT;
                    operand->element_size = 16;
                    break;
                case ZYDIS_CONVERSION_MODE_SINT8:
                    operand->size = 128;
                    operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
                    operand->element_size = 8;
                    break;
                case ZYDIS_CONVERSION_MODE_UINT8:
                    operand->size = 128;
                    operand->element_type = ZYDIS_ELEMENT_TYPE_UINT;
                    operand->element_size = 8;
                    break;
                default:
                    ZYAN_UNREACHABLE;
                }

                switch (instruction->avx.broadcast.mode)
                {
                case ZYDIS_BROADCAST_MODE_INVALID:
                    // Nothing to do here
                    break;
                case ZYDIS_BROADCAST_MODE_1_TO_8:
                case ZYDIS_BROADCAST_MODE_1_TO_16:
                    operand->size = operand->element_size;
                    break;
                case ZYDIS_BROADCAST_MODE_4_TO_8:
                case ZYDIS_BROADCAST_MODE_4_TO_16:
                    operand->size = operand->element_size * 4;
                    break;
                default:
                    ZYAN_UNREACHABLE;
                }
            }
#else
            ZYAN_UNREACHABLE;
#endif
            break;
        default:
            ZYAN_UNREACHABLE;
        }
        break;
    case ZYDIS_OPERAND_TYPE_POINTER:
        ZYAN_ASSERT((instruction->raw.imm[0].size == 16) ||
                    (instruction->raw.imm[0].size == 32));
        ZYAN_ASSERT( instruction->raw.imm[1].size == 16);
        operand->size = instruction->raw.imm[0].size + instruction->raw.imm[1].size;
        break;
    case ZYDIS_OPERAND_TYPE_IMMEDIATE:
        operand->size = definition->size[context->eosz_index] * 8;
        break;
    default:
        ZYAN_UNREACHABLE;
    }

    // Element-type and -size
    if (definition->element_type && (definition->element_type != ZYDIS_IELEMENT_TYPE_VARIABLE))
    {
        ZydisGetElementInfo(definition->element_type, &operand->element_type,
            &operand->element_size);
        if (!operand->element_size)
        {
            // The element size is the same as the operand size. This is used for single element
            // scaling operands
            operand->element_size = operand->size;
        }
    }

    // Element count
    if (operand->element_size && operand->size && (operand->element_type != ZYDIS_ELEMENT_TYPE_CC))
    {
        operand->element_count = operand->size / operand->element_size;
    } else
    {
        operand->element_count = 1;
    }
}
#endif

#ifndef ZYDIS_MINIMAL_MODE
/**
 * Decodes an register-operand.
 *
 * @param   instruction      A pointer to the `ZydisDecodedInstruction` struct.
 * @param   operand          A pointer to the `ZydisDecodedOperand` struct.
 * @param   register_class   The register class.
 * @param   register_id      The register id.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisDecodeOperandRegister(const ZydisDecodedInstruction* instruction,
    ZydisDecodedOperand* operand, ZydisRegisterClass register_class, ZyanU8 register_id)
{
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(operand);

    operand->type = ZYDIS_OPERAND_TYPE_REGISTER;

    if (register_class == ZYDIS_REGCLASS_GPR8)
    {
        if ((instruction->attributes & ZYDIS_ATTRIB_HAS_REX) && (register_id >= 4))
        {
            operand->reg.value = ZYDIS_REGISTER_SPL + (register_id - 4);
        } else
        {
            operand->reg.value = ZYDIS_REGISTER_AL + register_id;
        }
    } else
    {
        operand->reg.value = ZydisRegisterEncode(register_class, register_id);
        ZYAN_ASSERT(operand->reg.value);
        /*if (!operand->reg.value)
        {
            return ZYAN_STATUS_BAD_REGISTER;
        }*/

    }

    return ZYAN_STATUS_SUCCESS;
}
#endif

#ifndef ZYDIS_MINIMAL_MODE
/**
 * Decodes a memory operand.
 *
 * @param   context             A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction         A pointer to the `ZydisDecodedInstruction` struct.
 * @param   operand             A pointer to the `ZydisDecodedOperand` struct.
 * @param   vidx_register_class The register-class to use as the index register-class for
 *                              instructions with `VSIB` addressing.
 *
 * @return  A zyan status code.
 */

static ZyanStatus ZydisDecodeOperandMemory(const ZydisDecoderContext* context,
    const ZydisDecodedInstruction* instruction, ZydisDecodedOperand* operand,
    ZydisRegisterClass vidx_register_class)
{
    ZYAN_ASSERT(context);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(operand);
    ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM);
    ZYAN_ASSERT(instruction->raw.modrm.mod != 3);
    ZYAN_ASSERT(!vidx_register_class || ((instruction->raw.modrm.rm == 4) &&
        ((instruction->address_width == 32) || (instruction->address_width == 64))));

    operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
    operand->mem.type = ZYDIS_MEMOP_TYPE_MEM;

    const ZyanU8 modrm_rm = instruction->raw.modrm.rm;
    ZyanU8 displacement_size = 0;
    switch (instruction->address_width)
    {
    case 16:
    {
        static const ZydisRegister bases[] =
        {
            ZYDIS_REGISTER_BX,   ZYDIS_REGISTER_BX,   ZYDIS_REGISTER_BP,   ZYDIS_REGISTER_BP,
            ZYDIS_REGISTER_SI,   ZYDIS_REGISTER_DI,   ZYDIS_REGISTER_BP,   ZYDIS_REGISTER_BX
        };
        static const ZydisRegister indices[] =
        {
            ZYDIS_REGISTER_SI,   ZYDIS_REGISTER_DI,   ZYDIS_REGISTER_SI,   ZYDIS_REGISTER_DI,
            ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE
        };
        operand->mem.base = bases[modrm_rm];
        operand->mem.index = indices[modrm_rm];
        operand->mem.scale = (operand->mem.index == ZYDIS_REGISTER_NONE) ? 0 : 1;
        switch (instruction->raw.modrm.mod)
        {
        case 0:
            if (modrm_rm == 6)
            {
                displacement_size = 16;
                operand->mem.base = ZYDIS_REGISTER_NONE;
            }
            break;
        case 1:
            displacement_size = 8;
            break;
        case 2:
            displacement_size = 16;
            break;
        default:
            ZYAN_UNREACHABLE;
        }
        break;
    }
    case 32:
    {
        operand->mem.base = ZYDIS_REGISTER_EAX + ZydisCalcRegisterId(context, instruction,
            ZYDIS_REG_ENCODING_BASE, ZYDIS_REGCLASS_GPR32);
        switch (instruction->raw.modrm.mod)
        {
        case 0:
            if (modrm_rm == 5)
            {
                if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
                {
                    operand->mem.base = ZYDIS_REGISTER_EIP;
                } else
                {
                    operand->mem.base = ZYDIS_REGISTER_NONE;
                }
                displacement_size = 32;
            }
            break;
        case 1:
            displacement_size = 8;
            break;
        case 2:
            displacement_size = 32;
            break;
        default:
            ZYAN_UNREACHABLE;
        }
        if (modrm_rm == 4)
        {
            ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB);
            operand->mem.index =
                ZydisRegisterEncode(vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR32,
                    ZydisCalcRegisterId(context, instruction,
                        vidx_register_class ? ZYDIS_REG_ENCODING_VIDX : ZYDIS_REG_ENCODING_INDEX,
                        vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR32));
            operand->mem.scale = (1 << instruction->raw.sib.scale);
            if (operand->mem.index == ZYDIS_REGISTER_ESP)
            {
                operand->mem.index = ZYDIS_REGISTER_NONE;
                operand->mem.scale = 0;
            }
            if (operand->mem.base == ZYDIS_REGISTER_EBP)
            {
                if (instruction->raw.modrm.mod == 0)
                {
                    operand->mem.base = ZYDIS_REGISTER_NONE;
                }
                displacement_size = (instruction->raw.modrm.mod == 1) ? 8 : 32;
            }
        } else
        {
            operand->mem.index = ZYDIS_REGISTER_NONE;
            operand->mem.scale = 0;
        }
        break;
    }
    case 64:
    {
        operand->mem.base = ZYDIS_REGISTER_RAX + ZydisCalcRegisterId(context, instruction,
            ZYDIS_REG_ENCODING_BASE, ZYDIS_REGCLASS_GPR64);
        switch (instruction->raw.modrm.mod)
        {
        case 0:
            if (modrm_rm == 5)
            {
                if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
                {
                    operand->mem.base = ZYDIS_REGISTER_RIP;
                } else
                {
                    operand->mem.base = ZYDIS_REGISTER_NONE;
                }
                displacement_size = 32;
            }
            break;
        case 1:
            displacement_size = 8;
            break;
        case 2:
            displacement_size = 32;
            break;
        default:
            ZYAN_UNREACHABLE;
        }
        if ((modrm_rm & 0x07) == 4)
        {
            ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB);
            operand->mem.index =
                ZydisRegisterEncode(vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR64,
                    ZydisCalcRegisterId(context, instruction,
                        vidx_register_class ? ZYDIS_REG_ENCODING_VIDX : ZYDIS_REG_ENCODING_INDEX,
                        vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR64));
            operand->mem.scale = (1 << instruction->raw.sib.scale);
            if (operand->mem.index == ZYDIS_REGISTER_RSP)
            {
                operand->mem.index = ZYDIS_REGISTER_NONE;
                operand->mem.scale = 0;
            }
            if ((operand->mem.base == ZYDIS_REGISTER_RBP) ||
                (operand->mem.base == ZYDIS_REGISTER_R13))
            {
                if (instruction->raw.modrm.mod == 0)
                {
                    operand->mem.base = ZYDIS_REGISTER_NONE;
                }
                displacement_size = (instruction->raw.modrm.mod == 1) ? 8 : 32;
            }
        } else
        {
            operand->mem.index = ZYDIS_REGISTER_NONE;
            operand->mem.scale = 0;
        }
        break;
    }
    default:
        ZYAN_UNREACHABLE;
    }
    if (displacement_size)
    {
        ZYAN_ASSERT(instruction->raw.disp.size == displacement_size);
        operand->mem.disp.has_displacement = ZYAN_TRUE;
        operand->mem.disp.value = instruction->raw.disp.value;
    }
    return ZYAN_STATUS_SUCCESS;
}
#endif

#ifndef ZYDIS_MINIMAL_MODE
/**
 * Decodes an implicit register operand.
 *
 * @param   decoder         A pointer to the `ZydisDecoder` instance.
 * @param   context         A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
 * @param   operand         A pointer to the `ZydisDecodedOperand` struct.
 * @param   definition      A pointer to the `ZydisOperandDefinition` struct.
 */

static void ZydisDecodeOperandImplicitRegister(const ZydisDecoder* decoder,
    const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
    ZydisDecodedOperand* operand, const ZydisOperandDefinition* definition)
{
    ZYAN_ASSERT(context);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(operand);
    ZYAN_ASSERT(definition);

    operand->type = ZYDIS_OPERAND_TYPE_REGISTER;

    switch (definition->op.reg.type)
    {
    case ZYDIS_IMPLREG_TYPE_STATIC:
        operand->reg.value = definition->op.reg.reg.reg;
        break;
    case ZYDIS_IMPLREG_TYPE_GPR_OSZ:
    {
        static const ZydisRegisterClass lookup[3] =
        {
            ZYDIS_REGCLASS_GPR16,
            ZYDIS_REGCLASS_GPR32,
            ZYDIS_REGCLASS_GPR64
        };
        operand->reg.value =
            ZydisRegisterEncode(lookup[context->eosz_index], definition->op.reg.reg.id);
        break;
    }
    case ZYDIS_IMPLREG_TYPE_GPR_ASZ:
        operand->reg.value = ZydisRegisterEncode(
            (instruction->address_width    == 16) ? ZYDIS_REGCLASS_GPR16  :
            (instruction->address_width    == 32) ? ZYDIS_REGCLASS_GPR32  : ZYDIS_REGCLASS_GPR64,
            definition->op.reg.reg.id);
        break;
    case ZYDIS_IMPLREG_TYPE_IP_ASZ:
        operand->reg.value =
            (instruction->address_width    == 16) ? ZYDIS_REGISTER_IP     :
            (instruction->address_width    == 32) ? ZYDIS_REGISTER_EIP    : ZYDIS_REGISTER_RIP;
        break;
    case ZYDIS_IMPLREG_TYPE_GPR_SSZ:
        operand->reg.value = ZydisRegisterEncode(
            (decoder->stack_width == ZYDIS_STACK_WIDTH_16) ? ZYDIS_REGCLASS_GPR16 :
            (decoder->stack_width == ZYDIS_STACK_WIDTH_32) ? ZYDIS_REGCLASS_GPR32 :
                                                             ZYDIS_REGCLASS_GPR64,
            definition->op.reg.reg.id);
        break;
    case ZYDIS_IMPLREG_TYPE_IP_SSZ:
        operand->reg.value =
            (decoder->stack_width == ZYDIS_STACK_WIDTH_16) ? ZYDIS_REGISTER_EIP    :
            (decoder->stack_width == ZYDIS_STACK_WIDTH_32) ? ZYDIS_REGISTER_EIP    :
                                                             ZYDIS_REGISTER_RIP;
        break;
    case ZYDIS_IMPLREG_TYPE_FLAGS_SSZ:
        operand->reg.value =
            (decoder->stack_width == ZYDIS_STACK_WIDTH_16) ? ZYDIS_REGISTER_FLAGS  :
            (decoder->stack_width == ZYDIS_STACK_WIDTH_32) ? ZYDIS_REGISTER_EFLAGS :
                                                             ZYDIS_REGISTER_RFLAGS;
        break;
    default:
        ZYAN_UNREACHABLE;
    }
}
#endif

#ifndef ZYDIS_MINIMAL_MODE
/**
 * Decodes an implicit memory operand.
 *
 * @param   decoder         A pointer to the `ZydisDecoder` instance.
 * @param   context         A pointer to the `ZydisDecoderContext` struct.
 * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
 * @param   operand         A pointer to the `ZydisDecodedOperand` struct.
 * @param   definition      A pointer to the `ZydisOperandDefinition` struct.
 */

static void ZydisDecodeOperandImplicitMemory(const ZydisDecoder* decoder,
    const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
    ZydisDecodedOperand* operand, const ZydisOperandDefinition* definition)
{
    ZYAN_ASSERT(context);
    ZYAN_ASSERT(operand);
    ZYAN_ASSERT(definition);

    static const ZydisRegisterClass lookup[3] =
    {
        ZYDIS_REGCLASS_GPR16,
        ZYDIS_REGCLASS_GPR32,
        ZYDIS_REGCLASS_GPR64
    };

    operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
    operand->mem.type = ZYDIS_MEMOP_TYPE_MEM;

    switch (definition->op.mem.base)
    {
    case ZYDIS_IMPLMEM_BASE_AGPR_REG:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index],
            ZydisCalcRegisterId(context, instruction, ZYDIS_REG_ENCODING_REG,
                lookup[context->easz_index]));
        break;
    case ZYDIS_IMPLMEM_BASE_AGPR_RM:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index],
            ZydisCalcRegisterId(context, instruction, ZYDIS_REG_ENCODING_RM,
                lookup[context->easz_index]));
        break;
    case ZYDIS_IMPLMEM_BASE_AAX:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 0);
        break;
    case ZYDIS_IMPLMEM_BASE_ADX:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 2);
        break;
    case ZYDIS_IMPLMEM_BASE_ABX:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 3);
        break;
    case ZYDIS_IMPLMEM_BASE_ASI:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 6);
        break;
    case ZYDIS_IMPLMEM_BASE_ADI:
        operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 7);
        break;
    case ZYDIS_IMPLMEM_BASE_SSP:
        operand->mem.base = ZydisRegisterEncode(lookup[decoder->stack_width], 4);
        break;
    case ZYDIS_IMPLMEM_BASE_SBP:
        operand->mem.base = ZydisRegisterEncode(lookup[decoder->stack_width], 5);
        break;
    default:
        ZYAN_UNREACHABLE;
    }

    if (definition->op.mem.seg)
    {
        operand->mem.segment =
            ZydisRegisterEncode(ZYDIS_REGCLASS_SEGMENT, definition->op.mem.seg - 1);
        ZYAN_ASSERT(operand->mem.segment);
    }
}
#endif

#ifndef ZYDIS_MINIMAL_MODE
static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDecoderContext* context,
    const ZydisDecodedInstruction* instruction, ZydisDecodedOperand* operands, ZyanU8 operand_count)
{
    ZYAN_ASSERT(decoder);
    ZYAN_ASSERT(context);
    ZYAN_ASSERT(context->definition);
    ZYAN_ASSERT(instruction);
    ZYAN_ASSERT(operands);
    ZYAN_ASSERT(operand_count);
    ZYAN_ASSERT(operand_count <= instruction->operand_count);

    const ZydisInstructionDefinition* definition = context->definition;
    const ZydisOperandDefinition* operand = ZydisGetOperandDefinitions(definition);

    ZYAN_MEMSET(operands, 0, sizeof(ZydisDecodedOperand) * operand_count);

    ZyanU8 imm_id = 0;
    for (ZyanU8 i = 0; i < operand_count; ++i)
    {
        ZydisRegisterClass register_class = ZYDIS_REGCLASS_INVALID;

        operands[i].id = i;
        operands[i].visibility = operand->visibility;
        operands[i].actions = operand->actions;
        ZYAN_ASSERT(!(operand->actions &
            ZYDIS_OPERAND_ACTION_READ & ZYDIS_OPERAND_ACTION_CONDREAD) ||
            (operand->actions & ZYDIS_OPERAND_ACTION_READ) ^
            (operand->actions & ZYDIS_OPERAND_ACTION_CONDREAD));
        ZYAN_ASSERT(!(operand->actions &
            ZYDIS_OPERAND_ACTION_WRITE & ZYDIS_OPERAND_ACTION_CONDWRITE) ||
            (operand->actions & ZYDIS_OPERAND_ACTION_WRITE) ^
            (operand->actions & ZYDIS_OPERAND_ACTION_CONDWRITE));

        // Implicit operands
        switch (operand->type)
        {
        case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG:
            ZydisDecodeOperandImplicitRegister(decoder, context, instruction, &operands[i], operand);
            break;
        case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_MEM:
            ZydisDecodeOperandImplicitMemory(decoder, context, instruction, &operands[i], operand);
            break;
        case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1:
            operands[i].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
            operands[i].size = 8;
            operands[i].imm.value.u = 1;
            operands[i].imm.is_signed = ZYAN_FALSE;
            operands[i].imm.is_relative = ZYAN_FALSE;
            break;
        default:
            break;
        }
        if (operands[i].type)
        {
            goto FinalizeOperand;
        }

        operands[i].encoding = operand->op.encoding;

        // Register operands
        switch (operand->type)
        {
        case ZYDIS_SEMANTIC_OPTYPE_GPR8:
            register_class = ZYDIS_REGCLASS_GPR8;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR16:
            register_class = ZYDIS_REGCLASS_GPR16;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR32:
            register_class = ZYDIS_REGCLASS_GPR32;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR64:
            register_class = ZYDIS_REGCLASS_GPR64;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64:
            ZYAN_ASSERT((instruction->operand_width == 16) || (instruction->operand_width == 32) ||
                (instruction->operand_width == 64));
            register_class =
                (instruction->operand_width == 16) ? ZYDIS_REGCLASS_GPR16 : (
                    (instruction->operand_width == 32) ? ZYDIS_REGCLASS_GPR32 : ZYDIS_REGCLASS_GPR64);
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64:
            ZYAN_ASSERT((instruction->operand_width == 16) || (instruction->operand_width == 32) ||
                (instruction->operand_width == 64));
            register_class =
                (instruction->operand_width == 16) ? ZYDIS_REGCLASS_GPR32 : (
                    (instruction->operand_width == 32) ? ZYDIS_REGCLASS_GPR32 : ZYDIS_REGCLASS_GPR64);
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32:
            ZYAN_ASSERT((instruction->operand_width == 16) || (instruction->operand_width == 32) ||
                (instruction->operand_width == 64));
            register_class =
                (instruction->operand_width == 16) ? ZYDIS_REGCLASS_GPR16 : ZYDIS_REGCLASS_GPR32;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ:
            ZYAN_ASSERT((instruction->address_width == 16) || (instruction->address_width == 32) ||
                (instruction->address_width == 64));
            register_class =
                (instruction->address_width == 16) ? ZYDIS_REGCLASS_GPR16 : (
                    (instruction->address_width == 32) ? ZYDIS_REGCLASS_GPR32 : ZYDIS_REGCLASS_GPR64);
            break;
        case ZYDIS_SEMANTIC_OPTYPE_FPR:
            register_class = ZYDIS_REGCLASS_X87;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_MMX:
            register_class = ZYDIS_REGCLASS_MMX;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_XMM:
            register_class = ZYDIS_REGCLASS_XMM;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_YMM:
            register_class = ZYDIS_REGCLASS_YMM;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_ZMM:
            register_class = ZYDIS_REGCLASS_ZMM;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_TMM:
            register_class = ZYDIS_REGCLASS_TMM;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_BND:
            register_class = ZYDIS_REGCLASS_BOUND;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_SREG:
            register_class = ZYDIS_REGCLASS_SEGMENT;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_CR:
            register_class = ZYDIS_REGCLASS_CONTROL;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_DR:
            register_class = ZYDIS_REGCLASS_DEBUG;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_MASK:
            register_class = ZYDIS_REGCLASS_MASK;
            break;
        default:
            break;
        }
        if (register_class)
        {
            switch (operand->op.encoding)
            {
            case ZYDIS_OPERAND_ENCODING_MODRM_REG:
                ZYAN_CHECK(
                    ZydisDecodeOperandRegister(
                        instruction, &operands[i], register_class,
                        ZydisCalcRegisterId(
                            context, instruction, ZYDIS_REG_ENCODING_REG, register_class)));
                break;
            case ZYDIS_OPERAND_ENCODING_MODRM_RM:
                ZYAN_CHECK(
                    ZydisDecodeOperandRegister(
                        instruction, &operands[i], register_class,
                        ZydisCalcRegisterId(
                            context, instruction, ZYDIS_REG_ENCODING_RM, register_class)));
                break;
            case ZYDIS_OPERAND_ENCODING_OPCODE:
                ZYAN_CHECK(
                    ZydisDecodeOperandRegister(
                        instruction, &operands[i], register_class,
                        ZydisCalcRegisterId(
                            context, instruction, ZYDIS_REG_ENCODING_OPCODE, register_class)));
                break;
            case ZYDIS_OPERAND_ENCODING_NDSNDD:
                ZYAN_CHECK(
                    ZydisDecodeOperandRegister(
                        instruction, &operands[i], register_class,
                        ZydisCalcRegisterId(
                            context, instruction, ZYDIS_REG_ENCODING_NDSNDD, register_class)));
                break;
            case ZYDIS_OPERAND_ENCODING_MASK:
                ZYAN_CHECK(
                    ZydisDecodeOperandRegister(
                        instruction, &operands[i], register_class,
                        ZydisCalcRegisterId(
                            context, instruction, ZYDIS_REG_ENCODING_MASK, register_class)));
                break;
            case ZYDIS_OPERAND_ENCODING_IS4:
                ZYAN_CHECK(
                    ZydisDecodeOperandRegister(
                        instruction, &operands[i], register_class,
                        ZydisCalcRegisterId(
                            context, instruction, ZYDIS_REG_ENCODING_IS4, register_class)));
                break;
            default:
                ZYAN_UNREACHABLE;
            }

            if (operand->is_multisource4)
            {
                operands[i].attributes |= ZYDIS_OATTRIB_IS_MULTISOURCE4;
            }

            goto FinalizeOperand;
        }

        // Memory operands
        switch (operand->type)
        {
        case ZYDIS_SEMANTIC_OPTYPE_MEM:
            ZYAN_CHECK(
                ZydisDecodeOperandMemory(
                    context, instruction, &operands[i], ZYDIS_REGCLASS_INVALID));
            break;
        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX:
            ZYAN_CHECK(
                ZydisDecodeOperandMemory(
                    context, instruction, &operands[i], ZYDIS_REGCLASS_XMM));
            operands[i].mem.type = ZYDIS_MEMOP_TYPE_VSIB;
            break;
        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY:
            ZYAN_CHECK(
                ZydisDecodeOperandMemory(
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.