tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Encoder.c (158075B)


      1 /***************************************************************************************************
      2 
      3  Zyan Disassembler Library (Zydis)
      4 
      5  Original Author : Mappa
      6 
      7 * Permission is hereby granted, free of charge, to any person obtaining a copy
      8 * of this software and associated documentation files (the "Software"), to deal
      9 * in the Software without restriction, including without limitation the rights
     10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 * copies of the Software, and to permit persons to whom the Software is
     12 * furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in all
     15 * copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23 * SOFTWARE.
     24 
     25 ***************************************************************************************************/
     26 
     27 // ReSharper disable CppClangTidyClangDiagnosticSwitchEnum
     28 // ReSharper disable CppClangTidyClangDiagnosticCoveredSwitchDefault
     29 // ReSharper disable CppClangTidyClangDiagnosticImplicitFallthrough
     30 
     31 #include "zydis/Zycore/LibC.h"
     32 #include "zydis/Zydis/Encoder.h"
     33 #include "zydis/Zydis/Utils.h"
     34 #include "zydis/Zydis/Internal/EncoderData.h"
     35 #include "zydis/Zydis/Internal/SharedData.h"
     36 
     37 /* ============================================================================================== */
     38 /* Macros                                                                                         */
     39 /* ============================================================================================== */
     40 
     41 /* ---------------------------------------------------------------------------------------------- */
     42 /* Constants                                                                                      */
     43 /* ---------------------------------------------------------------------------------------------- */
     44 
     45 #define ZYDIS_OPSIZE_MAP_BYTEOP                 1
     46 #define ZYDIS_OPSIZE_MAP_DEFAULT64              4
     47 #define ZYDIS_OPSIZE_MAP_FORCE64                5
     48 #define ZYDIS_ADSIZE_MAP_IGNORED                1
     49 #define ZYDIS_LEGACY_SEGMENTS                   (ZYDIS_ATTRIB_HAS_SEGMENT_CS | \
     50                                                 ZYDIS_ATTRIB_HAS_SEGMENT_SS | \
     51                                                 ZYDIS_ATTRIB_HAS_SEGMENT_DS | \
     52                                                 ZYDIS_ATTRIB_HAS_SEGMENT_ES)
     53 #define ZYDIS_ENCODABLE_PREFIXES_NO_SEGMENTS    (ZYDIS_ENCODABLE_PREFIXES ^ \
     54                                                 ZYDIS_ATTRIB_HAS_SEGMENT)
     55 
     56 /* ---------------------------------------------------------------------------------------------- */
     57 
     58 /* ============================================================================================== */
     59 /* Internal enums and types                                                                       */
     60 /* ============================================================================================== */
     61 
     62 /**
     63 * Usage of `REX.W` prefix makes it impossible to use some byte-sized registers. Values of this
     64 * enum are used to track and facilitate enforcement of these restrictions.
     65 */
     66 typedef enum ZydisEncoderRexType_
     67 {
     68    ZYDIS_REX_TYPE_UNKNOWN,
     69    ZYDIS_REX_TYPE_REQUIRED,
     70    ZYDIS_REX_TYPE_FORBIDDEN,
     71 
     72    /**
     73     * Maximum value of this enum.
     74     */
     75    ZYDIS_REX_TYPE_MAX_VALUE = ZYDIS_REX_TYPE_FORBIDDEN,
     76    /**
     77     * The minimum number of bits required to represent all values of this enum.
     78     */
     79    ZYDIS_REX_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REX_TYPE_MAX_VALUE)
     80 } ZydisEncoderRexType;
     81 
     82 /**
     83 * Primary structure used during instruction matching phase. Once filled it contains information
     84 * about matched instruction definition and some values deduced from encoder request. It gets
     85 * converted to `ZydisEncoderInstruction` during instruction building phase.
     86 */
     87 typedef struct ZydisEncoderInstructionMatch_
     88 {
     89    /**
     90     * A pointer to the `ZydisEncoderRequest` instance.
     91     */
     92    const ZydisEncoderRequest *request;
     93    /**
     94     * A pointer to the `ZydisEncodableInstruction` instance.
     95     */
     96    const ZydisEncodableInstruction *definition;
     97    /**
     98     * A pointer to the `ZydisInstructionDefinition` instance.
     99     */
    100    const ZydisInstructionDefinition *base_definition;
    101    /**
    102     * A pointer to the `ZydisOperandDefinition` array.
    103     */
    104    const ZydisOperandDefinition *operands;
    105    /**
    106     * Encodable attributes for this instruction.
    107     */
    108    ZydisInstructionAttributes attributes;
    109    /**
    110     * Effective operand size attribute.
    111     */
    112    ZyanU8 eosz;
    113    /**
    114     * Effective address size attribute.
    115     */
    116    ZyanU8 easz;
    117    /**
    118     * Effective displacement size.
    119     */
    120    ZyanU8 disp_size;
    121    /**
    122     * Effective immediate size.
    123     */
    124    ZyanU8 imm_size;
    125    /**
    126     * Exponent of compressed displacement scale factor (2^cd8_scale)
    127     */
    128    ZyanU8 cd8_scale;
    129    /**
    130     * `REX` prefix constraints.
    131     */
    132    ZydisEncoderRexType rex_type;
    133    /**
    134     * True for special cases where operand size attribute must be lower than 64 bits.
    135     */
    136    ZyanBool eosz64_forbidden;
    137    /**
    138     * True when instruction definition has relative operand (used for branching instructions).
    139     */
    140    ZyanBool has_rel_operand;
    141 } ZydisEncoderInstructionMatch;
    142 
    143 /**
    144 * Encapsulates information about writable buffer.
    145 */
    146 typedef struct ZydisEncoderBuffer_
    147 {
    148    /**
    149     * A pointer to actual data buffer.
    150     */
    151    ZyanU8 *buffer;
    152    /**
    153     * Size of this buffer.
    154     */
    155    ZyanUSize size;
    156    /**
    157     * Current write offset.
    158     */
    159    ZyanUSize offset;
    160 } ZydisEncoderBuffer;
    161 
    162 /**
    163 * Low-level instruction representation. Once filled this structure contains all information
    164 * required for final instruction emission phase.
    165 */
    166 typedef struct ZydisEncoderInstruction_
    167 {
    168    /**
    169     * Encodable attributes for this instruction.
    170     */
    171    ZydisInstructionAttributes attributes;
    172    /**
    173     * The instruction encoding.
    174     */
    175    ZydisInstructionEncoding encoding;
    176    /**
    177     * The opcode map.
    178     */
    179    ZydisOpcodeMap opcode_map;
    180    /**
    181     * The opcode.
    182     */
    183    ZyanU8 opcode;
    184    /**
    185     * The `vvvv` field (`VEX`, `EVEX`, `MVEX`, `XOP`).
    186     */
    187    ZyanU8 vvvv;
    188    /**
    189     * The `sss` field (`MVEX`).
    190     */
    191    ZyanU8 sss;
    192    /**
    193     * The mask register ID.
    194     */
    195    ZyanU8 mask;
    196    /**
    197     * The vector length.
    198     */
    199    ZyanU8 vector_length;
    200    /**
    201     * The `mod` component of Mod/RM byte.
    202     */
    203    ZyanU8 mod;
    204    /**
    205     * The `reg` component of Mod/RM byte.
    206     */
    207    ZyanU8 reg;
    208    /**
    209     * The `rm` component of Mod/RM byte.
    210     */
    211    ZyanU8 rm;
    212    /**
    213     * The scale component of SIB byte.
    214     */
    215    ZyanU8 scale;
    216    /**
    217     * The index component of SIB byte.
    218     */
    219    ZyanU8 index;
    220    /**
    221     * The base component of SIB byte.
    222     */
    223    ZyanU8 base;
    224    /**
    225     * The `REX.W` bit.
    226     */
    227    ZyanBool rex_w;
    228    /**
    229     * True if using zeroing mask (`EVEX`).
    230     */
    231    ZyanBool zeroing;
    232    /**
    233     * True if using eviction hint (`MVEX`).
    234     */
    235    ZyanBool eviction_hint;
    236    /**
    237     * Size of displacement value.
    238     */
    239    ZyanU8 disp_size;
    240    /**
    241     * Size of immediate value.
    242     */
    243    ZyanU8 imm_size;
    244    /**
    245     * The displacement value.
    246     */
    247    ZyanU64 disp;
    248    /**
    249     * The immediate value.
    250     */
    251    ZyanU64 imm;
    252 } ZydisEncoderInstruction;
    253 
    254 /* ============================================================================================== */
    255 /* Internal functions                                                                             */
    256 /* ============================================================================================== */
    257 
    258 /**
    259 * Converts `ZydisInstructionEncoding` to `ZydisEncodableEncoding`.
    260 *
    261 * @param   encoding `ZydisInstructionEncoding` value to convert.
    262 *
    263 * @return  Equivalent `ZydisEncodableEncoding` value.
    264 */
    265 static ZydisEncodableEncoding ZydisGetEncodableEncoding(ZydisInstructionEncoding encoding)
    266 {
    267    static const ZydisEncodableEncoding encoding_lookup[6] =
    268    {
    269        ZYDIS_ENCODABLE_ENCODING_LEGACY,
    270        ZYDIS_ENCODABLE_ENCODING_3DNOW,
    271        ZYDIS_ENCODABLE_ENCODING_XOP,
    272        ZYDIS_ENCODABLE_ENCODING_VEX,
    273        ZYDIS_ENCODABLE_ENCODING_EVEX,
    274        ZYDIS_ENCODABLE_ENCODING_MVEX,
    275    };
    276    ZYAN_ASSERT((ZyanUSize)encoding <= ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE);
    277    return encoding_lookup[encoding];
    278 }
    279 
    280 /**
    281 * Converts `ZydisMachineMode` to default stack width value expressed in bits.
    282 *
    283 * @param   machine_mode `ZydisMachineMode` value to convert.
    284 *
    285 * @return  Stack width for requested machine mode.
    286 */
    287 static ZyanU8 ZydisGetMachineModeWidth(ZydisMachineMode machine_mode)
    288 {
    289    ZYAN_ASSERT((ZyanUSize)machine_mode <= ZYDIS_MACHINE_MODE_MAX_VALUE);
    290    static const ZyanU8 lookup[6] =
    291    {
    292        /* ZYDIS_MACHINE_MODE_LONG_64 */            64,
    293        /* ZYDIS_MACHINE_MODE_LONG_COMPAT_32 */     32,
    294        /* ZYDIS_MACHINE_MODE_LONG_COMPAT_16 */     16,
    295        /* ZYDIS_MACHINE_MODE_LEGACY_32 */          32,
    296        /* ZYDIS_MACHINE_MODE_LEGACY_16 */          16,
    297        /* ZYDIS_MACHINE_MODE_REAL_16 */            16,
    298    };
    299    return lookup[machine_mode];
    300 }
    301 
    302 /**
    303 * Converts `ZydisAddressSizeHint` to address size expressed in bits.
    304 *
    305 * @param   hint Address size hint.
    306 *
    307 * @return  Address size in bits.
    308 */
    309 static ZyanU8 ZydisGetAszFromHint(ZydisAddressSizeHint hint)
    310 {
    311    ZYAN_ASSERT((ZyanUSize)hint <= ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE);
    312    static const ZyanU8 lookup[ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE + 1] = { 0, 16, 32, 64 };
    313    return lookup[hint];
    314 }
    315 
    316 /**
    317 * Converts `ZydisOperandSizeHint` to operand size expressed in bits.
    318 *
    319 * @param   hint Operand size hint.
    320 *
    321 * @return  Operand size in bits.
    322 */
    323 static ZyanU8 ZydisGetOszFromHint(ZydisOperandSizeHint hint)
    324 {
    325    ZYAN_ASSERT((ZyanUSize)hint <= ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE);
    326    static const ZyanU8 lookup[ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE + 1] = { 0, 8, 16, 32, 64 };
    327    return lookup[hint];
    328 }
    329 
    330 /**
    331 * Calculates maximum size of absolute address value based on address size hint.
    332 *
    333 * @param   request A pointer to `ZydisEncoderRequest` struct.
    334 *
    335 * @return  Maximum address size in bits.
    336 */
    337 static ZyanU8 ZydisGetMaxAddressSize(const ZydisEncoderRequest *request)
    338 {
    339    ZyanU8 addr_size = ZydisGetAszFromHint(request->address_size_hint);
    340    if (addr_size == 0)
    341    {
    342        addr_size = ZydisGetMachineModeWidth(request->machine_mode);
    343    }
    344    return addr_size;
    345 }
    346 
    347 /**
    348 * Calculates effective operand size.
    349 *
    350 * @param   match            A pointer to `ZydisEncoderInstructionMatch` struct.
    351 * @param   size_table       Array of possible size values for different operand sizes.
    352 * @param   desired_size     Operand size requested by caller.
    353 * @param   exact_match_mode True if desired_size must be matched exactly, false when
    354 *                           "not lower than" matching is desired.
    355 *
    356 * @return  Effective operand size in bits.
    357 */
    358 static ZyanU8 ZydisGetOperandSizeFromElementSize(ZydisEncoderInstructionMatch *match,
    359    const ZyanU16 *size_table, ZyanU16 desired_size, ZyanBool exact_match_mode)
    360 {
    361    if ((match->base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_DEFAULT64) &&
    362        (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
    363    {
    364        if ((exact_match_mode && (size_table[2] == desired_size)) ||
    365            (!exact_match_mode && (size_table[2] >= desired_size)))
    366        {
    367            return 64;
    368        }
    369        else if (size_table[0] == desired_size)
    370        {
    371            return 16;
    372        }
    373    }
    374    else if ((match->base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_FORCE64) &&
    375             (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
    376    {
    377        if (size_table[2] == desired_size)
    378        {
    379            return 64;
    380        }
    381    }
    382    else
    383    {
    384        static const ZyanI8 eosz_priority_lookup[4][3] =
    385        {
    386            {  0,  1, -1 },
    387            {  1,  0, -1 },
    388            {  1,  2,  0 },
    389        };
    390        const ZyanU8 eosz_index = ZydisGetMachineModeWidth(match->request->machine_mode) >> 5;
    391        for (int i = 0; i < 3; ++i)
    392        {
    393            const ZyanI8 eosz_candidate = eosz_priority_lookup[eosz_index][i];
    394            if ((eosz_candidate == -1) ||
    395                !(match->definition->operand_sizes & (1 << eosz_candidate)))
    396            {
    397                continue;
    398            }
    399            if ((exact_match_mode && (size_table[eosz_candidate] == desired_size)) ||
    400                (!exact_match_mode && (size_table[eosz_candidate] >= desired_size)))
    401            {
    402                return 16 << eosz_candidate;
    403            }
    404        }
    405    }
    406 
    407    return 0;
    408 }
    409 
    410 /**
    411 * Calculates effective immediate size.
    412 *
    413 * @param   match        A pointer to `ZydisEncoderInstructionMatch` struct.
    414 * @param   size_table   Array of possible size values for different operand sizes.
    415 * @param   min_imm_size Minimum immediate size.
    416 *
    417 * @return  Effective operand size in bits.
    418 */
    419 static ZyanU8 ZydisGetScaledImmSize(ZydisEncoderInstructionMatch *match, const ZyanU16 *size_table,
    420    ZyanU8 min_imm_size)
    421 {
    422    if (match->eosz == 0)
    423    {
    424        match->eosz = ZydisGetOperandSizeFromElementSize(match, size_table, min_imm_size,
    425            ZYAN_FALSE);
    426        return match->eosz != 0 ? (ZyanU8)size_table[match->eosz >> 5] : 0;
    427    }
    428 
    429    const ZyanU8 index = match->eosz >> 5;
    430    return size_table[index] >= min_imm_size ? (ZyanU8)size_table[index] : 0;
    431 }
    432 
    433 /**
    434 * Calculates size of smallest integral type able to represent provided signed value.
    435 *
    436 * @param   imm Immediate to be represented.
    437 *
    438 * @return  Size of smallest integral type able to represent provided signed value.
    439 */
    440 static ZyanU8 ZydisGetSignedImmSize(ZyanI64 imm)
    441 {
    442    if (imm >= ZYAN_INT8_MIN && imm <= ZYAN_INT8_MAX)
    443    {
    444        return 8;
    445    }
    446    if (imm >= ZYAN_INT16_MIN && imm <= ZYAN_INT16_MAX)
    447    {
    448        return 16;
    449    }
    450    if (imm >= ZYAN_INT32_MIN && imm <= ZYAN_INT32_MAX)
    451    {
    452        return 32;
    453    }
    454 
    455    return 64;
    456 }
    457 
    458 /**
    459 * Calculates size of smallest integral type able to represent provided unsigned value.
    460 *
    461 * @param   imm Immediate to be represented.
    462 *
    463 * @return  Size of smallest integral type able to represent provided unsigned value.
    464 */
    465 static ZyanU8 ZydisGetUnsignedImmSize(ZyanU64 imm)
    466 {
    467    if (imm <= ZYAN_UINT8_MAX)
    468    {
    469        return 8;
    470    }
    471    if (imm <= ZYAN_UINT16_MAX)
    472    {
    473        return 16;
    474    }
    475    if (imm <= ZYAN_UINT32_MAX)
    476    {
    477        return 32;
    478    }
    479 
    480    return 64;
    481 }
    482 
    483 /**
    484 * Checks if operand encoding encodes a signed immediate value.
    485 *
    486 * @param   encoding Operand encoding for immediate value.
    487 *
    488 * @return  True for encodings that represent signed values, false otherwise.
    489 */
    490 static ZyanBool ZydisIsImmSigned(ZydisOperandEncoding encoding)
    491 {
    492    switch (encoding)
    493    {
    494    case ZYDIS_OPERAND_ENCODING_SIMM8:
    495    case ZYDIS_OPERAND_ENCODING_SIMM16:
    496    case ZYDIS_OPERAND_ENCODING_SIMM32:
    497    case ZYDIS_OPERAND_ENCODING_SIMM64:
    498    case ZYDIS_OPERAND_ENCODING_SIMM16_32_64:
    499    case ZYDIS_OPERAND_ENCODING_SIMM32_32_64:
    500    case ZYDIS_OPERAND_ENCODING_SIMM16_32_32:
    501    case ZYDIS_OPERAND_ENCODING_JIMM8:
    502    case ZYDIS_OPERAND_ENCODING_JIMM16:
    503    case ZYDIS_OPERAND_ENCODING_JIMM32:
    504    case ZYDIS_OPERAND_ENCODING_JIMM64:
    505    case ZYDIS_OPERAND_ENCODING_JIMM16_32_64:
    506    case ZYDIS_OPERAND_ENCODING_JIMM32_32_64:
    507    case ZYDIS_OPERAND_ENCODING_JIMM16_32_32:
    508    case ZYDIS_OPERAND_ENCODING_DISP8:
    509    case ZYDIS_OPERAND_ENCODING_DISP16:
    510    case ZYDIS_OPERAND_ENCODING_DISP32:
    511    case ZYDIS_OPERAND_ENCODING_DISP64:
    512    case ZYDIS_OPERAND_ENCODING_DISP16_32_64:
    513    case ZYDIS_OPERAND_ENCODING_DISP32_32_64:
    514    case ZYDIS_OPERAND_ENCODING_DISP16_32_32:
    515        return ZYAN_TRUE;
    516    case ZYDIS_OPERAND_ENCODING_UIMM8:
    517    case ZYDIS_OPERAND_ENCODING_UIMM16:
    518    case ZYDIS_OPERAND_ENCODING_UIMM32:
    519    case ZYDIS_OPERAND_ENCODING_UIMM64:
    520    case ZYDIS_OPERAND_ENCODING_UIMM16_32_64:
    521    case ZYDIS_OPERAND_ENCODING_UIMM32_32_64:
    522    case ZYDIS_OPERAND_ENCODING_UIMM16_32_32:
    523    case ZYDIS_OPERAND_ENCODING_IS4:
    524        return ZYAN_FALSE;
    525    default:
    526        ZYAN_UNREACHABLE;
    527    }
    528 }
    529 
    530 /**
    531 * Calculates effective immediate size.
    532 *
    533 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
    534 * @param   imm     Immediate value to encode.
    535 * @param   def_op  Operand definition for immediate operand.
    536 *
    537 * @return  Effective operand size in bits (0 if function failed).
    538 */
    539 static ZyanU8 ZydisGetEffectiveImmSize(ZydisEncoderInstructionMatch *match, ZyanI64 imm,
    540    const ZydisOperandDefinition *def_op)
    541 {
    542    ZyanU8 eisz = 0;
    543    ZyanU8 min_size = ZydisIsImmSigned((ZydisOperandEncoding)def_op->op.encoding)
    544        ? ZydisGetSignedImmSize(imm)
    545        : ZydisGetUnsignedImmSize((ZyanU64)imm);
    546 
    547    switch (def_op->op.encoding)
    548    {
    549    case ZYDIS_OPERAND_ENCODING_UIMM8:
    550    case ZYDIS_OPERAND_ENCODING_SIMM8:
    551        eisz = 8;
    552        break;
    553    case ZYDIS_OPERAND_ENCODING_IS4:
    554        ZYAN_ASSERT(def_op->element_type == ZYDIS_IELEMENT_TYPE_UINT8);
    555        eisz = ((ZyanU64)imm <= 15) ? 8 : 0;
    556        break;
    557    case ZYDIS_OPERAND_ENCODING_UIMM16:
    558    case ZYDIS_OPERAND_ENCODING_SIMM16:
    559        eisz = 16;
    560        break;
    561    case ZYDIS_OPERAND_ENCODING_UIMM32:
    562    case ZYDIS_OPERAND_ENCODING_SIMM32:
    563        eisz = 32;
    564        break;
    565    case ZYDIS_OPERAND_ENCODING_UIMM64:
    566    case ZYDIS_OPERAND_ENCODING_SIMM64:
    567        eisz = 64;
    568        break;
    569    case ZYDIS_OPERAND_ENCODING_UIMM16_32_64:
    570    case ZYDIS_OPERAND_ENCODING_SIMM16_32_64:
    571    {
    572        static const ZyanU16 simm16_32_64_sizes[3] = { 16, 32, 64 };
    573        return ZydisGetScaledImmSize(match, simm16_32_64_sizes, min_size);
    574    }
    575    case ZYDIS_OPERAND_ENCODING_UIMM32_32_64:
    576    case ZYDIS_OPERAND_ENCODING_SIMM32_32_64:
    577    {
    578        static const ZyanU16 simm32_32_64_sizes[3] = { 32, 32, 64 };
    579        return ZydisGetScaledImmSize(match, simm32_32_64_sizes, min_size);
    580    }
    581    case ZYDIS_OPERAND_ENCODING_UIMM16_32_32:
    582    case ZYDIS_OPERAND_ENCODING_SIMM16_32_32:
    583    {
    584        static const ZyanU16 simm16_32_32_sizes[3] = { 16, 32, 32 };
    585        return ZydisGetScaledImmSize(match, simm16_32_32_sizes, min_size);
    586    }
    587    case ZYDIS_OPERAND_ENCODING_DISP16_32_64:
    588    {
    589        ZYAN_ASSERT(match->easz == 0);
    590        const ZyanU8 addr_size = ZydisGetMaxAddressSize(match->request);
    591        const ZyanU64 uimm = imm & (~(0xFFFFFFFFFFFFFFFFULL << (addr_size - 1) << 1));
    592        if (min_size < addr_size && ZydisGetUnsignedImmSize(uimm) > min_size)
    593        {
    594            min_size = addr_size;
    595        }
    596        if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
    597        {
    598            if (min_size < 32)
    599            {
    600                min_size = 32;
    601            }
    602            match->easz = eisz = min_size;
    603        }
    604        else
    605        {
    606            if (min_size < 16)
    607            {
    608                min_size = 16;
    609            }
    610            if (min_size == 16 || min_size == 32)
    611            {
    612                match->easz = eisz = min_size;
    613            }
    614        }
    615        break;
    616    }
    617    case ZYDIS_OPERAND_ENCODING_JIMM8:
    618    case ZYDIS_OPERAND_ENCODING_JIMM16:
    619    case ZYDIS_OPERAND_ENCODING_JIMM32:
    620    case ZYDIS_OPERAND_ENCODING_JIMM64:
    621    {
    622        ZyanU8 jimm_index = def_op->op.encoding - ZYDIS_OPERAND_ENCODING_JIMM8;
    623        if ((match->request->branch_width != ZYDIS_BRANCH_WIDTH_NONE) &&
    624            (match->request->branch_width != (ZydisBranchWidth)(ZYDIS_BRANCH_WIDTH_8 + jimm_index)))
    625        {
    626            return 0;
    627        }
    628        eisz = 8 << jimm_index;
    629        break;
    630    }
    631    case ZYDIS_OPERAND_ENCODING_JIMM16_32_32:
    632        switch (match->request->branch_width)
    633        {
    634        case ZYDIS_BRANCH_WIDTH_NONE:
    635        {
    636            static const ZyanU16 jimm16_32_32_sizes[3] = { 16, 32, 32 };
    637            return ZydisGetScaledImmSize(match, jimm16_32_32_sizes, min_size);
    638        }
    639        case ZYDIS_BRANCH_WIDTH_16:
    640            eisz = 16;
    641            break;
    642        case ZYDIS_BRANCH_WIDTH_32:
    643            eisz = 32;
    644            break;
    645        case ZYDIS_BRANCH_WIDTH_8:
    646        case ZYDIS_BRANCH_WIDTH_64:
    647            return 0;
    648        default:
    649            ZYAN_UNREACHABLE;
    650        }
    651        break;
    652    default:
    653        ZYAN_UNREACHABLE;
    654    }
    655 
    656    return eisz >= min_size ? eisz : 0;
    657 }
    658 
    659 /**
    660 * Checks if register width is compatible with effective operand size.
    661 *
    662 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
    663 * @param   reg_width   Register width in bits.
    664 *
    665 * @return  True if width is compatible, false otherwise.
    666 */
    667 static ZyanBool ZydisCheckOsz(ZydisEncoderInstructionMatch *match, ZydisRegisterWidth reg_width)
    668 {
    669    ZYAN_ASSERT(reg_width <= ZYAN_UINT8_MAX);
    670    if (match->eosz == 0)
    671    {
    672        if (reg_width == 8)
    673        {
    674            return ZYAN_FALSE;
    675        }
    676        match->eosz = (ZyanU8)reg_width;
    677        return ZYAN_TRUE;
    678    }
    679 
    680    return match->eosz == (ZyanU8)reg_width ? ZYAN_TRUE : ZYAN_FALSE;
    681 }
    682 
    683 /**
    684 * Checks if register width is compatible with effective address size.
    685 *
    686 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
    687 * @param   reg_width   Register width in bits.
    688 *
    689 * @return  True if width is compatible, false otherwise.
    690 */
    691 static ZyanBool ZydisCheckAsz(ZydisEncoderInstructionMatch *match, ZydisRegisterWidth reg_width)
    692 {
    693    ZYAN_ASSERT(reg_width <= ZYAN_UINT8_MAX);
    694    if (match->easz == 0)
    695    {
    696        if ((match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
    697            (reg_width == 16))
    698        {
    699            return ZYAN_FALSE;
    700        }
    701        match->easz = (ZyanU8)reg_width;
    702        return ZYAN_TRUE;
    703    }
    704 
    705    return match->easz == (ZyanU8)reg_width ? ZYAN_TRUE : ZYAN_FALSE;
    706 }
    707 
    708 /**
    709 * Checks if specified register is valid for provided register class, encoding and machine mode.
    710 *
    711 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
    712 * @param   reg         `ZydisRegister` value.
    713 * @param   reg_class   Register class.
    714 *
    715 * @return  True if register value is allowed, false otherwise.
    716 */
    717 static ZyanBool ZydisIsRegisterAllowed(ZydisEncoderInstructionMatch *match, ZydisRegister reg,
    718    ZydisRegisterClass reg_class)
    719 {
    720    const ZyanI8 reg_id = ZydisRegisterGetId(reg);
    721    ZYAN_ASSERT(reg_id >= 0 && reg_id <= 31);
    722    if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
    723    {
    724        if ((match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_EVEX) &&
    725            (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_MVEX) &&
    726            (reg_class != ZYDIS_REGCLASS_GPR8) &&
    727            (reg_id >= 16))
    728        {
    729            return ZYAN_FALSE;
    730        }
    731    }
    732    else
    733    {
    734        if (reg_class == ZYDIS_REGCLASS_GPR64)
    735        {
    736            return ZYAN_FALSE;
    737        }
    738        if (reg_id >= 8)
    739        {
    740            return ZYAN_FALSE;
    741        }
    742    }
    743 
    744    return ZYAN_TRUE;
    745 }
    746 
    747 /**
    748 * Checks if specified scale value is valid for use with SIB addressing.
    749 *
    750 * @param   scale Scale value.
    751 *
    752 * @return  True if value is valid, false otherwise.
    753 */
    754 static ZyanBool ZydisIsScaleValid(ZyanU8 scale)
    755 {
    756    switch (scale)
    757    {
    758    case 0:
    759    case 1:
    760    case 2:
    761    case 4:
    762    case 8:
    763        return ZYAN_TRUE;
    764    default:
    765        return ZYAN_FALSE;
    766    }
    767 }
    768 
    769 /**
    770 * Enforces register usage constraints associated with usage of `REX` prefix.
    771 *
    772 * @param   match               A pointer to `ZydisEncoderInstructionMatch` struct.
    773 * @param   reg                 `ZydisRegister` value.
    774 * @param   addressing_mode     True if checked address is used for address calculations. This
    775 *                              implies more permissive checks.
    776 *
    777 * @return  True if register usage is allowed, false otherwise.
    778 */
    779 static ZyanBool ZydisValidateRexType(ZydisEncoderInstructionMatch *match, ZydisRegister reg,
    780    ZyanBool addressing_mode)
    781 {
    782    switch (reg)
    783    {
    784    case ZYDIS_REGISTER_AL:
    785    case ZYDIS_REGISTER_CL:
    786    case ZYDIS_REGISTER_DL:
    787    case ZYDIS_REGISTER_BL:
    788        return ZYAN_TRUE;
    789    case ZYDIS_REGISTER_AH:
    790    case ZYDIS_REGISTER_CH:
    791    case ZYDIS_REGISTER_DH:
    792    case ZYDIS_REGISTER_BH:
    793        if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
    794        {
    795            match->rex_type = ZYDIS_REX_TYPE_FORBIDDEN;
    796        }
    797        else if (match->rex_type == ZYDIS_REX_TYPE_REQUIRED)
    798        {
    799            return ZYAN_FALSE;
    800        }
    801        break;
    802    case ZYDIS_REGISTER_SPL:
    803    case ZYDIS_REGISTER_BPL:
    804    case ZYDIS_REGISTER_SIL:
    805    case ZYDIS_REGISTER_DIL:
    806    case ZYDIS_REGISTER_R8B:
    807    case ZYDIS_REGISTER_R9B:
    808    case ZYDIS_REGISTER_R10B:
    809    case ZYDIS_REGISTER_R11B:
    810    case ZYDIS_REGISTER_R12B:
    811    case ZYDIS_REGISTER_R13B:
    812    case ZYDIS_REGISTER_R14B:
    813    case ZYDIS_REGISTER_R15B:
    814        if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
    815        {
    816            match->rex_type = ZYDIS_REX_TYPE_REQUIRED;
    817        }
    818        else if (match->rex_type == ZYDIS_REX_TYPE_FORBIDDEN)
    819        {
    820            return ZYAN_FALSE;
    821        }
    822        break;
    823    default:
    824        if ((ZydisRegisterGetId(reg) > 7) ||
    825            (!addressing_mode && (ZydisRegisterGetClass(reg) == ZYDIS_REGCLASS_GPR64)))
    826        {
    827            if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
    828            {
    829                match->rex_type = ZYDIS_REX_TYPE_REQUIRED;
    830            }
    831            else if (match->rex_type == ZYDIS_REX_TYPE_FORBIDDEN)
    832            {
    833                return ZYAN_FALSE;
    834            }
    835        }
    836        break;
    837    }
    838 
    839    return ZYAN_TRUE;
    840 }
    841 
    842 /**
    843 * Checks if specified register is valid for use with SIB addressing.
    844 *
    845 * @param   match          A pointer to `ZydisEncoderInstructionMatch` struct.
    846 * @param   reg_class      Register class.
    847 * @param   reg            `ZydisRegister` value.
    848 *
    849 * @return  True if register value is allowed, false otherwise.
    850 */
    851 static ZyanBool ZydisIsValidAddressingClass(ZydisEncoderInstructionMatch *match,
    852    ZydisRegisterClass reg_class, ZydisRegister reg)
    853 {
    854    ZyanBool result;
    855    const ZyanBool is_64 = (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64);
    856    switch (reg_class)
    857    {
    858    case ZYDIS_REGCLASS_INVALID:
    859        return ZYAN_TRUE;
    860    case ZYDIS_REGCLASS_GPR16:
    861        result = !is_64;
    862        break;
    863    case ZYDIS_REGCLASS_GPR32:
    864        result = is_64 || ZydisRegisterGetId(reg) < 8;
    865        break;
    866    case ZYDIS_REGCLASS_GPR64:
    867        result = is_64;
    868        break;
    869    default:
    870        return ZYAN_FALSE;
    871    }
    872 
    873    return result && ZydisValidateRexType(match, reg, ZYAN_TRUE);
    874 }
    875 
    876 /**
    877 * Helper function that determines correct `ModR/M.RM` value for 16-bit addressing mode.
    878 *
    879 * @param   base   `ZydisRegister` used as `SIB.base`.
    880 * @param   index  `ZydisRegister` used as `SIB.index`.
    881 *
    882 * @return  `ModR/M.RM` value (-1 if function failed).
    883 */
    884 static ZyanI8 ZydisGetRm16(ZydisRegister base, ZydisRegister index)
    885 {
    886    static const ZydisRegister modrm16_lookup[8][2] =
    887    {
    888        { ZYDIS_REGISTER_BX, ZYDIS_REGISTER_SI },
    889        { ZYDIS_REGISTER_BX, ZYDIS_REGISTER_DI },
    890        { ZYDIS_REGISTER_BP, ZYDIS_REGISTER_SI },
    891        { ZYDIS_REGISTER_BP, ZYDIS_REGISTER_DI },
    892        { ZYDIS_REGISTER_SI, ZYDIS_REGISTER_NONE },
    893        { ZYDIS_REGISTER_DI, ZYDIS_REGISTER_NONE },
    894        { ZYDIS_REGISTER_BP, ZYDIS_REGISTER_NONE },
    895        { ZYDIS_REGISTER_BX, ZYDIS_REGISTER_NONE },
    896    };
    897    for (ZyanI8 i = 0; i < (ZyanI8)ZYAN_ARRAY_LENGTH(modrm16_lookup); ++i)
    898    {
    899        if ((modrm16_lookup[i][0] == base) &&
    900            (modrm16_lookup[i][1] == index))
    901        {
    902            return i;
    903        }
    904    }
    905 
    906    return -1;
    907 }
    908 
    909 /**
    910 * Encodes `MVEX.sss` field for specified broadcast mode.
    911 *
    912 * @param   broadcast Broadcast mode.
    913 *
    914 * @return  Corresponding `MVEX.sss` value.
    915 */
    916 static ZyanU8 ZydisEncodeMvexBroadcastMode(ZydisBroadcastMode broadcast)
    917 {
    918    switch (broadcast)
    919    {
    920    case ZYDIS_BROADCAST_MODE_INVALID:
    921        return 0;
    922    case ZYDIS_BROADCAST_MODE_1_TO_16:
    923    case ZYDIS_BROADCAST_MODE_1_TO_8:
    924        return 1;
    925    case ZYDIS_BROADCAST_MODE_4_TO_16:
    926    case ZYDIS_BROADCAST_MODE_4_TO_8:
    927        return 2;
    928    default:
    929        ZYAN_UNREACHABLE;
    930    }
    931 }
    932 
    933 /**
    934 * Encodes `MVEX.sss` field for specified conversion mode.
    935 *
    936 * @param   conversion Conversion mode.
    937 *
    938 * @return  Corresponding `MVEX.sss` value.
    939 */
    940 static ZyanU8 ZydisEncodeMvexConversionMode(ZydisConversionMode conversion)
    941 {
    942    switch (conversion)
    943    {
    944    case ZYDIS_CONVERSION_MODE_INVALID:
    945        return 0;
    946    case ZYDIS_CONVERSION_MODE_FLOAT16:
    947        return 3;
    948    case ZYDIS_CONVERSION_MODE_UINT8:
    949        return 4;
    950    case ZYDIS_CONVERSION_MODE_SINT8:
    951        return 5;
    952    case ZYDIS_CONVERSION_MODE_UINT16:
    953        return 6;
    954    case ZYDIS_CONVERSION_MODE_SINT16:
    955        return 7;
    956    default:
    957        ZYAN_UNREACHABLE;
    958    }
    959 }
    960 
    961 /**
    962 * Determines scale factor for compressed 8-bit displacement (`EVEX` instructions only).
    963 *
    964 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
    965 *
    966 * @return  log2(scale factor)
    967 */
    968 static ZyanU8 ZydisGetCompDispScaleEvex(const ZydisEncoderInstructionMatch *match)
    969 {
    970    const ZydisInstructionDefinitionEVEX *evex_def =
    971        (const ZydisInstructionDefinitionEVEX *)match->base_definition;
    972 
    973    ZYAN_ASSERT(match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
    974    ZYAN_ASSERT(evex_def->tuple_type);
    975    ZYAN_ASSERT(evex_def->element_size);
    976    const ZyanU8 vector_length = match->definition->vector_length - ZYDIS_VECTOR_LENGTH_128;
    977    static const ZyanU8 size_indexes[ZYDIS_IELEMENT_SIZE_MAX_VALUE + 1] =
    978    {
    979        0, 0, 0, 1, 2, 4
    980    };
    981    ZYAN_ASSERT(evex_def->element_size < ZYAN_ARRAY_LENGTH(size_indexes));
    982    const ZyanU8 size_index = size_indexes[evex_def->element_size];
    983    switch (evex_def->tuple_type)
    984    {
    985    case ZYDIS_TUPLETYPE_FV:
    986    {
    987        static const ZyanU8 scales[2][3][3] =
    988        {
    989            /*B0*/ { /*16*/ { 4, 5, 6 }, /*32*/ { 4, 5, 6 }, /*64*/ { 4, 5, 6 } },
    990            /*B1*/ { /*16*/ { 1, 1, 1 }, /*32*/ { 2, 2, 2 }, /*64*/ { 3, 3, 3 } }
    991        };
    992        const ZyanU8 broadcast = match->request->evex.broadcast ? 1 : 0;
    993        ZYAN_ASSERT(size_index < 3);
    994        return scales[broadcast][size_index][vector_length];
    995    }
    996    case ZYDIS_TUPLETYPE_HV:
    997    {
    998        static const ZyanU8 scales[2][2][3] =
    999        {
   1000            /*B0*/ { /*16*/ {  3, 4, 5 }, /*32*/ {  3, 4, 5 } },
   1001            /*B1*/ { /*16*/ {  1, 1, 1 }, /*32*/ {  2, 2, 2 } }
   1002        };
   1003        const ZyanU8 broadcast = match->request->evex.broadcast ? 1 : 0;
   1004        ZYAN_ASSERT(size_index < 3);
   1005        return scales[broadcast][size_index][vector_length];
   1006    }
   1007    case ZYDIS_TUPLETYPE_FVM:
   1008    {
   1009        static const ZyanU8 scales[3] =
   1010        {
   1011            4, 5, 6
   1012        };
   1013        return scales[vector_length];
   1014    }
   1015    case ZYDIS_TUPLETYPE_GSCAT:
   1016    case ZYDIS_TUPLETYPE_T1S:
   1017    {
   1018        static const ZyanU8 scales[6] =
   1019        {
   1020            /*   */ 0,
   1021            /*  8*/ 0,
   1022            /* 16*/ 1,
   1023            /* 32*/ 2,
   1024            /* 64*/ 3,
   1025            /*128*/ 4
   1026        };
   1027        ZYAN_ASSERT(evex_def->element_size < ZYAN_ARRAY_LENGTH(scales));
   1028        return scales[evex_def->element_size];
   1029    }
   1030    case ZYDIS_TUPLETYPE_T1F:
   1031    {
   1032        static const ZyanU8 scales[3] =
   1033        {
   1034            /* 16*/ 1,
   1035            /* 32*/ 2,
   1036            /* 64*/ 3
   1037        };
   1038        ZYAN_ASSERT(size_index < 3);
   1039        return scales[size_index];
   1040    }
   1041    case ZYDIS_TUPLETYPE_T1_4X:
   1042        return 4;
   1043    case ZYDIS_TUPLETYPE_T2:
   1044        return match->definition->rex_w ? 4 : 3;
   1045    case ZYDIS_TUPLETYPE_T4:
   1046        return match->definition->rex_w ? 5 : 4;
   1047    case ZYDIS_TUPLETYPE_T8:
   1048        return 5;
   1049    case ZYDIS_TUPLETYPE_HVM:
   1050    {
   1051        static const ZyanU8 scales[3] =
   1052        {
   1053            3, 4, 5
   1054        };
   1055        return scales[vector_length];
   1056    }
   1057    case ZYDIS_TUPLETYPE_QVM:
   1058    {
   1059        static const ZyanU8 scales[3] =
   1060        {
   1061            2, 3, 4
   1062        };
   1063        return scales[vector_length];
   1064    }
   1065    case ZYDIS_TUPLETYPE_OVM:
   1066    {
   1067        static const ZyanU8 scales[3] =
   1068        {
   1069            1, 2, 3
   1070        };
   1071        return scales[vector_length];
   1072    }
   1073    case ZYDIS_TUPLETYPE_M128:
   1074        return 4;
   1075    case ZYDIS_TUPLETYPE_DUP:
   1076    {
   1077        static const ZyanU8 scales[3] =
   1078        {
   1079            3, 5, 6
   1080        };
   1081        return scales[vector_length];
   1082    }
   1083    case ZYDIS_TUPLETYPE_QUARTER:
   1084    {
   1085        static const ZyanU8 scales[2][3] =
   1086        {
   1087            /*B0*/ { 2, 3, 4 },
   1088            /*B1*/ { 1, 1, 1 }
   1089        };
   1090        const ZyanU8 broadcast = match->request->evex.broadcast ? 1 : 0;
   1091        return scales[broadcast][vector_length];
   1092    }
   1093    default:
   1094        ZYAN_UNREACHABLE;
   1095    }
   1096 }
   1097 
   1098 /**
   1099 * Determines scale factor for compressed 8-bit displacement (`MVEX` instructions only).
   1100 *
   1101 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
   1102 *
   1103 * @return  log2(scale factor)
   1104 */
   1105 static ZyanU8 ZydisGetCompDispScaleMvex(const ZydisEncoderInstructionMatch *match)
   1106 {
   1107    const ZydisInstructionDefinitionMVEX *mvex_def =
   1108        (const ZydisInstructionDefinitionMVEX *)match->base_definition;
   1109 
   1110    ZyanU8 index = mvex_def->has_element_granularity;
   1111    ZYAN_ASSERT(!index || !mvex_def->broadcast);
   1112    if (!index && mvex_def->broadcast)
   1113    {
   1114        switch (mvex_def->broadcast)
   1115        {
   1116        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8:
   1117        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16:
   1118            index = 1;
   1119            break;
   1120        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8:
   1121        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16:
   1122            index = 2;
   1123            break;
   1124        default:
   1125            ZYAN_UNREACHABLE;
   1126        }
   1127    }
   1128 
   1129    const ZyanU8 sss = ZydisEncodeMvexBroadcastMode(match->request->mvex.broadcast) |
   1130                       ZydisEncodeMvexConversionMode(match->request->mvex.conversion);
   1131    switch (mvex_def->functionality)
   1132    {
   1133    case ZYDIS_MVEX_FUNC_IGNORED:
   1134    case ZYDIS_MVEX_FUNC_INVALID:
   1135    case ZYDIS_MVEX_FUNC_RC:
   1136    case ZYDIS_MVEX_FUNC_SAE:
   1137    case ZYDIS_MVEX_FUNC_SWIZZLE_32:
   1138    case ZYDIS_MVEX_FUNC_SWIZZLE_64:
   1139        return 0;
   1140    case ZYDIS_MVEX_FUNC_F_32:
   1141    case ZYDIS_MVEX_FUNC_I_32:
   1142    case ZYDIS_MVEX_FUNC_F_64:
   1143    case ZYDIS_MVEX_FUNC_I_64:
   1144        return 6;
   1145    case ZYDIS_MVEX_FUNC_SF_32:
   1146    case ZYDIS_MVEX_FUNC_SF_32_BCST:
   1147    case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
   1148    case ZYDIS_MVEX_FUNC_UF_32:
   1149    {
   1150        static const ZyanU8 lookup[3][8] =
   1151        {
   1152            { 6, 2, 4, 5, 4, 4, 5, 5 },
   1153            { 2, 0, 0, 1, 0, 0, 1, 1 },
   1154            { 4, 0, 0, 3, 2, 2, 3, 3 }
   1155        };
   1156        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
   1157        return lookup[index][sss];
   1158    }
   1159    case ZYDIS_MVEX_FUNC_SI_32:
   1160    case ZYDIS_MVEX_FUNC_UI_32:
   1161    case ZYDIS_MVEX_FUNC_SI_32_BCST:
   1162    case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
   1163    {
   1164        static const ZyanU8 lookup[3][8] =
   1165        {
   1166            { 6, 2, 4, 0, 4, 4, 5, 5 },
   1167            { 2, 0, 0, 0, 0, 0, 1, 1 },
   1168            { 4, 0, 0, 0, 2, 2, 3, 3 }
   1169        };
   1170        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
   1171        return lookup[index][sss];
   1172    }
   1173    case ZYDIS_MVEX_FUNC_SF_64:
   1174    case ZYDIS_MVEX_FUNC_UF_64:
   1175    case ZYDIS_MVEX_FUNC_SI_64:
   1176    case ZYDIS_MVEX_FUNC_UI_64:
   1177    {
   1178        static const ZyanU8 lookup[3][3] =
   1179        {
   1180            { 6, 3, 5 },
   1181            { 3, 0, 0 },
   1182            { 5, 0, 0 }
   1183        };
   1184        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
   1185        return lookup[index][sss];
   1186    }
   1187    case ZYDIS_MVEX_FUNC_DF_32:
   1188    case ZYDIS_MVEX_FUNC_DI_32:
   1189    {
   1190        static const ZyanU8 lookup[2][8] =
   1191        {
   1192            { 6, 0, 0, 5, 4, 4, 5, 5 },
   1193            { 2, 0, 0, 1, 0, 0, 1, 1 }
   1194        };
   1195        ZYAN_ASSERT(index < 2);
   1196        ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index]));
   1197        return lookup[index][sss];
   1198    }
   1199    case ZYDIS_MVEX_FUNC_DF_64:
   1200    case ZYDIS_MVEX_FUNC_DI_64:
   1201        ZYAN_ASSERT(index < 2);
   1202        return index == 0 ? 6 : 3;
   1203    default:
   1204        ZYAN_UNREACHABLE;
   1205    }
   1206 }
   1207 
   1208 /**
   1209 * Determines scale factor for compressed 8-bit displacement.
   1210 *
   1211 * @param   match A pointer to `ZydisEncoderInstructionMatch` struct.
   1212 *
   1213 * @return  log2(scale factor)
   1214 */
   1215 static ZyanU8 ZydisGetCompDispScale(const ZydisEncoderInstructionMatch *match)
   1216 {
   1217    switch (match->definition->encoding)
   1218    {
   1219    case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
   1220    case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
   1221    case ZYDIS_INSTRUCTION_ENCODING_XOP:
   1222    case ZYDIS_INSTRUCTION_ENCODING_VEX:
   1223        return 0;
   1224    case ZYDIS_INSTRUCTION_ENCODING_EVEX:
   1225        return ZydisGetCompDispScaleEvex(match);
   1226    case ZYDIS_INSTRUCTION_ENCODING_MVEX:
   1227        return ZydisGetCompDispScaleMvex(match);
   1228    default:
   1229        ZYAN_UNREACHABLE;
   1230    }
   1231 }
   1232 
   1233 /**
   1234 * Checks if requested operand matches register operand from instruction definition.
   1235 *
   1236 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   1237 * @param   user_op     Operand definition from `ZydisEncoderRequest` structure.
   1238 * @param   def_op      Decoder's operand definition from current instruction definition.
   1239 *
   1240 * @return  True if operands match, false otherwise.
   1241 */
   1242 static ZyanBool ZydisIsRegisterOperandCompatible(ZydisEncoderInstructionMatch *match,
   1243    const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
   1244 {
   1245    const ZydisRegisterClass reg_class = ZydisRegisterGetClass(user_op->reg.value);
   1246    const ZydisRegisterWidth reg_width = ZydisRegisterClassGetWidth(match->request->machine_mode,
   1247        reg_class);
   1248    if (reg_width == 0)
   1249    {
   1250        return ZYAN_FALSE;
   1251    }
   1252 
   1253    ZyanBool is4_expected_value = ZYAN_FALSE;
   1254    switch (def_op->type)
   1255    {
   1256    case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG:
   1257        switch (def_op->op.reg.type)
   1258        {
   1259        case ZYDIS_IMPLREG_TYPE_STATIC:
   1260            if (def_op->op.reg.reg.reg != user_op->reg.value)
   1261            {
   1262                return ZYAN_FALSE;
   1263            }
   1264            break;
   1265        case ZYDIS_IMPLREG_TYPE_GPR_OSZ:
   1266            if ((reg_class != ZYDIS_REGCLASS_GPR8) &&
   1267                (reg_class != ZYDIS_REGCLASS_GPR16) &&
   1268                (reg_class != ZYDIS_REGCLASS_GPR32) &&
   1269                (reg_class != ZYDIS_REGCLASS_GPR64))
   1270            {
   1271                return ZYAN_FALSE;
   1272            }
   1273            if (def_op->op.reg.reg.id != ZydisRegisterGetId(user_op->reg.value))
   1274            {
   1275                return ZYAN_FALSE;
   1276            }
   1277            if (!ZydisCheckOsz(match, reg_width))
   1278            {
   1279                return ZYAN_FALSE;
   1280            }
   1281            break;
   1282        case ZYDIS_IMPLREG_TYPE_GPR_ASZ:
   1283            if ((reg_class != ZYDIS_REGCLASS_GPR8) &&
   1284                (reg_class != ZYDIS_REGCLASS_GPR16) &&
   1285                (reg_class != ZYDIS_REGCLASS_GPR32) &&
   1286                (reg_class != ZYDIS_REGCLASS_GPR64))
   1287            {
   1288                return ZYAN_FALSE;
   1289            }
   1290            if (def_op->op.reg.reg.id != ZydisRegisterGetId(user_op->reg.value))
   1291            {
   1292                return ZYAN_FALSE;
   1293            }
   1294            if (!ZydisCheckAsz(match, reg_width))
   1295            {
   1296                return ZYAN_FALSE;
   1297            }
   1298            break;
   1299        default:
   1300            ZYAN_UNREACHABLE;
   1301        }
   1302        break;
   1303    case ZYDIS_SEMANTIC_OPTYPE_GPR8:
   1304        if (reg_class != ZYDIS_REGCLASS_GPR8)
   1305        {
   1306            return ZYAN_FALSE;
   1307        }
   1308        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1309        {
   1310            return ZYAN_FALSE;
   1311        }
   1312        if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
   1313        {
   1314            return ZYAN_FALSE;
   1315        }
   1316        break;
   1317    case ZYDIS_SEMANTIC_OPTYPE_GPR16:
   1318        if (reg_class != ZYDIS_REGCLASS_GPR16)
   1319        {
   1320            return ZYAN_FALSE;
   1321        }
   1322        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1323        {
   1324            return ZYAN_FALSE;
   1325        }
   1326        break;
   1327    case ZYDIS_SEMANTIC_OPTYPE_GPR32:
   1328        if (reg_class != ZYDIS_REGCLASS_GPR32)
   1329        {
   1330            return ZYAN_FALSE;
   1331        }
   1332        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1333        {
   1334            return ZYAN_FALSE;
   1335        }
   1336        break;
   1337    case ZYDIS_SEMANTIC_OPTYPE_GPR64:
   1338        if (reg_class != ZYDIS_REGCLASS_GPR64)
   1339        {
   1340            return ZYAN_FALSE;
   1341        }
   1342        break;
   1343    case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64:
   1344        if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
   1345            (reg_class != ZYDIS_REGCLASS_GPR32) &&
   1346            (reg_class != ZYDIS_REGCLASS_GPR64))
   1347        {
   1348            return ZYAN_FALSE;
   1349        }
   1350        if (!ZydisCheckOsz(match, reg_width))
   1351        {
   1352            return ZYAN_FALSE;
   1353        }
   1354        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1355        {
   1356            return ZYAN_FALSE;
   1357        }
   1358        if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
   1359        {
   1360            return ZYAN_FALSE;
   1361        }
   1362        break;
   1363    case ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64:
   1364        if ((reg_class != ZYDIS_REGCLASS_GPR32) &&
   1365            (reg_class != ZYDIS_REGCLASS_GPR64))
   1366        {
   1367            return ZYAN_FALSE;
   1368        }
   1369        if (match->eosz == 0)
   1370        {
   1371            if (reg_class == ZYDIS_REGCLASS_GPR64)
   1372            {
   1373                match->eosz = 64;
   1374            }
   1375            else
   1376            {
   1377                match->eosz64_forbidden = ZYAN_TRUE;
   1378            }
   1379        }
   1380        else if (match->eosz != (ZyanU8)reg_width)
   1381        {
   1382            return ZYAN_FALSE;
   1383        }
   1384        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1385        {
   1386            return ZYAN_FALSE;
   1387        }
   1388        if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
   1389        {
   1390            return ZYAN_FALSE;
   1391        }
   1392        break;
   1393    case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32:
   1394        if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
   1395            (reg_class != ZYDIS_REGCLASS_GPR32))
   1396        {
   1397            return ZYAN_FALSE;
   1398        }
   1399        if (!ZydisCheckOsz(match, reg_width))
   1400        {
   1401            if (match->eosz != 64 || reg_class != ZYDIS_REGCLASS_GPR32)
   1402            {
   1403                return ZYAN_FALSE;
   1404            }
   1405        }
   1406        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1407        {
   1408            return ZYAN_FALSE;
   1409        }
   1410        break;
   1411    case ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ:
   1412        if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
   1413            (reg_class != ZYDIS_REGCLASS_GPR32) &&
   1414            (reg_class != ZYDIS_REGCLASS_GPR64))
   1415        {
   1416            return ZYAN_FALSE;
   1417        }
   1418        if (!ZydisCheckAsz(match, reg_width))
   1419        {
   1420            return ZYAN_FALSE;
   1421        }
   1422        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1423        {
   1424            return ZYAN_FALSE;
   1425        }
   1426        break;
   1427    case ZYDIS_SEMANTIC_OPTYPE_FPR:
   1428        if (reg_class != ZYDIS_REGCLASS_X87)
   1429        {
   1430            return ZYAN_FALSE;
   1431        }
   1432        break;
   1433    case ZYDIS_SEMANTIC_OPTYPE_MMX:
   1434        if (reg_class != ZYDIS_REGCLASS_MMX)
   1435        {
   1436            return ZYAN_FALSE;
   1437        }
   1438        break;
   1439    case ZYDIS_SEMANTIC_OPTYPE_XMM:
   1440        if (reg_class != ZYDIS_REGCLASS_XMM)
   1441        {
   1442            return ZYAN_FALSE;
   1443        }
   1444        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1445        {
   1446            return ZYAN_FALSE;
   1447        }
   1448        is4_expected_value = def_op->op.encoding == ZYDIS_OPERAND_ENCODING_IS4;
   1449        break;
   1450    case ZYDIS_SEMANTIC_OPTYPE_YMM:
   1451        if (reg_class != ZYDIS_REGCLASS_YMM)
   1452        {
   1453            return ZYAN_FALSE;
   1454        }
   1455        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1456        {
   1457            return ZYAN_FALSE;
   1458        }
   1459        is4_expected_value = def_op->op.encoding == ZYDIS_OPERAND_ENCODING_IS4;
   1460        break;
   1461    case ZYDIS_SEMANTIC_OPTYPE_ZMM:
   1462        if (reg_class != ZYDIS_REGCLASS_ZMM)
   1463        {
   1464            return ZYAN_FALSE;
   1465        }
   1466        if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
   1467        {
   1468            return ZYAN_FALSE;
   1469        }
   1470        break;
   1471    case ZYDIS_SEMANTIC_OPTYPE_TMM:
   1472        if (reg_class != ZYDIS_REGCLASS_TMM)
   1473        {
   1474            return ZYAN_FALSE;
   1475        }
   1476        break;
   1477    case ZYDIS_SEMANTIC_OPTYPE_BND:
   1478        if (reg_class != ZYDIS_REGCLASS_BOUND)
   1479        {
   1480            return ZYAN_FALSE;
   1481        }
   1482        break;
   1483    case ZYDIS_SEMANTIC_OPTYPE_SREG:
   1484        if (reg_class != ZYDIS_REGCLASS_SEGMENT)
   1485        {
   1486            return ZYAN_FALSE;
   1487        }
   1488        if ((def_op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) &&
   1489            (user_op->reg.value == ZYDIS_REGISTER_CS))
   1490        {
   1491            return ZYAN_FALSE;
   1492        }
   1493        break;
   1494    case ZYDIS_SEMANTIC_OPTYPE_CR:
   1495    {
   1496        if (reg_class != ZYDIS_REGCLASS_CONTROL)
   1497        {
   1498            return ZYAN_FALSE;
   1499        }
   1500        static const ZyanU8 cr_lookup[16] =
   1501        {
   1502            1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
   1503        };
   1504        const ZyanI8 reg_id = ZydisRegisterGetId(user_op->reg.value);
   1505        if ((match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) &&
   1506            (reg_id == 8))
   1507        {
   1508            return ZYAN_FALSE;
   1509        }
   1510        if (!cr_lookup[reg_id])
   1511        {
   1512            return ZYAN_FALSE;
   1513        }
   1514        break;
   1515    }
   1516    case ZYDIS_SEMANTIC_OPTYPE_DR:
   1517        if (reg_class != ZYDIS_REGCLASS_DEBUG)
   1518        {
   1519            return ZYAN_FALSE;
   1520        }
   1521        if (user_op->reg.value >= ZYDIS_REGISTER_DR8)
   1522        {
   1523            return ZYAN_FALSE;
   1524        }
   1525        break;
   1526    case ZYDIS_SEMANTIC_OPTYPE_MASK:
   1527        if (reg_class != ZYDIS_REGCLASS_MASK)
   1528        {
   1529            return ZYAN_FALSE;
   1530        }
   1531 
   1532        // MVEX does not require similar policy check
   1533        if ((match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) &&
   1534            (def_op->op.encoding == ZYDIS_OPERAND_ENCODING_MASK))
   1535        {
   1536            const ZydisInstructionDefinitionEVEX *evex_def =
   1537                (const ZydisInstructionDefinitionEVEX *)match->base_definition;
   1538            ZYAN_ASSERT((evex_def->mask_policy != ZYDIS_MASK_POLICY_INVALID) &&
   1539                        (evex_def->mask_policy != ZYDIS_MASK_POLICY_FORBIDDEN));
   1540            if ((evex_def->mask_policy == ZYDIS_MASK_POLICY_REQUIRED) &&
   1541                (user_op->reg.value == ZYDIS_REGISTER_K0))
   1542            {
   1543                return ZYAN_FALSE;
   1544            }
   1545            if ((evex_def->mask_policy == ZYDIS_MASK_POLICY_ALLOWED) &&
   1546                (match->request->evex.zeroing_mask) &&
   1547                (user_op->reg.value == ZYDIS_REGISTER_K0))
   1548            {
   1549                return ZYAN_FALSE;
   1550            }
   1551        }
   1552        break;
   1553    default:
   1554        ZYAN_UNREACHABLE;
   1555    }
   1556 
   1557    if (user_op->reg.is4 != is4_expected_value)
   1558    {
   1559        return ZYAN_FALSE;
   1560    }
   1561 
   1562    return ZYAN_TRUE;
   1563 }
   1564 
   1565 /**
   1566 * Checks if requested operand matches memory operand from instruction definition.
   1567 *
   1568 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   1569 * @param   user_op     Operand definition from `ZydisEncoderRequest` structure.
   1570 * @param   def_op      Decoder's operand definition from current instruction definition.
   1571 *
   1572 * @return  True if operands match, false otherwise.
   1573 */
   1574 static ZyanBool ZydisIsMemoryOperandCompatible(ZydisEncoderInstructionMatch *match,
   1575    const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
   1576 {
   1577    switch (def_op->type)
   1578    {
   1579    case ZYDIS_SEMANTIC_OPTYPE_MEM:
   1580    case ZYDIS_SEMANTIC_OPTYPE_AGEN:
   1581    case ZYDIS_SEMANTIC_OPTYPE_MIB:
   1582    case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX:
   1583    case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY:
   1584    case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ:
   1585    {
   1586        if ((def_op->type == ZYDIS_SEMANTIC_OPTYPE_MIB) &&
   1587            (user_op->mem.scale != 0))
   1588        {
   1589            return ZYAN_FALSE;
   1590        }
   1591        const ZyanI64 displacement = user_op->mem.displacement;
   1592        ZyanU8 disp_size = 0;
   1593        if (displacement)
   1594        {
   1595            disp_size = ZydisGetSignedImmSize(displacement);
   1596            if (disp_size > 32)
   1597            {
   1598                return ZYAN_FALSE;
   1599            }
   1600 
   1601            match->cd8_scale = ZydisGetCompDispScale(match);
   1602            if (match->cd8_scale)
   1603            {
   1604                const ZyanI64 mask = (1 << match->cd8_scale) - 1;
   1605                if (!(displacement & mask))
   1606                {
   1607                    if (ZydisGetSignedImmSize(displacement >> match->cd8_scale) == 8)
   1608                    {
   1609                        disp_size = 8;
   1610                    }
   1611                }
   1612                else if (disp_size == 8)
   1613                {
   1614                    disp_size = 16;
   1615                }
   1616            }
   1617        }
   1618 
   1619        if (def_op->type != ZYDIS_SEMANTIC_OPTYPE_AGEN)
   1620        {
   1621            if (match->eosz != 0)
   1622            {
   1623                const ZyanU8 eosz_index = match->eosz >> 5;
   1624                if (def_op->size[eosz_index] != user_op->mem.size)
   1625                {
   1626                    return ZYAN_FALSE;
   1627                }
   1628            }
   1629            else if ((match->definition->vector_length != ZYDIS_VECTOR_LENGTH_INVALID) ||
   1630                     (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
   1631            {
   1632                ZyanU8 eosz_index = ZydisGetMachineModeWidth(match->request->machine_mode) >> 5;
   1633                if (match->eosz64_forbidden && (eosz_index == 2))
   1634                {
   1635                    eosz_index = 1;
   1636                }
   1637                ZyanU16 allowed_mem_size = def_op->size[eosz_index];
   1638                if ((!allowed_mem_size) &&
   1639                    (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_VEX))
   1640                {
   1641                    ZYAN_ASSERT((match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
   1642                                (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX));
   1643                    switch (match->definition->vector_length)
   1644                    {
   1645                    case ZYDIS_VECTOR_LENGTH_128:
   1646                        allowed_mem_size = 16;
   1647                        break;
   1648                    case ZYDIS_VECTOR_LENGTH_256:
   1649                        allowed_mem_size = 32;
   1650                        break;
   1651                    case ZYDIS_VECTOR_LENGTH_INVALID:
   1652                        ZYAN_ASSERT(match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX);
   1653                        ZYAN_FALLTHROUGH;
   1654                    case ZYDIS_VECTOR_LENGTH_512:
   1655                        allowed_mem_size = 64;
   1656                        break;
   1657                    default:
   1658                        ZYAN_UNREACHABLE;
   1659                    }
   1660                    if (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX)
   1661                    {
   1662                        const ZydisInstructionDefinitionEVEX *evex_def =
   1663                            (const ZydisInstructionDefinitionEVEX *)match->base_definition;
   1664                        static const ZyanU8 element_sizes[ZYDIS_IELEMENT_SIZE_MAX_VALUE + 1] =
   1665                        {
   1666                              0, 1, 2, 4, 8, 16
   1667                        };
   1668                        ZYAN_ASSERT(evex_def->element_size < ZYAN_ARRAY_LENGTH(element_sizes));
   1669                        const ZyanU8 element_size = element_sizes[evex_def->element_size];
   1670                        if (match->request->evex.broadcast || evex_def->broadcast)
   1671                        {
   1672                            allowed_mem_size = element_size;
   1673                        }
   1674                        else
   1675                        {
   1676                            switch (evex_def->tuple_type)
   1677                            {
   1678                            case ZYDIS_TUPLETYPE_FV:
   1679                                break;
   1680                            case ZYDIS_TUPLETYPE_HV:
   1681                                allowed_mem_size /= 2;
   1682                                break;
   1683                            case ZYDIS_TUPLETYPE_QUARTER:
   1684                                allowed_mem_size /= 4;
   1685                                break;
   1686                            default:
   1687                                ZYAN_UNREACHABLE;
   1688                            }
   1689                        }
   1690                    }
   1691                    else
   1692                    {
   1693                        const ZydisInstructionDefinitionMVEX *mvex_def =
   1694                            (const ZydisInstructionDefinitionMVEX *)match->base_definition;
   1695                        ZyanU16 element_size;
   1696                        switch (match->request->mvex.conversion)
   1697                        {
   1698                        case ZYDIS_CONVERSION_MODE_INVALID:
   1699 
   1700                            switch (mvex_def->functionality)
   1701                            {
   1702                            case ZYDIS_MVEX_FUNC_SF_32:
   1703                            case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
   1704                            case ZYDIS_MVEX_FUNC_UF_32:
   1705                            case ZYDIS_MVEX_FUNC_DF_32:
   1706                            case ZYDIS_MVEX_FUNC_SI_32:
   1707                            case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
   1708                            case ZYDIS_MVEX_FUNC_UI_32:
   1709                            case ZYDIS_MVEX_FUNC_DI_32:
   1710                                allowed_mem_size = 64;
   1711                                element_size = 4;
   1712                                break;
   1713                            case ZYDIS_MVEX_FUNC_SF_64:
   1714                            case ZYDIS_MVEX_FUNC_UF_64:
   1715                            case ZYDIS_MVEX_FUNC_DF_64:
   1716                            case ZYDIS_MVEX_FUNC_SI_64:
   1717                            case ZYDIS_MVEX_FUNC_UI_64:
   1718                            case ZYDIS_MVEX_FUNC_DI_64:
   1719                                allowed_mem_size = 64;
   1720                                element_size = 8;
   1721                                break;
   1722                            case ZYDIS_MVEX_FUNC_SF_32_BCST:
   1723                            case ZYDIS_MVEX_FUNC_SI_32_BCST:
   1724                                allowed_mem_size = 32;
   1725                                element_size = 4;
   1726                                break;
   1727                            default:
   1728                                ZYAN_UNREACHABLE;
   1729                            }
   1730                            break;
   1731                        case ZYDIS_CONVERSION_MODE_FLOAT16:
   1732                        case ZYDIS_CONVERSION_MODE_SINT16:
   1733                        case ZYDIS_CONVERSION_MODE_UINT16:
   1734                            allowed_mem_size = 32;
   1735                            element_size = 2;
   1736                            break;
   1737                        case ZYDIS_CONVERSION_MODE_SINT8:
   1738                        case ZYDIS_CONVERSION_MODE_UINT8:
   1739                            allowed_mem_size = 16;
   1740                            element_size = 1;
   1741                            break;
   1742                        default:
   1743                            ZYAN_UNREACHABLE;
   1744                        }
   1745                        ZYAN_ASSERT(!mvex_def->broadcast || !match->request->mvex.broadcast);
   1746                        switch (mvex_def->broadcast)
   1747                        {
   1748                        case ZYDIS_MVEX_STATIC_BROADCAST_NONE:
   1749                            break;
   1750                        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8:
   1751                        case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16:
   1752                            allowed_mem_size = element_size;
   1753                            break;
   1754                        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8:
   1755                        case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16:
   1756                            allowed_mem_size = element_size * 4;
   1757                            break;
   1758                        default:
   1759                            ZYAN_UNREACHABLE;
   1760                        }
   1761                        switch (match->request->mvex.broadcast)
   1762                        {
   1763                        case ZYDIS_BROADCAST_MODE_INVALID:
   1764                            break;
   1765                        case ZYDIS_BROADCAST_MODE_1_TO_8:
   1766                        case ZYDIS_BROADCAST_MODE_1_TO_16:
   1767                            allowed_mem_size = element_size;
   1768                            break;
   1769                        case ZYDIS_BROADCAST_MODE_4_TO_8:
   1770                        case ZYDIS_BROADCAST_MODE_4_TO_16:
   1771                            allowed_mem_size = element_size * 4;
   1772                            break;
   1773                        default:
   1774                            ZYAN_UNREACHABLE;
   1775                        }
   1776                    }
   1777                }
   1778                if (user_op->mem.size != allowed_mem_size)
   1779                {
   1780                    return ZYAN_FALSE;
   1781                }
   1782            }
   1783            else if (match->definition->rex_w)
   1784            {
   1785                match->eosz = 64;
   1786            }
   1787            else if (match->definition->vector_length == ZYDIS_VECTOR_LENGTH_INVALID)
   1788            {
   1789                match->eosz = ZydisGetOperandSizeFromElementSize(match, def_op->size,
   1790                    user_op->mem.size, ZYAN_TRUE);
   1791                if (match->eosz == 0)
   1792                {
   1793                    return ZYAN_FALSE;
   1794                }
   1795            }
   1796            else
   1797            {
   1798                ZYAN_UNREACHABLE;
   1799            }
   1800        }
   1801        else
   1802        {
   1803            if (match->easz != 0)
   1804            {
   1805                if (match->easz != user_op->mem.size)
   1806                {
   1807                    return ZYAN_FALSE;
   1808                }
   1809            }
   1810            else
   1811            {
   1812                switch (user_op->mem.size)
   1813                {
   1814                case 2:
   1815                case 4:
   1816                case 8:
   1817                    match->easz = (ZyanU8)user_op->mem.size << 3;
   1818                    break;
   1819                default:
   1820                    return ZYAN_FALSE;
   1821                }
   1822            }
   1823        }
   1824 
   1825        ZydisRegisterClass vsib_index_class = ZYDIS_REGCLASS_INVALID;
   1826        ZyanBool is_vsib = ZYAN_TRUE;
   1827        switch (def_op->type)
   1828        {
   1829        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX:
   1830            vsib_index_class = ZYDIS_REGCLASS_XMM;
   1831            break;
   1832        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY:
   1833            vsib_index_class = ZYDIS_REGCLASS_YMM;
   1834            break;
   1835        case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ:
   1836            vsib_index_class = ZYDIS_REGCLASS_ZMM;
   1837            break;
   1838        default:
   1839            is_vsib = ZYAN_FALSE;
   1840            break;
   1841        }
   1842        const ZyanBool is_rip_relative = (user_op->mem.base == ZYDIS_REGISTER_RIP) ||
   1843                                         (user_op->mem.base == ZYDIS_REGISTER_EIP);
   1844        if (is_rip_relative)
   1845        {
   1846            const ZyanBool no_rip_rel = ZYDIS_OPDEF_GET_MEM_HIGH_BIT(match->base_definition->op_rm);
   1847            if (no_rip_rel || ((match->definition->modrm & 7) == 4))
   1848            {
   1849                return ZYAN_FALSE;
   1850            }
   1851        }
   1852        const ZydisRegisterClass reg_base_class = ZydisRegisterGetClass(user_op->mem.base);
   1853        if ((reg_base_class == ZYDIS_REGCLASS_INVALID) &&
   1854            (user_op->mem.base != ZYDIS_REGISTER_NONE))
   1855        {
   1856            return ZYAN_FALSE;
   1857        }
   1858        const ZydisRegisterClass reg_index_class = ZydisRegisterGetClass(user_op->mem.index);
   1859        if ((reg_index_class == ZYDIS_REGCLASS_INVALID) &&
   1860            (user_op->mem.index != ZYDIS_REGISTER_NONE))
   1861        {
   1862            return ZYAN_FALSE;
   1863        }
   1864        if (is_vsib)
   1865        {
   1866            const ZyanU8 mode_width = ZydisGetMachineModeWidth(match->request->machine_mode);
   1867            const ZyanI8 reg_index_id = ZydisRegisterGetId(user_op->mem.index);
   1868            if (((match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) ||
   1869                 (reg_base_class != ZYDIS_REGCLASS_GPR64)) &&
   1870                 (reg_base_class != ZYDIS_REGCLASS_GPR32) &&
   1871                 (reg_base_class != ZYDIS_REGCLASS_INVALID))
   1872            {
   1873                return ZYAN_FALSE;
   1874            }
   1875            if ((reg_base_class == ZYDIS_REGCLASS_GPR32) &&
   1876                (mode_width != 64) &&
   1877                (ZydisRegisterGetId(user_op->mem.base) > 7))
   1878            {
   1879                return ZYAN_FALSE;
   1880            }
   1881            ZyanU8 max_reg_id = 7;
   1882            if (mode_width == 64)
   1883            {
   1884                max_reg_id = match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_VEX ?
   1885                    31 : 15;
   1886            }
   1887            if ((reg_index_class != vsib_index_class) ||
   1888                (reg_index_id > max_reg_id))
   1889            {
   1890                return ZYAN_FALSE;
   1891            }
   1892        }
   1893        else
   1894        {
   1895            if (!ZydisIsValidAddressingClass(match, reg_base_class, user_op->mem.base))
   1896            {
   1897                if (!is_rip_relative || match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
   1898                {
   1899                    return ZYAN_FALSE;
   1900                }
   1901            }
   1902            if (!ZydisIsValidAddressingClass(match, reg_index_class, user_op->mem.index))
   1903            {
   1904                return ZYAN_FALSE;
   1905            }
   1906            if (reg_base_class != ZYDIS_REGCLASS_INVALID &&
   1907                reg_index_class != ZYDIS_REGCLASS_INVALID &&
   1908                reg_base_class != reg_index_class)
   1909            {
   1910                return ZYAN_FALSE;
   1911            }
   1912            if (user_op->mem.index == ZYDIS_REGISTER_ESP ||
   1913                user_op->mem.index == ZYDIS_REGISTER_RSP)
   1914            {
   1915                return ZYAN_FALSE;
   1916            }
   1917        }
   1918        if (reg_index_class != ZYDIS_REGCLASS_INVALID &&
   1919            user_op->mem.scale == 0 &&
   1920            def_op->type != ZYDIS_SEMANTIC_OPTYPE_MIB)
   1921        {
   1922            return ZYAN_FALSE;
   1923        }
   1924        if (reg_index_class == ZYDIS_REGCLASS_INVALID &&
   1925            user_op->mem.scale != 0)
   1926        {
   1927            return ZYAN_FALSE;
   1928        }
   1929        ZyanU8 candidate_easz = 0;
   1930        ZyanBool disp_only = ZYAN_FALSE;
   1931        if (reg_base_class != ZYDIS_REGCLASS_INVALID)
   1932        {
   1933            if (is_rip_relative)
   1934            {
   1935                candidate_easz = user_op->mem.base == ZYDIS_REGISTER_RIP ? 64 : 32;
   1936            }
   1937            else
   1938            {
   1939                candidate_easz = (ZyanU8)ZydisRegisterClassGetWidth(match->request->machine_mode,
   1940                    reg_base_class);
   1941            }
   1942        }
   1943        else if (reg_index_class != ZYDIS_REGCLASS_INVALID)
   1944        {
   1945            if (is_vsib)
   1946            {
   1947                candidate_easz = ZydisGetMachineModeWidth(match->request->machine_mode);
   1948            }
   1949            else
   1950            {
   1951                candidate_easz = (ZyanU8)ZydisRegisterClassGetWidth(match->request->machine_mode,
   1952                    reg_index_class);
   1953            }
   1954        }
   1955        else if (disp_size != 8 || !match->cd8_scale)
   1956        {
   1957            const ZyanU8 addr_size = ZydisGetMaxAddressSize(match->request);
   1958            if (disp_size > addr_size)
   1959            {
   1960                return ZYAN_FALSE;
   1961            }
   1962            ZyanU8 min_disp_size = match->easz ? match->easz : 16;
   1963            if (((min_disp_size == 16) && !(match->definition->address_sizes & ZYDIS_WIDTH_16)) ||
   1964                 (min_disp_size == 64) ||
   1965                 (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
   1966            {
   1967                min_disp_size = 32;
   1968            }
   1969            if (disp_size < min_disp_size)
   1970            {
   1971                disp_size = min_disp_size;
   1972            }
   1973            const ZyanI64 disp = user_op->mem.displacement;
   1974            if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
   1975            {
   1976                candidate_easz = addr_size;
   1977                if (addr_size == 32 && disp >= 0 && match->easz != 32)
   1978                {
   1979                    candidate_easz = 64;
   1980                }
   1981            }
   1982            else
   1983            {
   1984                const ZyanU64 uimm = disp & (~(0xFFFFFFFFFFFFFFFFULL << (addr_size - 1) << 1));
   1985                if (disp_size < addr_size && ZydisGetUnsignedImmSize(uimm) > disp_size)
   1986                {
   1987                    disp_size = addr_size;
   1988                }
   1989                candidate_easz = disp_size;
   1990            }
   1991            disp_only = ZYAN_TRUE;
   1992        }
   1993        if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
   1994        {
   1995            if (is_rip_relative && reg_index_class != ZYDIS_REGCLASS_INVALID)
   1996            {
   1997                return ZYAN_FALSE;
   1998            }
   1999        }
   2000        else
   2001        {
   2002            if (candidate_easz == 16 && !disp_only)
   2003            {
   2004                if (disp_size > 16)
   2005                {
   2006                    return ZYAN_FALSE;
   2007                }
   2008                const ZyanI8 rm16 = ZydisGetRm16(user_op->mem.base, user_op->mem.index);
   2009                if (rm16 == -1)
   2010                {
   2011                    return ZYAN_FALSE;
   2012                }
   2013                const ZyanU8 allowed_scale = rm16 < 4 ? 1 : 0;
   2014                if (user_op->mem.scale != allowed_scale)
   2015                {
   2016                    return ZYAN_FALSE;
   2017                }
   2018            }
   2019        }
   2020        if (match->easz != 0)
   2021        {
   2022            if (match->easz != candidate_easz)
   2023            {
   2024                return ZYAN_FALSE;
   2025            }
   2026        }
   2027        else
   2028        {
   2029            match->easz = candidate_easz;
   2030        }
   2031        if ((match->base_definition->address_size_map == ZYDIS_ADSIZE_MAP_IGNORED) &&
   2032            (match->easz != ZydisGetMachineModeWidth(match->request->machine_mode)))
   2033        {
   2034            return ZYAN_FALSE;
   2035        }
   2036        match->disp_size = disp_size;
   2037        break;
   2038    }
   2039    case ZYDIS_SEMANTIC_OPTYPE_MOFFS:
   2040    {
   2041        if (user_op->mem.base != ZYDIS_REGISTER_NONE ||
   2042            user_op->mem.index != ZYDIS_REGISTER_NONE ||
   2043            user_op->mem.scale != 0)
   2044        {
   2045            return ZYAN_FALSE;
   2046        }
   2047        const ZyanU8 min_disp_size = ZydisGetSignedImmSize(user_op->mem.displacement);
   2048        if (min_disp_size > ZydisGetMaxAddressSize(match->request))
   2049        {
   2050            return ZYAN_FALSE;
   2051        }
   2052        if (match->eosz != 0)
   2053        {
   2054            const ZyanU8 eosz_index = match->eosz >> 5;
   2055            if (def_op->size[eosz_index] != user_op->mem.size)
   2056            {
   2057                return ZYAN_FALSE;
   2058            }
   2059        }
   2060        else
   2061        {
   2062            match->eosz = ZydisGetOperandSizeFromElementSize(match, def_op->size,
   2063                user_op->mem.size, ZYAN_TRUE);
   2064            if (match->eosz == 0)
   2065            {
   2066                return ZYAN_FALSE;
   2067            }
   2068        }
   2069        match->disp_size = ZydisGetEffectiveImmSize(match, user_op->mem.displacement, def_op);
   2070        if (match->disp_size == 0)
   2071        {
   2072            return ZYAN_FALSE;
   2073        }
   2074        // This is not a standard rejection. It's a special case for `mov` instructions (`moffs`
   2075        // variants only). In 64-bit mode it's possible to get a shorter encoding for addresses
   2076        // that can fit into 32-bit displacements.
   2077        if (match->disp_size == 64 && min_disp_size < match->disp_size)
   2078        {
   2079            return ZYAN_FALSE;
   2080        }
   2081        break;
   2082    }
   2083    default:
   2084        ZYAN_UNREACHABLE;
   2085    }
   2086 
   2087    return ZYAN_TRUE;
   2088 }
   2089 
   2090 /**
   2091 * Checks if requested operand matches pointer operand from instruction definition.
   2092 *
   2093 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2094 * @param   user_op     Operand definition from `ZydisEncoderRequest` structure.
   2095 *
   2096 * @return  True if operands match, false otherwise.
   2097 */
   2098 static ZyanBool ZydisIsPointerOperandCompatible(ZydisEncoderInstructionMatch *match,
   2099    const ZydisEncoderOperand *user_op)
   2100 {
   2101    ZYAN_ASSERT(match->eosz == 0);
   2102    ZYAN_ASSERT(match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64);
   2103    ZYAN_ASSERT((match->request->branch_type == ZYDIS_BRANCH_TYPE_NONE) ||
   2104                (match->request->branch_type == ZYDIS_BRANCH_TYPE_FAR));
   2105    const ZyanU8 min_disp_size = ZydisGetUnsignedImmSize(user_op->ptr.offset);
   2106    const ZyanU8 desired_disp_size = (match->request->branch_width == ZYDIS_BRANCH_WIDTH_NONE)
   2107        ? ZydisGetMachineModeWidth(match->request->machine_mode)
   2108        : (4 << match->request->branch_width);
   2109    if (min_disp_size > desired_disp_size)
   2110    {
   2111        return ZYAN_FALSE;
   2112    }
   2113    match->eosz = match->disp_size = desired_disp_size;
   2114    match->imm_size = 16;
   2115    return ZYAN_TRUE;
   2116 }
   2117 
   2118 /**
   2119 * Checks if requested operand matches immediate operand from instruction definition.
   2120 *
   2121 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2122 * @param   user_op     Operand definition from `ZydisEncoderRequest` structure.
   2123 * @param   def_op      Decoder's operand definition from current instruction definition.
   2124 *
   2125 * @return  True if operands match, false otherwise.
   2126 */
   2127 static ZyanBool ZydisIsImmediateOperandCompabile(ZydisEncoderInstructionMatch *match,
   2128    const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
   2129 {
   2130    switch (def_op->type)
   2131    {
   2132    case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1:
   2133        if (user_op->imm.u != 1)
   2134        {
   2135            return ZYAN_FALSE;
   2136        }
   2137        break;
   2138    case ZYDIS_SEMANTIC_OPTYPE_IMM:
   2139    case ZYDIS_SEMANTIC_OPTYPE_REL:
   2140    {
   2141        const ZyanU8 imm_size = ZydisGetEffectiveImmSize(match, user_op->imm.s, def_op);
   2142        if (def_op->op.encoding != ZYDIS_OPERAND_ENCODING_IS4)
   2143        {
   2144            if (imm_size == 0)
   2145            {
   2146                return ZYAN_FALSE;
   2147            }
   2148            if (match->imm_size)
   2149            {
   2150                ZYAN_ASSERT(match->disp_size == 0);
   2151                match->disp_size = match->imm_size;
   2152            }
   2153        }
   2154        else
   2155        {
   2156            ZYAN_ASSERT(match->imm_size == 0);
   2157            if (imm_size != 8)
   2158            {
   2159                return ZYAN_FALSE;
   2160            }
   2161        }
   2162        match->imm_size = imm_size;
   2163        match->has_rel_operand = (def_op->type == ZYDIS_SEMANTIC_OPTYPE_REL);
   2164        break;
   2165    }
   2166    default:
   2167        ZYAN_UNREACHABLE;
   2168    }
   2169 
   2170    return ZYAN_TRUE;
   2171 }
   2172 
   2173 /**
   2174 * Checks if requested boardcast mode is compatible with instruction definition.
   2175 *
   2176 * @param   evex_def       Definition for `EVEX`-encoded instruction.
   2177 * @param   vector_length  Vector length.
   2178 * @param   broadcast      Requested broadcast mode.
   2179 *
   2180 * @return  True if broadcast mode is compatible, false otherwise.
   2181 */
   2182 static ZyanBool ZydisIsBroadcastModeCompatible(const ZydisInstructionDefinitionEVEX *evex_def,
   2183    ZydisVectorLength vector_length, ZydisBroadcastMode broadcast)
   2184 {
   2185    if (broadcast == ZYDIS_BROADCAST_MODE_INVALID)
   2186    {
   2187        return ZYAN_TRUE;
   2188    }
   2189 
   2190    ZyanU8 vector_size = 0;
   2191    ZYAN_ASSERT(vector_length != ZYDIS_VECTOR_LENGTH_INVALID);
   2192    switch (vector_length)
   2193    {
   2194    case ZYDIS_VECTOR_LENGTH_128:
   2195        vector_size = 16;
   2196        break;
   2197    case ZYDIS_VECTOR_LENGTH_256:
   2198        vector_size = 32;
   2199        break;
   2200    case ZYDIS_VECTOR_LENGTH_512:
   2201        vector_size = 64;
   2202        break;
   2203    default:
   2204        ZYAN_UNREACHABLE;
   2205    }
   2206    switch (evex_def->tuple_type)
   2207    {
   2208    case ZYDIS_TUPLETYPE_FV:
   2209        break;
   2210    case ZYDIS_TUPLETYPE_HV:
   2211        vector_size /= 2;
   2212        break;
   2213    case ZYDIS_TUPLETYPE_QUARTER:
   2214        vector_size /= 4;
   2215        break;
   2216    default:
   2217        ZYAN_UNREACHABLE;
   2218    }
   2219 
   2220    ZyanU8 element_size;
   2221    switch (evex_def->element_size)
   2222    {
   2223    case ZYDIS_IELEMENT_SIZE_16:
   2224        element_size = 2;
   2225        break;
   2226    case ZYDIS_IELEMENT_SIZE_32:
   2227        element_size = 4;
   2228        break;
   2229    case ZYDIS_IELEMENT_SIZE_64:
   2230        element_size = 8;
   2231        break;
   2232    default:
   2233        ZYAN_UNREACHABLE;
   2234    }
   2235 
   2236    ZydisBroadcastMode allowed_mode;
   2237    const ZyanU8 element_count = vector_size / element_size;
   2238    switch (element_count)
   2239    {
   2240    case 2:
   2241        allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_2;
   2242        break;
   2243    case 4:
   2244        allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_4;
   2245        break;
   2246    case 8:
   2247        allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_8;
   2248        break;
   2249    case 16:
   2250        allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_16;
   2251        break;
   2252    case 32:
   2253        allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_32;
   2254        break;
   2255    default:
   2256        ZYAN_UNREACHABLE;
   2257    }
   2258 
   2259    if (broadcast != allowed_mode)
   2260    {
   2261        return ZYAN_FALSE;
   2262    }
   2263 
   2264    return ZYAN_TRUE;
   2265 }
   2266 
   2267 /**
   2268 * Checks if requested `EVEX`-specific features are compatible with instruction definition.
   2269 *
   2270 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2271 * @param   request     A pointer to `ZydisEncoderRequest` struct.
   2272 *
   2273 * @return  True if features are compatible, false otherwise.
   2274 */
   2275 static ZyanBool ZydisAreEvexFeaturesCompatible(const ZydisEncoderInstructionMatch *match,
   2276    const ZydisEncoderRequest *request)
   2277 {
   2278    if (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_EVEX)
   2279    {
   2280        return ZYAN_TRUE;
   2281    }
   2282 
   2283    const ZydisInstructionDefinitionEVEX *evex_def =
   2284        (const ZydisInstructionDefinitionEVEX *)match->base_definition;
   2285    if ((!evex_def->accepts_zero_mask) &&
   2286        (evex_def->mask_override != ZYDIS_MASK_OVERRIDE_ZEROING) &&
   2287        (request->evex.zeroing_mask))
   2288    {
   2289        return ZYAN_FALSE;
   2290    }
   2291 
   2292    switch (evex_def->functionality)
   2293    {
   2294    case ZYDIS_EVEX_FUNC_INVALID:
   2295        if ((request->evex.sae) ||
   2296            (request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2297            (request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
   2298        {
   2299            return ZYAN_FALSE;
   2300        }
   2301        break;
   2302    case ZYDIS_EVEX_FUNC_BC:
   2303        if ((request->evex.sae) ||
   2304            (request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
   2305        {
   2306            return ZYAN_FALSE;
   2307        }
   2308        if (!ZydisIsBroadcastModeCompatible(evex_def, match->definition->vector_length,
   2309            request->evex.broadcast))
   2310        {
   2311            return ZYAN_FALSE;
   2312        }
   2313        break;
   2314    case ZYDIS_EVEX_FUNC_RC:
   2315        if (request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID)
   2316        {
   2317            return ZYAN_FALSE;
   2318        }
   2319        if (request->evex.rounding == ZYDIS_ROUNDING_MODE_INVALID)
   2320        {
   2321            if (request->evex.sae)
   2322            {
   2323                return ZYAN_FALSE;
   2324            }
   2325        }
   2326        else
   2327        {
   2328            if (!request->evex.sae)
   2329            {
   2330                return ZYAN_FALSE;
   2331            }
   2332        }
   2333        break;
   2334    case ZYDIS_EVEX_FUNC_SAE:
   2335        if ((request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2336            (request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
   2337        {
   2338            return ZYAN_FALSE;
   2339        }
   2340        break;
   2341    default:
   2342        ZYAN_UNREACHABLE;
   2343    }
   2344 
   2345    return ZYAN_TRUE;
   2346 }
   2347 
   2348 /**
   2349 * Checks if requested `MVEX`-specific features are compatible with instruction definition.
   2350 *
   2351 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2352 * @param   request     A pointer to `ZydisEncoderRequest` struct.
   2353 *
   2354 * @return  True if features are compatible, false otherwise.
   2355 */
   2356 static ZyanBool ZydisAreMvexFeaturesCompatible(const ZydisEncoderInstructionMatch *match,
   2357    const ZydisEncoderRequest *request)
   2358 {
   2359    if (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_MVEX)
   2360    {
   2361        return ZYAN_TRUE;
   2362    }
   2363    if (((match->definition->modrm >> 6) == 3) &&
   2364        (request->mvex.eviction_hint))
   2365    {
   2366        return ZYAN_FALSE;
   2367    }
   2368 
   2369    const ZydisInstructionDefinitionMVEX *mvex_def =
   2370        (const ZydisInstructionDefinitionMVEX *)match->base_definition;
   2371    switch (mvex_def->functionality)
   2372    {
   2373    case ZYDIS_MVEX_FUNC_IGNORED:
   2374    case ZYDIS_MVEX_FUNC_INVALID:
   2375    case ZYDIS_MVEX_FUNC_F_32:
   2376    case ZYDIS_MVEX_FUNC_I_32:
   2377    case ZYDIS_MVEX_FUNC_F_64:
   2378    case ZYDIS_MVEX_FUNC_I_64:
   2379    case ZYDIS_MVEX_FUNC_UF_64:
   2380    case ZYDIS_MVEX_FUNC_UI_64:
   2381    case ZYDIS_MVEX_FUNC_DF_64:
   2382    case ZYDIS_MVEX_FUNC_DI_64:
   2383        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2384            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2385            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2386            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2387            (request->mvex.sae))
   2388        {
   2389            return ZYAN_FALSE;
   2390        }
   2391        break;
   2392    case ZYDIS_MVEX_FUNC_RC:
   2393        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2394            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2395            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2396            (request->mvex.eviction_hint))
   2397        {
   2398            return ZYAN_FALSE;
   2399        }
   2400        break;
   2401    case ZYDIS_MVEX_FUNC_SAE:
   2402        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2403            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2404            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2405            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2406            (request->mvex.eviction_hint))
   2407        {
   2408            return ZYAN_FALSE;
   2409        }
   2410        break;
   2411    case ZYDIS_MVEX_FUNC_SWIZZLE_32:
   2412    case ZYDIS_MVEX_FUNC_SWIZZLE_64:
   2413        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2414            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2415            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2416            (request->mvex.sae))
   2417        {
   2418            return ZYAN_FALSE;
   2419        }
   2420        break;
   2421    case ZYDIS_MVEX_FUNC_SF_32:
   2422        if ((request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2423            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2424            (request->mvex.sae))
   2425        {
   2426            return ZYAN_FALSE;
   2427        }
   2428        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2429            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_16) &&
   2430            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
   2431        {
   2432            return ZYAN_FALSE;
   2433        }
   2434        if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) &&
   2435            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_FLOAT16) &&
   2436            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT8) &&
   2437            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT16) &&
   2438            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT16))
   2439        {
   2440            return ZYAN_FALSE;
   2441        }
   2442        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2443            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID))
   2444        {
   2445            return ZYAN_FALSE;
   2446        }
   2447        break;
   2448    case ZYDIS_MVEX_FUNC_SI_32:
   2449        if ((request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2450            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2451            (request->mvex.sae))
   2452        {
   2453            return ZYAN_FALSE;
   2454        }
   2455        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2456            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_16) &&
   2457            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
   2458        {
   2459            return ZYAN_FALSE;
   2460        }
   2461        if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) &&
   2462            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT8) &&
   2463            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT8) &&
   2464            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT16) &&
   2465            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT16))
   2466        {
   2467            return ZYAN_FALSE;
   2468        }
   2469        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2470            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID))
   2471        {
   2472            return ZYAN_FALSE;
   2473        }
   2474        break;
   2475    case ZYDIS_MVEX_FUNC_SF_32_BCST:
   2476    case ZYDIS_MVEX_FUNC_SI_32_BCST:
   2477        if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2478            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2479            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2480            (request->mvex.sae))
   2481        {
   2482            return ZYAN_FALSE;
   2483        }
   2484        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2485            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_16) &&
   2486            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
   2487        {
   2488            return ZYAN_FALSE;
   2489        }
   2490        break;
   2491    case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
   2492    case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
   2493        if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2494            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2495            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2496            (request->mvex.sae))
   2497        {
   2498            return ZYAN_FALSE;
   2499        }
   2500        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2501            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
   2502        {
   2503            return ZYAN_FALSE;
   2504        }
   2505        break;
   2506    case ZYDIS_MVEX_FUNC_SF_64:
   2507    case ZYDIS_MVEX_FUNC_SI_64:
   2508        if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
   2509            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2510            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2511            (request->mvex.sae))
   2512        {
   2513            return ZYAN_FALSE;
   2514        }
   2515        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
   2516            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_8) &&
   2517            (request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_8))
   2518        {
   2519            return ZYAN_FALSE;
   2520        }
   2521        break;
   2522    case ZYDIS_MVEX_FUNC_UF_32:
   2523    case ZYDIS_MVEX_FUNC_DF_32:
   2524        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2525            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2526            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2527            (request->mvex.sae))
   2528        {
   2529            return ZYAN_FALSE;
   2530        }
   2531        break;
   2532    case ZYDIS_MVEX_FUNC_UI_32:
   2533    case ZYDIS_MVEX_FUNC_DI_32:
   2534        if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
   2535            (request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
   2536            (request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
   2537            (request->mvex.sae))
   2538        {
   2539            return ZYAN_FALSE;
   2540        }
   2541        if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) &&
   2542            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT8) &&
   2543            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT8) &&
   2544            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT16) &&
   2545            (request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT16))
   2546        {
   2547            return ZYAN_FALSE;
   2548        }
   2549        break;
   2550    default:
   2551        ZYAN_UNREACHABLE;
   2552    }
   2553 
   2554    return ZYAN_TRUE;
   2555 }
   2556 
   2557 /**
   2558 * Checks if operands specified in encoder request satisfy additional constraints mandated by
   2559 * matched instruction definition.
   2560 *
   2561 * @param   match   A pointer to `ZydisEncoderInstructionMatch` struct.
   2562 *
   2563 * @return  True if operands passed the checks, false otherwise.
   2564 */
   2565 static ZyanBool ZydisCheckConstraints(const ZydisEncoderInstructionMatch *match)
   2566 {
   2567    const ZydisEncoderOperand *operands = match->request->operands;
   2568    ZyanBool is_gather = ZYAN_FALSE;
   2569    switch (match->definition->encoding)
   2570    {
   2571    case ZYDIS_INSTRUCTION_ENCODING_VEX:
   2572    {
   2573        const ZydisInstructionDefinitionVEX *vex_def =
   2574            (const ZydisInstructionDefinitionVEX *)match->base_definition;
   2575        if (vex_def->is_gather)
   2576        {
   2577            ZYAN_ASSERT(match->request->operand_count == 3);
   2578            ZYAN_ASSERT(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2579            ZYAN_ASSERT(operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY);
   2580            ZYAN_ASSERT(operands[2].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2581            const ZyanI8 dest = ZydisRegisterGetId(operands[0].reg.value);
   2582            const ZyanI8 index = ZydisRegisterGetId(operands[1].mem.index);
   2583            const ZyanI8 mask = ZydisRegisterGetId(operands[2].reg.value);
   2584            // If any pair of the index, mask, or destination registers are the same, the
   2585            // instruction results a UD fault.
   2586            if ((dest == index) || (dest == mask) || (index == mask))
   2587            {
   2588                return ZYAN_FALSE;
   2589            }
   2590        }
   2591 
   2592        if (vex_def->no_source_source_match)
   2593        {
   2594            ZYAN_ASSERT(match->request->operand_count == 3);
   2595            ZYAN_ASSERT(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2596            ZYAN_ASSERT(operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2597            ZYAN_ASSERT(operands[2].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2598            const ZydisRegister dest = operands[0].reg.value;
   2599            const ZydisRegister source1 = operands[1].reg.value;
   2600            const ZydisRegister source2 = operands[2].reg.value;
   2601            // AMX-E4: #UD if srcdest == src1 OR src1 == src2 OR srcdest == src2.
   2602            if ((dest == source1) || (source1 == source2) || (dest == source2))
   2603            {
   2604                return ZYAN_FALSE;
   2605            }
   2606        }
   2607 
   2608        return ZYAN_TRUE;
   2609    }
   2610    case ZYDIS_INSTRUCTION_ENCODING_EVEX:
   2611    {
   2612        const ZydisInstructionDefinitionEVEX *evex_def =
   2613            (const ZydisInstructionDefinitionEVEX *)match->base_definition;
   2614        is_gather = evex_def->is_gather;
   2615        if (evex_def->no_source_dest_match)
   2616        {
   2617            ZYAN_ASSERT(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2618            ZYAN_ASSERT(operands[2].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2619            ZYAN_ASSERT((operands[3].type == ZYDIS_OPERAND_TYPE_REGISTER) ||
   2620                        (operands[3].type == ZYDIS_OPERAND_TYPE_MEMORY));
   2621            const ZydisRegister dest = operands[0].reg.value;
   2622            const ZydisRegister source1 = operands[2].reg.value;
   2623            const ZydisRegister source2 = (operands[3].type == ZYDIS_OPERAND_TYPE_REGISTER)
   2624                ? operands[3].reg.value
   2625                : ZYDIS_REGISTER_NONE;
   2626 
   2627            if ((dest == source1) || (dest == source2))
   2628            {
   2629                return ZYAN_FALSE;
   2630            }
   2631        }
   2632        break;
   2633    }
   2634    case ZYDIS_INSTRUCTION_ENCODING_MVEX:
   2635    {
   2636        const ZydisInstructionDefinitionMVEX *mvex_def =
   2637            (const ZydisInstructionDefinitionMVEX *)match->base_definition;
   2638        is_gather = mvex_def->is_gather;
   2639        break;
   2640    }
   2641    default:
   2642        return ZYAN_TRUE;
   2643    }
   2644 
   2645    if ((is_gather) && (operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER))
   2646    {
   2647        ZYAN_ASSERT(match->request->operand_count == 3);
   2648        ZYAN_ASSERT(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER);
   2649        ZYAN_ASSERT(operands[2].type == ZYDIS_OPERAND_TYPE_MEMORY);
   2650        const ZyanI8 dest = ZydisRegisterGetId(operands[0].reg.value);
   2651        const ZyanI8 index = ZydisRegisterGetId(operands[2].mem.index);
   2652        // EVEX: The instruction will #UD fault if the destination vector zmm1 is the same as
   2653        // index vector VINDEX.
   2654        // MVEX: The KNC GATHER instructions forbid using the same vector register for destination
   2655        // and for the index. (https://github.com/intelxed/xed/issues/281#issuecomment-970074554)
   2656        if (dest == index)
   2657        {
   2658            return ZYAN_FALSE;
   2659        }
   2660    }
   2661 
   2662    return ZYAN_TRUE;
   2663 }
   2664 
   2665 /**
   2666 * Checks if operands and encoding-specific features from `ZydisEncoderRequest` match
   2667 * encoder's instruction definition.
   2668 *
   2669 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2670 * @param   request     A pointer to `ZydisEncoderRequest` struct.
   2671 *
   2672 * @return  True if definition is compatible, false otherwise.
   2673 */
   2674 static ZyanBool ZydisIsDefinitionCompatible(ZydisEncoderInstructionMatch *match,
   2675    const ZydisEncoderRequest *request)
   2676 {
   2677    ZYAN_ASSERT(request->operand_count == match->base_definition->operand_count_visible);
   2678    match->operands = ZydisGetOperandDefinitions(match->base_definition);
   2679 
   2680    if (!ZydisAreEvexFeaturesCompatible(match, request))
   2681    {
   2682        return ZYAN_FALSE;
   2683    }
   2684    if (!ZydisAreMvexFeaturesCompatible(match, request))
   2685    {
   2686        return ZYAN_FALSE;
   2687    }
   2688 
   2689    for (ZyanU8 i = 0; i < request->operand_count; ++i)
   2690    {
   2691        const ZydisEncoderOperand *user_op = &request->operands[i];
   2692        const ZydisOperandDefinition *def_op = &match->operands[i];
   2693        ZYAN_ASSERT(def_op->visibility != ZYDIS_OPERAND_VISIBILITY_HIDDEN);
   2694        ZyanBool is_compatible = ZYAN_FALSE;
   2695        switch (user_op->type)
   2696        {
   2697        case ZYDIS_OPERAND_TYPE_REGISTER:
   2698            is_compatible = ZydisIsRegisterOperandCompatible(match, user_op, def_op);
   2699            break;
   2700        case ZYDIS_OPERAND_TYPE_MEMORY:
   2701            is_compatible = ZydisIsMemoryOperandCompatible(match, user_op, def_op);
   2702            break;
   2703        case ZYDIS_OPERAND_TYPE_POINTER:
   2704            is_compatible = ZydisIsPointerOperandCompatible(match, user_op);
   2705            break;
   2706        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
   2707            is_compatible = ZydisIsImmediateOperandCompabile(match, user_op, def_op);
   2708            break;
   2709        default:
   2710            ZYAN_UNREACHABLE;
   2711        }
   2712 
   2713        if (!is_compatible)
   2714        {
   2715            return ZYAN_FALSE;
   2716        }
   2717    }
   2718 
   2719    ZyanU8 eosz = 0;
   2720    if (match->base_definition->branch_type != ZYDIS_BRANCH_TYPE_NONE)
   2721    {
   2722        switch (request->branch_width)
   2723        {
   2724        case ZYDIS_BRANCH_WIDTH_NONE:
   2725            break;
   2726        case ZYDIS_BRANCH_WIDTH_8:
   2727            if ((!match->has_rel_operand) ||
   2728                (match->base_definition->branch_type != ZYDIS_BRANCH_TYPE_SHORT))
   2729            {
   2730                return ZYAN_FALSE;
   2731            }
   2732            break;
   2733        case ZYDIS_BRANCH_WIDTH_16:
   2734            eosz = 16;
   2735            break;
   2736        case ZYDIS_BRANCH_WIDTH_32:
   2737            eosz = ((match->has_rel_operand) &&
   2738                    (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
   2739                    (match->base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_FORCE64))
   2740                ? 64
   2741                : 32;
   2742            break;
   2743        case ZYDIS_BRANCH_WIDTH_64:
   2744            if (match->has_rel_operand)
   2745            {
   2746                return ZYAN_FALSE;
   2747            }
   2748            eosz = 64;
   2749            break;
   2750        default:
   2751            ZYAN_UNREACHABLE;
   2752        }
   2753    }
   2754    if (eosz)
   2755    {
   2756        if (match->eosz != 0)
   2757        {
   2758            if (match->eosz != eosz)
   2759            {
   2760                return ZYAN_FALSE;
   2761            }
   2762        }
   2763        else
   2764        {
   2765            match->eosz = eosz;
   2766        }
   2767    }
   2768 
   2769    if (!ZydisCheckConstraints(match))
   2770    {
   2771        return ZYAN_FALSE;
   2772    }
   2773 
   2774    return ZYAN_TRUE;
   2775 }
   2776 
   2777 /**
   2778 * Checks if requested set of prefixes is compatible with instruction definition.
   2779 *
   2780 * @param   match A pointer to `ZydisEncoderInstructionMatch` struct.
   2781 *
   2782 * @return  A zyan status code.
   2783 */
   2784 static ZyanBool ZydisArePrefixesCompatible(const ZydisEncoderInstructionMatch *match)
   2785 {
   2786    // Early-exit optimization for when no prefixes are requested at all.
   2787    if (!(match->attributes & ZYDIS_ENCODABLE_PREFIXES))
   2788    {
   2789        return ZYAN_TRUE;
   2790    }
   2791 
   2792    if ((!match->base_definition->accepts_segment) &&
   2793        (match->attributes & ZYDIS_ATTRIB_HAS_SEGMENT))
   2794    {
   2795        return ZYAN_FALSE;
   2796    }
   2797    if (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_LEGACY)
   2798    {
   2799        return !(match->attributes & ZYDIS_ENCODABLE_PREFIXES_NO_SEGMENTS);
   2800    }
   2801 
   2802    const ZydisInstructionDefinitionLEGACY *legacy_def =
   2803        (const ZydisInstructionDefinitionLEGACY *)match->base_definition;
   2804    if ((!legacy_def->accepts_LOCK) &&
   2805        (match->attributes & ZYDIS_ATTRIB_HAS_LOCK))
   2806    {
   2807        return ZYAN_FALSE;
   2808    }
   2809    if ((!legacy_def->accepts_REP) &&
   2810        (match->attributes & ZYDIS_ATTRIB_HAS_REP))
   2811    {
   2812        return ZYAN_FALSE;
   2813    }
   2814    if ((!legacy_def->accepts_REPEREPZ) &&
   2815        (match->attributes & ZYDIS_ATTRIB_HAS_REPE))
   2816    {
   2817        return ZYAN_FALSE;
   2818    }
   2819    if ((!legacy_def->accepts_REPNEREPNZ) &&
   2820        (match->attributes & ZYDIS_ATTRIB_HAS_REPNE))
   2821    {
   2822        return ZYAN_FALSE;
   2823    }
   2824    if ((!legacy_def->accepts_BOUND) &&
   2825        (match->attributes & ZYDIS_ATTRIB_HAS_BND))
   2826    {
   2827        return ZYAN_FALSE;
   2828    }
   2829    if ((!legacy_def->accepts_XACQUIRE) &&
   2830        (match->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE))
   2831    {
   2832        return ZYAN_FALSE;
   2833    }
   2834    if ((!legacy_def->accepts_XRELEASE) &&
   2835        (match->attributes & ZYDIS_ATTRIB_HAS_XRELEASE))
   2836    {
   2837        return ZYAN_FALSE;
   2838    }
   2839    if ((!legacy_def->accepts_branch_hints) &&
   2840        (match->attributes & (ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN |
   2841                              ZYDIS_ATTRIB_HAS_BRANCH_TAKEN)))
   2842    {
   2843        return ZYAN_FALSE;
   2844    }
   2845    if ((!legacy_def->accepts_NOTRACK) &&
   2846        (match->attributes & ZYDIS_ATTRIB_HAS_NOTRACK))
   2847    {
   2848        return ZYAN_FALSE;
   2849    }
   2850    if ((!legacy_def->accepts_hle_without_lock) &&
   2851        (match->attributes & (ZYDIS_ATTRIB_HAS_XACQUIRE |
   2852                              ZYDIS_ATTRIB_HAS_XRELEASE)) &&
   2853        !(match->attributes & ZYDIS_ATTRIB_HAS_LOCK))
   2854    {
   2855        return ZYAN_FALSE;
   2856    }
   2857 
   2858    return ZYAN_TRUE;
   2859 }
   2860 
   2861 /**
   2862 * Returns operand mask containing information about operand count and types in a compressed form.
   2863 *
   2864 * @param   request     A pointer to `ZydisEncoderRequest` struct.
   2865 *
   2866 * @return  Operand mask.
   2867 */
   2868 static ZyanU16 ZydisGetOperandMask(const ZydisEncoderRequest *request)
   2869 {
   2870    ZyanU16 operand_mask = request->operand_count;
   2871    ZyanU8 bit_offset = ZYAN_BITS_TO_REPRESENT(ZYDIS_ENCODER_MAX_OPERANDS);
   2872    for (ZyanU8 i = 0; i < request->operand_count; ++i)
   2873    {
   2874        operand_mask |= (request->operands[i].type - ZYDIS_OPERAND_TYPE_REGISTER) << bit_offset;
   2875        bit_offset += ZYAN_BITS_TO_REPRESENT(
   2876            ZYDIS_OPERAND_TYPE_MAX_VALUE - ZYDIS_OPERAND_TYPE_REGISTER);
   2877    }
   2878 
   2879    return operand_mask;
   2880 }
   2881 
   2882 /**
   2883 * Handles optimization opportunities indicated by `swappable` field in instruction definition
   2884 * structure. See `ZydisEncodableInstruction` for more information.
   2885 *
   2886 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2887 *
   2888 * @return  True if definition has been swapped, false otherwise.
   2889 */
   2890 static ZyanBool ZydisHandleSwappableDefinition(ZydisEncoderInstructionMatch *match)
   2891 {
   2892    if (!match->definition->swappable)
   2893    {
   2894        return ZYAN_FALSE;
   2895    }
   2896 
   2897    // Special case for ISA-wide unique conflict between two `mov` variants
   2898    // mov gpr16_32_64(encoding=opcode), imm(encoding=simm16_32_64,scale_factor=osz)
   2899    // mov gpr16_32_64(encoding=modrm_rm), imm(encoding=simm16_32_32,scale_factor=osz)
   2900    if (match->request->mnemonic == ZYDIS_MNEMONIC_MOV)
   2901    {
   2902        const ZyanU8 imm_size = ZydisGetSignedImmSize(match->request->operands[1].imm.s);
   2903        if ((match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
   2904            (match->eosz == 64) &&
   2905            (imm_size < 64))
   2906        {
   2907            return ZYAN_TRUE;
   2908        }
   2909    }
   2910 
   2911    ZYAN_ASSERT((match->request->operand_count == 2) || (match->request->operand_count == 3));
   2912    const ZyanU8 src_index = (match->request->operand_count == 3) ? 2 : 1;
   2913    const ZyanI8 dest_id = ZydisRegisterGetId(match->request->operands[0].reg.value);
   2914    const ZyanI8 src_id = ZydisRegisterGetId(match->request->operands[src_index].reg.value);
   2915    if ((dest_id <= 7) && (src_id > 7))
   2916    {
   2917        ++match->definition;
   2918        ZydisGetInstructionDefinition(match->definition->encoding,
   2919            match->definition->instruction_reference, &match->base_definition);
   2920        match->operands = ZydisGetOperandDefinitions(match->base_definition);
   2921        return ZYAN_TRUE;
   2922    }
   2923 
   2924    return ZYAN_FALSE;
   2925 }
   2926 
   2927 /**
   2928 * This function attempts to find a matching instruction definition for provided encoder request.
   2929 *
   2930 * @param   request     A pointer to `ZydisEncoderRequest` struct.
   2931 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   2932 *
   2933 * @return  A zyan status code.
   2934 */
   2935 static ZyanStatus ZydisFindMatchingDefinition(const ZydisEncoderRequest *request,
   2936    ZydisEncoderInstructionMatch *match)
   2937 {
   2938    ZYAN_MEMSET(match, 0, sizeof(ZydisEncoderInstructionMatch));
   2939    match->request = request;
   2940    match->attributes = request->prefixes;
   2941 
   2942    const ZydisEncodableInstruction *definition = ZYAN_NULL;
   2943    const ZyanU8 definition_count = ZydisGetEncodableInstructions(request->mnemonic, &definition);
   2944    ZYAN_ASSERT(definition && definition_count);
   2945    const ZydisWidthFlag mode_width = ZydisGetMachineModeWidth(request->machine_mode) >> 4;
   2946    const ZyanBool is_compat =
   2947        (request->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_16) ||
   2948        (request->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_32);
   2949    const ZyanU8 default_asz = ZydisGetAszFromHint(request->address_size_hint);
   2950    const ZyanU8 default_osz = ZydisGetOszFromHint(request->operand_size_hint);
   2951    const ZyanU16 operand_mask = ZydisGetOperandMask(request);
   2952 
   2953    for (ZyanU8 i = 0; i < definition_count; ++i, ++definition)
   2954    {
   2955        if (definition->operand_mask != operand_mask)
   2956        {
   2957            continue;
   2958        }
   2959        const ZydisInstructionDefinition *base_definition = ZYAN_NULL;
   2960        ZydisGetInstructionDefinition(definition->encoding, definition->instruction_reference,
   2961            &base_definition);
   2962        if (!(definition->modes & mode_width))
   2963        {
   2964            continue;
   2965        }
   2966        if ((request->allowed_encodings != ZYDIS_ENCODABLE_ENCODING_DEFAULT) &&
   2967            !(ZydisGetEncodableEncoding(definition->encoding) & request->allowed_encodings))
   2968        {
   2969            continue;
   2970        }
   2971        if (request->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
   2972        {
   2973            if (base_definition->requires_protected_mode)
   2974            {
   2975                continue;
   2976            }
   2977            switch (definition->encoding)
   2978            {
   2979            case ZYDIS_INSTRUCTION_ENCODING_XOP:
   2980            case ZYDIS_INSTRUCTION_ENCODING_VEX:
   2981            case ZYDIS_INSTRUCTION_ENCODING_EVEX:
   2982            case ZYDIS_INSTRUCTION_ENCODING_MVEX:
   2983                continue;
   2984            default:
   2985                break;
   2986            }
   2987        }
   2988        else if ((request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) &&
   2989                 (definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
   2990        {
   2991            continue;
   2992        }
   2993        if (is_compat && base_definition->no_compat_mode)
   2994        {
   2995            continue;
   2996        }
   2997        if ((request->branch_type != ZYDIS_BRANCH_TYPE_NONE) &&
   2998            (request->branch_type != base_definition->branch_type))
   2999        {
   3000            continue;
   3001        }
   3002        if ((base_definition->branch_type == ZYDIS_BRANCH_TYPE_NONE) &&
   3003            (request->branch_width != ZYDIS_BRANCH_WIDTH_NONE))
   3004        {
   3005            continue;
   3006        }
   3007 
   3008        match->definition = definition;
   3009        match->base_definition = base_definition;
   3010        match->operands = ZYAN_NULL;
   3011        match->easz = definition->accepts_hint == ZYDIS_SIZE_HINT_ASZ ? default_asz : 0;
   3012        match->eosz = definition->accepts_hint == ZYDIS_SIZE_HINT_OSZ ? default_osz : 0;
   3013        match->disp_size = match->imm_size = match->cd8_scale = 0;
   3014        match->rex_type = ZYDIS_REX_TYPE_UNKNOWN;
   3015        match->eosz64_forbidden = ZYAN_FALSE;
   3016        match->has_rel_operand = ZYAN_FALSE;
   3017        if ((base_definition->operand_size_map != ZYDIS_OPSIZE_MAP_BYTEOP) &&
   3018            (match->eosz == 8))
   3019        {
   3020            continue;
   3021        }
   3022        if (!ZydisArePrefixesCompatible(match))
   3023        {
   3024            continue;
   3025        }
   3026        if (!ZydisIsDefinitionCompatible(match, request))
   3027        {
   3028            continue;
   3029        }
   3030        if (ZydisHandleSwappableDefinition(match))
   3031        {
   3032            if (definition == match->definition)
   3033            {
   3034                continue;
   3035            }
   3036            ++i;
   3037            definition = match->definition;
   3038            base_definition = match->base_definition;
   3039        }
   3040 
   3041        if (match->easz == 0)
   3042        {
   3043            if (definition->address_sizes & mode_width)
   3044            {
   3045                match->easz = (ZyanU8)(mode_width << 4);
   3046            }
   3047            else if (mode_width == ZYDIS_WIDTH_16)
   3048            {
   3049                match->easz = 32;
   3050            }
   3051            else if (mode_width == ZYDIS_WIDTH_32)
   3052            {
   3053                match->easz = 16;
   3054            }
   3055            else
   3056            {
   3057                match->easz = 32;
   3058            }
   3059            ZYAN_ASSERT(definition->address_sizes & (match->easz >> 4));
   3060        }
   3061        else if (!(definition->address_sizes & (match->easz >> 4)))
   3062        {
   3063            continue;
   3064        }
   3065 
   3066        if (mode_width == ZYDIS_WIDTH_64)
   3067        {
   3068            if (base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_DEFAULT64)
   3069            {
   3070                if (match->eosz == 0)
   3071                {
   3072                    ZYAN_ASSERT(definition->operand_sizes & (ZYDIS_WIDTH_16 | ZYDIS_WIDTH_64));
   3073                    if (definition->operand_sizes & ZYDIS_WIDTH_64)
   3074                    {
   3075                        match->eosz = 64;
   3076                    }
   3077                    else
   3078                    {
   3079                        match->eosz = 16;
   3080                    }
   3081                }
   3082                else if (match->eosz == 32)
   3083                {
   3084                    continue;
   3085                }
   3086            }
   3087            else if (base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_FORCE64)
   3088            {
   3089                if (match->eosz == 0)
   3090                {
   3091                    match->eosz = 64;
   3092                }
   3093                else if (match->eosz != 64)
   3094                {
   3095                    continue;
   3096                }
   3097            }
   3098        }
   3099        if (match->eosz == 0)
   3100        {
   3101            const ZydisWidthFlag default_width = (mode_width == ZYDIS_WIDTH_64)
   3102                ? ZYDIS_WIDTH_32
   3103                : mode_width;
   3104            if (definition->operand_sizes & default_width)
   3105            {
   3106                match->eosz = (ZyanU8)(default_width << 4);
   3107            }
   3108            else if (definition->operand_sizes & ZYDIS_WIDTH_16)
   3109            {
   3110                match->eosz = 16;
   3111            }
   3112            else if (definition->operand_sizes & ZYDIS_WIDTH_32)
   3113            {
   3114                match->eosz = 32;
   3115            }
   3116            else
   3117            {
   3118                match->eosz = 64;
   3119            }
   3120        }
   3121        else if (match->eosz64_forbidden && match->eosz == 64)
   3122        {
   3123            continue;
   3124        }
   3125        else if (!(definition->operand_sizes & (match->eosz >> 4)))
   3126        {
   3127            continue;
   3128        }
   3129 
   3130        return ZYAN_STATUS_SUCCESS;
   3131    }
   3132 
   3133    return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION;
   3134 }
   3135 
   3136 /**
   3137 * Emits unsigned integer value.
   3138 *
   3139 * @param   data    Value to emit.
   3140 * @param   size    Value size in bytes.
   3141 * @param   buffer  A pointer to `ZydisEncoderBuffer` struct.
   3142 *
   3143 * @return  A zyan status code.
   3144 */
   3145 static ZyanStatus ZydisEmitUInt(ZyanU64 data, ZyanU8 size, ZydisEncoderBuffer *buffer)
   3146 {
   3147    ZYAN_ASSERT(size == 1 || size == 2 || size == 4 || size == 8);
   3148 
   3149    const ZyanUSize new_offset = buffer->offset + size;
   3150    if (new_offset > buffer->size)
   3151    {
   3152        return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
   3153    }
   3154 
   3155    // TODO: fix for big-endian systems
   3156    // The size variable is not passed on purpose to allow the compiler
   3157    // to generate better code with a known size at compile time.
   3158    if (size == 1)
   3159    {
   3160        ZYAN_MEMCPY(buffer->buffer + buffer->offset, &data, 1);
   3161    }
   3162    else if (size == 2)
   3163    {
   3164        ZYAN_MEMCPY(buffer->buffer + buffer->offset, &data, 2);
   3165    }
   3166    else if (size == 4)
   3167    {
   3168        ZYAN_MEMCPY(buffer->buffer + buffer->offset, &data, 4);
   3169    }
   3170    else if (size == 8)
   3171    {
   3172        ZYAN_MEMCPY(buffer->buffer + buffer->offset, &data, 8);
   3173    }
   3174    else
   3175    {
   3176        ZYAN_UNREACHABLE;
   3177    }
   3178 
   3179    buffer->offset = new_offset;
   3180    return ZYAN_STATUS_SUCCESS;
   3181 }
   3182 
   3183 /**
   3184 * Emits a single byte.
   3185 *
   3186 * @param   byte    Value to emit.
   3187 * @param   buffer  A pointer to `ZydisEncoderBuffer` struct.
   3188 *
   3189 * @return  A zyan status code.
   3190 */
   3191 static ZyanStatus ZydisEmitByte(ZyanU8 byte, ZydisEncoderBuffer *buffer)
   3192 {
   3193    return ZydisEmitUInt(byte, 1, buffer);
   3194 }
   3195 
   3196 /**
   3197 * Emits legact prefixes.
   3198 *
   3199 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3200 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3201 *
   3202 * @return  A zyan status code.
   3203 */
   3204 static ZyanStatus ZydisEmitLegacyPrefixes(const ZydisEncoderInstruction *instruction,
   3205    ZydisEncoderBuffer *buffer)
   3206 {
   3207    ZyanBool compressed_prefixes = ZYAN_FALSE;
   3208    switch (instruction->encoding)
   3209    {
   3210    case ZYDIS_INSTRUCTION_ENCODING_XOP:
   3211    case ZYDIS_INSTRUCTION_ENCODING_VEX:
   3212    case ZYDIS_INSTRUCTION_ENCODING_EVEX:
   3213    case ZYDIS_INSTRUCTION_ENCODING_MVEX:
   3214        compressed_prefixes = ZYAN_TRUE;
   3215        break;
   3216    default:
   3217        break;
   3218    }
   3219 
   3220    // Group 1
   3221    if (instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK)
   3222    {
   3223        ZYAN_CHECK(ZydisEmitByte(0xF0, buffer));
   3224    }
   3225    if (!compressed_prefixes)
   3226    {
   3227        if (instruction->attributes & (ZYDIS_ATTRIB_HAS_REPNE |
   3228                                       ZYDIS_ATTRIB_HAS_BND |
   3229                                       ZYDIS_ATTRIB_HAS_XACQUIRE))
   3230        {
   3231            ZYAN_CHECK(ZydisEmitByte(0xF2, buffer));
   3232        }
   3233        if (instruction->attributes & (ZYDIS_ATTRIB_HAS_REP |
   3234                                       ZYDIS_ATTRIB_HAS_REPE |
   3235                                       ZYDIS_ATTRIB_HAS_XRELEASE))
   3236        {
   3237            ZYAN_CHECK(ZydisEmitByte(0xF3, buffer));
   3238        }
   3239    }
   3240 
   3241    // Group 2
   3242    if (instruction->attributes & (ZYDIS_ATTRIB_HAS_SEGMENT_CS |
   3243                                   ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN))
   3244    {
   3245        ZYAN_CHECK(ZydisEmitByte(0x2E, buffer));
   3246    }
   3247    if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS)
   3248    {
   3249        ZYAN_CHECK(ZydisEmitByte(0x36, buffer));
   3250    }
   3251    if (instruction->attributes & (ZYDIS_ATTRIB_HAS_SEGMENT_DS |
   3252                                   ZYDIS_ATTRIB_HAS_BRANCH_TAKEN))
   3253    {
   3254        ZYAN_CHECK(ZydisEmitByte(0x3E, buffer));
   3255    }
   3256    if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_ES)
   3257    {
   3258        ZYAN_CHECK(ZydisEmitByte(0x26, buffer));
   3259    }
   3260    if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_FS)
   3261    {
   3262        ZYAN_CHECK(ZydisEmitByte(0x64, buffer));
   3263    }
   3264    if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_GS)
   3265    {
   3266        ZYAN_CHECK(ZydisEmitByte(0x65, buffer));
   3267    }
   3268    if (instruction->attributes & ZYDIS_ATTRIB_HAS_NOTRACK)
   3269    {
   3270        ZYAN_CHECK(ZydisEmitByte(0x3E, buffer));
   3271    }
   3272 
   3273    // Group 3
   3274    if (!compressed_prefixes)
   3275    {
   3276        if (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE)
   3277        {
   3278            ZYAN_CHECK(ZydisEmitByte(0x66, buffer));
   3279        }
   3280    }
   3281 
   3282    // Group 4
   3283    if (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE)
   3284    {
   3285        ZYAN_CHECK(ZydisEmitByte(0x67, buffer));
   3286    }
   3287 
   3288    return ZYAN_STATUS_SUCCESS;
   3289 }
   3290 
   3291 /**
   3292 * Encodes low nibble of `REX` prefix.
   3293 *
   3294 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3295 * @param   high_r          A pointer to `ZyanBool` variable that will be set to true when the
   3296 *                          highest `ModR/M.reg` bit cannot be encoded using `REX` prefix.
   3297 *
   3298 * @return  A zyan status code.
   3299 */
   3300 static ZyanU8 ZydisEncodeRexLowNibble(const ZydisEncoderInstruction *instruction, ZyanBool *high_r)
   3301 {
   3302    if (high_r)
   3303    {
   3304        *high_r = ZYAN_FALSE;
   3305    }
   3306 
   3307    ZyanU8 rex = 0;
   3308    if ((instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM) &&
   3309        (instruction->attributes & ZYDIS_ATTRIB_HAS_SIB))
   3310    {
   3311        if (instruction->base & 0x08)
   3312        {
   3313            rex |= 1;
   3314        }
   3315        if (instruction->index & 0x08)
   3316        {
   3317            rex |= 2;
   3318        }
   3319        if (instruction->reg & 0x08)
   3320        {
   3321            rex |= 4;
   3322        }
   3323        if (high_r && (instruction->reg & 0x10))
   3324        {
   3325            *high_r = ZYAN_TRUE;
   3326        }
   3327    }
   3328    else if (instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM)
   3329    {
   3330        if (instruction->rm & 0x08)
   3331        {
   3332            rex |= 1;
   3333        }
   3334        if (instruction->rm & 0x10)
   3335        {
   3336            rex |= 2;
   3337        }
   3338        if (instruction->reg & 0x08)
   3339        {
   3340            rex |= 4;
   3341        }
   3342        if (high_r && (instruction->reg & 0x10))
   3343        {
   3344            *high_r = ZYAN_TRUE;
   3345        }
   3346    }
   3347    else
   3348    {
   3349        if (instruction->rm & 0x08)
   3350        {
   3351            rex |= 1;
   3352        }
   3353    }
   3354 
   3355    if (instruction->rex_w)
   3356    {
   3357        rex |= 8;
   3358    }
   3359 
   3360    return rex;
   3361 }
   3362 
   3363 /**
   3364 * Emits `REX` prefix.
   3365 *
   3366 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3367 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3368 *
   3369 * @return  A zyan status code.
   3370 */
   3371 static ZyanStatus ZydisEmitRex(const ZydisEncoderInstruction *instruction,
   3372    ZydisEncoderBuffer *buffer)
   3373 {
   3374    const ZyanU8 rex = ZydisEncodeRexLowNibble(instruction, ZYAN_NULL);
   3375    if (rex || (instruction->attributes & ZYDIS_ATTRIB_HAS_REX))
   3376    {
   3377        ZYAN_CHECK(ZydisEmitByte(0x40 | rex, buffer));
   3378    }
   3379 
   3380    return ZYAN_STATUS_SUCCESS;
   3381 }
   3382 
   3383 /**
   3384 * Encodes common parts of `VEX` prefix.
   3385 *
   3386 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3387 * @param   mmmmm           A pointer to `ZyanU8` variable that will receive `VEX.mmmmm`
   3388 * @param   pp              A pointer to `ZyanU8` variable that will receive `VEX.pp`
   3389 * @param   vvvv            A pointer to `ZyanU8` variable that will receive `VEX.vvvv`
   3390 * @param   rex             A pointer to `ZyanU8` variable that will receive 'REX`
   3391 * @param   high_r          A pointer to `ZyanBool` variable that will be set to true when the
   3392 *                          highest `ModR/M.reg` bit cannot be encoded using `REX` prefix.
   3393 */
   3394 static void ZydisEncodeVexCommons(ZydisEncoderInstruction *instruction, ZyanU8 *mmmmm, ZyanU8 *pp,
   3395    ZyanU8 *vvvv, ZyanU8 *rex, ZyanBool *high_r)
   3396 {
   3397    switch (instruction->opcode_map)
   3398    {
   3399    case ZYDIS_OPCODE_MAP_DEFAULT:
   3400    case ZYDIS_OPCODE_MAP_0F:
   3401    case ZYDIS_OPCODE_MAP_0F38:
   3402    case ZYDIS_OPCODE_MAP_0F3A:
   3403    case ZYDIS_OPCODE_MAP_MAP5:
   3404    case ZYDIS_OPCODE_MAP_MAP6:
   3405        *mmmmm = (ZyanU8)instruction->opcode_map;
   3406        break;
   3407    case ZYDIS_OPCODE_MAP_XOP8:
   3408    case ZYDIS_OPCODE_MAP_XOP9:
   3409    case ZYDIS_OPCODE_MAP_XOPA:
   3410        *mmmmm = 8 + ((ZyanU8)instruction->opcode_map - ZYDIS_OPCODE_MAP_XOP8);
   3411        break;
   3412    default:
   3413        ZYAN_UNREACHABLE;
   3414    }
   3415    instruction->opcode_map = ZYDIS_OPCODE_MAP_DEFAULT;
   3416 
   3417    *pp = 0;
   3418    if (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE)
   3419    {
   3420        *pp = 1;
   3421    }
   3422    else if (instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
   3423    {
   3424        *pp = 2;
   3425    }
   3426    else if (instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
   3427    {
   3428        *pp = 3;
   3429    }
   3430 
   3431    *vvvv = ~instruction->vvvv;
   3432    *rex = ZydisEncodeRexLowNibble(instruction, high_r);
   3433 }
   3434 
   3435 /**
   3436 * Emits `XOP` prefix.
   3437 *
   3438 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3439 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3440 *
   3441 * @return  A zyan status code.
   3442 */
   3443 static ZyanStatus ZydisEmitXop(ZydisEncoderInstruction *instruction, ZydisEncoderBuffer *buffer)
   3444 {
   3445    ZyanU8 mmmmm, pp, vvvv, rex;
   3446    ZydisEncodeVexCommons(instruction, &mmmmm, &pp, &vvvv, &rex, ZYAN_NULL);
   3447    ZYAN_ASSERT(instruction->vector_length <= 1);
   3448    const ZyanU8 b1 = (((~rex) & 0x07) << 5) | mmmmm;
   3449    const ZyanU8 b2 = ((rex & 0x08) << 4) | ((vvvv & 0xF) << 3) | (instruction->vector_length << 2) | pp;
   3450    ZYAN_CHECK(ZydisEmitByte(0x8F, buffer));
   3451    ZYAN_CHECK(ZydisEmitByte(b1, buffer));
   3452    ZYAN_CHECK(ZydisEmitByte(b2, buffer));
   3453    return ZYAN_STATUS_SUCCESS;
   3454 }
   3455 
   3456 /**
   3457 * Emits `VEX` prefix.
   3458 *
   3459 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3460 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3461 *
   3462 * @return  A zyan status code.
   3463 */
   3464 static ZyanStatus ZydisEmitVex(ZydisEncoderInstruction *instruction, ZydisEncoderBuffer *buffer)
   3465 {
   3466    ZyanU8 mmmmm, pp, vvvv, rex;
   3467    ZydisEncodeVexCommons(instruction, &mmmmm, &pp, &vvvv, &rex, ZYAN_NULL);
   3468    ZYAN_ASSERT(instruction->vector_length <= 1);
   3469    if (mmmmm != 1 || (rex & 0x0B))
   3470    {
   3471        const ZyanU8 b1 = (((~rex) & 0x07) << 5) | mmmmm;
   3472        const ZyanU8 b2 = ((rex & 0x08) << 4) |
   3473                          ((vvvv & 0xF) << 3) |
   3474                          (instruction->vector_length << 2) |
   3475                          pp;
   3476        ZYAN_CHECK(ZydisEmitByte(0xC4, buffer));
   3477        ZYAN_CHECK(ZydisEmitByte(b1, buffer));
   3478        ZYAN_CHECK(ZydisEmitByte(b2, buffer));
   3479    }
   3480    else
   3481    {
   3482        const ZyanU8 b1 = (((~rex) & 0x04) << 5) |
   3483                          ((vvvv & 0xF) << 3) |
   3484                          (instruction->vector_length << 2) |
   3485                          pp;
   3486        ZYAN_CHECK(ZydisEmitByte(0xC5, buffer));
   3487        ZYAN_CHECK(ZydisEmitByte(b1, buffer));
   3488    }
   3489 
   3490    return ZYAN_STATUS_SUCCESS;
   3491 }
   3492 
   3493 /**
   3494 * Encodes common parts of `EVEX` prefix.
   3495 *
   3496 * @param   instruction A pointer to `ZydisEncoderInstruction` struct.
   3497 * @param   p0          A pointer to `ZyanU8` variable that will receive 2nd byte of `EVEX` prefix.
   3498 * @param   p1          A pointer to `ZyanU8` variable that will receive 3rd byte of `EVEX` prefix.
   3499 * @param   vvvvv       A pointer to `ZyanU8` variable that will receive `EVEX.vvvvv`.
   3500 */
   3501 static void ZydisEncodeEvexCommons(ZydisEncoderInstruction *instruction, ZyanU8 *p0, ZyanU8 *p1,
   3502    ZyanU8 *vvvvv)
   3503 {
   3504    ZyanBool high_r;
   3505    ZyanU8 mmmmm, pp, rex;
   3506    ZydisEncodeVexCommons(instruction, &mmmmm, &pp, vvvvv, &rex, &high_r);
   3507    *p0 = (((~rex) & 0x07) << 5) | mmmmm;
   3508    if (!high_r)
   3509    {
   3510        *p0 |= 0x10;
   3511    }
   3512    *p1 = ((rex & 0x08) << 4) | ((*vvvvv & 0x0F) << 3) | 0x04 | pp;
   3513 }
   3514 
   3515 /**
   3516 * Emits `EVEX` prefix.
   3517 *
   3518 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3519 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3520 *
   3521 * @return  A zyan status code.
   3522 */
   3523 static ZyanStatus ZydisEmitEvex(ZydisEncoderInstruction *instruction, ZydisEncoderBuffer *buffer)
   3524 {
   3525    ZyanU8 p0, p1, vvvvv;
   3526    ZydisEncodeEvexCommons(instruction, &p0, &p1, &vvvvv);
   3527    ZyanU8 p2 = (instruction->vector_length << 5) | ((vvvvv & 0x10) >> 1) | instruction->mask;
   3528    if (instruction->zeroing)
   3529    {
   3530        p2 |= 0x80;
   3531    }
   3532    if (instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX_B)
   3533    {
   3534        p2 |= 0x10;
   3535    }
   3536    if (instruction->index & 0x10)
   3537    {
   3538        p2 &= 0xF7;
   3539    }
   3540 
   3541    ZYAN_CHECK(ZydisEmitByte(0x62, buffer));
   3542    ZYAN_CHECK(ZydisEmitByte(p0, buffer));
   3543    ZYAN_CHECK(ZydisEmitByte(p1, buffer));
   3544    ZYAN_CHECK(ZydisEmitByte(p2, buffer));
   3545    return ZYAN_STATUS_SUCCESS;
   3546 }
   3547 
   3548 /**
   3549 * Emits `MVEX` prefix.
   3550 *
   3551 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3552 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3553 *
   3554 * @return  A zyan status code.
   3555 */
   3556 static ZyanStatus ZydisEmitMvex(ZydisEncoderInstruction *instruction, ZydisEncoderBuffer *buffer)
   3557 {
   3558    ZyanU8 p0, p1, vvvvv;
   3559    ZydisEncodeEvexCommons(instruction, &p0, &p1, &vvvvv);
   3560    ZyanU8 p2 = (instruction->sss << 4) | ((vvvvv & 0x10) >> 1) | instruction->mask;
   3561    if (instruction->eviction_hint)
   3562    {
   3563        p2 |= 0x80;
   3564    }
   3565    if (instruction->index & 0x10)
   3566    {
   3567        p2 &= 0xF7;
   3568    }
   3569 
   3570    ZYAN_CHECK(ZydisEmitByte(0x62, buffer));
   3571    ZYAN_CHECK(ZydisEmitByte(p0, buffer));
   3572    ZYAN_CHECK(ZydisEmitByte(p1 & 0xFB, buffer));
   3573    ZYAN_CHECK(ZydisEmitByte(p2, buffer));
   3574    return ZYAN_STATUS_SUCCESS;
   3575 }
   3576 
   3577 /**
   3578 * Emits instruction as stream of bytes.
   3579 *
   3580 * @param   instruction     A pointer to `ZydisEncoderInstruction` struct.
   3581 * @param   buffer          A pointer to `ZydisEncoderBuffer` struct.
   3582 *
   3583 * @return  A zyan status code.
   3584 */
   3585 static ZyanStatus ZydisEmitInstruction(ZydisEncoderInstruction *instruction,
   3586    ZydisEncoderBuffer *buffer)
   3587 {
   3588    ZYAN_CHECK(ZydisEmitLegacyPrefixes(instruction, buffer));
   3589 
   3590    switch (instruction->encoding)
   3591    {
   3592    case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
   3593    case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
   3594        ZYAN_CHECK(ZydisEmitRex(instruction, buffer));
   3595        break;
   3596    case ZYDIS_INSTRUCTION_ENCODING_XOP:
   3597        ZYAN_CHECK(ZydisEmitXop(instruction, buffer));
   3598        break;
   3599    case ZYDIS_INSTRUCTION_ENCODING_VEX:
   3600        ZYAN_CHECK(ZydisEmitVex(instruction, buffer));
   3601        break;
   3602    case ZYDIS_INSTRUCTION_ENCODING_EVEX:
   3603        ZYAN_CHECK(ZydisEmitEvex(instruction, buffer));
   3604        break;
   3605    case ZYDIS_INSTRUCTION_ENCODING_MVEX:
   3606        ZYAN_CHECK(ZydisEmitMvex(instruction, buffer));
   3607        break;
   3608    default:
   3609        ZYAN_UNREACHABLE;
   3610    }
   3611 
   3612    switch (instruction->opcode_map)
   3613    {
   3614    case ZYDIS_OPCODE_MAP_DEFAULT:
   3615        break;
   3616    case ZYDIS_OPCODE_MAP_0F:
   3617        ZYAN_CHECK(ZydisEmitByte(0x0F, buffer));
   3618        break;
   3619    case ZYDIS_OPCODE_MAP_0F38:
   3620        ZYAN_CHECK(ZydisEmitByte(0x0F, buffer));
   3621        ZYAN_CHECK(ZydisEmitByte(0x38, buffer));
   3622        break;
   3623    case ZYDIS_OPCODE_MAP_0F3A:
   3624        ZYAN_CHECK(ZydisEmitByte(0x0F, buffer));
   3625        ZYAN_CHECK(ZydisEmitByte(0x3A, buffer));
   3626        break;
   3627    case ZYDIS_OPCODE_MAP_0F0F:
   3628        ZYAN_CHECK(ZydisEmitByte(0x0F, buffer));
   3629        ZYAN_CHECK(ZydisEmitByte(0x0F, buffer));
   3630        break;
   3631    default:
   3632        ZYAN_UNREACHABLE;
   3633    }
   3634    if (instruction->encoding != ZYDIS_INSTRUCTION_ENCODING_3DNOW)
   3635    {
   3636        ZYAN_CHECK(ZydisEmitByte(instruction->opcode, buffer));
   3637    }
   3638 
   3639    if (instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM)
   3640    {
   3641        const ZyanU8 modrm = (instruction->mod << 6) |
   3642                             ((instruction->reg & 7) << 3) |
   3643                             (instruction->rm & 7);
   3644        ZYAN_CHECK(ZydisEmitByte(modrm, buffer));
   3645    }
   3646    if (instruction->attributes & ZYDIS_ATTRIB_HAS_SIB)
   3647    {
   3648        const ZyanU8 sib = (instruction->scale << 6) |
   3649                           ((instruction->index & 7) << 3) |
   3650                           (instruction->base & 7);
   3651        ZYAN_CHECK(ZydisEmitByte(sib, buffer));
   3652    }
   3653    if (instruction->disp_size)
   3654    {
   3655        ZYAN_CHECK(ZydisEmitUInt(instruction->disp, instruction->disp_size / 8, buffer));
   3656    }
   3657    if (instruction->imm_size)
   3658    {
   3659        ZYAN_CHECK(ZydisEmitUInt(instruction->imm, instruction->imm_size / 8, buffer));
   3660    }
   3661    if (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
   3662    {
   3663        ZYAN_CHECK(ZydisEmitByte(instruction->opcode, buffer));
   3664    }
   3665 
   3666    return ZYAN_STATUS_SUCCESS;
   3667 }
   3668 
   3669 /**
   3670 * Encodes register operand as fields inside `ZydisEncoderInstruction` structure.
   3671 *
   3672 * @param   user_op     Validated operand definition from `ZydisEncoderRequest` structure.
   3673 * @param   def_op      Decoder's operand definition from instruction definition.
   3674 * @param   instruction A pointer to `ZydisEncoderInstruction` struct.
   3675 */
   3676 static void ZydisBuildRegisterOperand(const ZydisEncoderOperand *user_op,
   3677    const ZydisOperandDefinition *def_op, ZydisEncoderInstruction *instruction)
   3678 {
   3679    if (def_op->type == ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG)
   3680    {
   3681        return;
   3682    }
   3683 
   3684    ZyanU8 reg_id = 0;
   3685    if (ZydisRegisterGetClass(user_op->reg.value) != ZYDIS_REGCLASS_GPR8)
   3686    {
   3687        reg_id = (ZyanU8)ZydisRegisterGetId(user_op->reg.value);
   3688    }
   3689    else
   3690    {
   3691        static const ZyanU8 reg8_lookup[] = {
   3692            0, 1, 2, 3,                     // AL, CL, DL, BL
   3693            4, 5, 6, 7,                     // AH, CH, DH, BH
   3694            4, 5, 6, 7,                     // SPL, BPL, SIL, DIL
   3695            8, 9, 10, 11, 12, 13, 14, 15,   // R8B-R15B
   3696        };
   3697        ZYAN_ASSERT(
   3698            ((ZyanUSize)user_op->reg.value - ZYDIS_REGISTER_AL) < ZYAN_ARRAY_LENGTH(reg8_lookup));
   3699        reg_id = reg8_lookup[user_op->reg.value - ZYDIS_REGISTER_AL];
   3700        if (user_op->reg.value >= ZYDIS_REGISTER_SPL && user_op->reg.value <= ZYDIS_REGISTER_DIL)
   3701        {
   3702            instruction->attributes |= ZYDIS_ATTRIB_HAS_REX;
   3703        }
   3704    }
   3705 
   3706    switch (def_op->op.encoding)
   3707    {
   3708    case ZYDIS_OPERAND_ENCODING_MODRM_REG:
   3709        instruction->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
   3710        instruction->reg = reg_id;
   3711        break;
   3712    case ZYDIS_OPERAND_ENCODING_MODRM_RM:
   3713        instruction->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
   3714        instruction->rm = reg_id;
   3715        break;
   3716    case ZYDIS_OPERAND_ENCODING_OPCODE:
   3717        instruction->opcode += reg_id & 7;
   3718        instruction->rm = reg_id;
   3719        break;
   3720    case ZYDIS_OPERAND_ENCODING_NDSNDD:
   3721        instruction->vvvv = reg_id;
   3722        break;
   3723    case ZYDIS_OPERAND_ENCODING_IS4:
   3724        instruction->imm_size = 8;
   3725        instruction->imm = reg_id << 4;
   3726        break;
   3727    case ZYDIS_OPERAND_ENCODING_MASK:
   3728        instruction->mask = reg_id;
   3729        break;
   3730    default:
   3731        ZYAN_UNREACHABLE;
   3732    }
   3733 }
   3734 
   3735 /**
   3736 * Encodes memory operand as fields inside `ZydisEncoderInstruction` structure.
   3737 *
   3738 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   3739 * @param   user_op     Decoder's operand definition from instruction definition.
   3740 * @param   instruction A pointer to `ZydisEncoderInstruction` struct.
   3741 */
   3742 static void ZydisBuildMemoryOperand(ZydisEncoderInstructionMatch *match,
   3743    const ZydisEncoderOperand *user_op, ZydisEncoderInstruction *instruction)
   3744 {
   3745    instruction->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
   3746    instruction->disp = (ZyanU64)user_op->mem.displacement;
   3747    if (match->easz == 16)
   3748    {
   3749        const ZyanI8 rm = ZydisGetRm16(user_op->mem.base, user_op->mem.index);
   3750        if (rm != -1)
   3751        {
   3752            instruction->rm = (ZyanU8)rm;
   3753            instruction->disp_size = match->disp_size;
   3754            switch (instruction->disp_size)
   3755            {
   3756            case 0:
   3757                if (rm == 6)
   3758                {
   3759                    instruction->disp_size = 8;
   3760                    instruction->mod = 1;
   3761                }
   3762                break;
   3763            case 8:
   3764                instruction->mod = 1;
   3765                break;
   3766            case 16:
   3767                instruction->mod = 2;
   3768                break;
   3769            default:
   3770                ZYAN_UNREACHABLE;
   3771            }
   3772        }
   3773        else
   3774        {
   3775            instruction->rm = 6;
   3776            instruction->disp_size = 16;
   3777        }
   3778        return;
   3779    }
   3780 
   3781    if (user_op->mem.index == ZYDIS_REGISTER_NONE)
   3782    {
   3783        if (user_op->mem.base == ZYDIS_REGISTER_NONE)
   3784        {
   3785            if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
   3786            {
   3787                instruction->rm = 4;
   3788                instruction->attributes |= ZYDIS_ATTRIB_HAS_SIB;
   3789                instruction->base = 5;
   3790                instruction->index = 4;
   3791            }
   3792            else
   3793            {
   3794                instruction->rm = 5;
   3795            }
   3796            instruction->disp_size = 32;
   3797            return;
   3798        }
   3799        else if ((user_op->mem.base == ZYDIS_REGISTER_RIP) ||
   3800                 (user_op->mem.base == ZYDIS_REGISTER_EIP))
   3801        {
   3802            instruction->rm = 5;
   3803            instruction->disp_size = 32;
   3804            return;
   3805        }
   3806    }
   3807 
   3808    const ZyanU8 reg_base_id = (ZyanU8)ZydisRegisterGetId(user_op->mem.base);
   3809    const ZyanU8 reg_index_id = (ZyanU8)ZydisRegisterGetId(user_op->mem.index);
   3810    instruction->disp_size = match->disp_size;
   3811    switch (instruction->disp_size)
   3812    {
   3813    case 0:
   3814        if (reg_base_id == 5 || reg_base_id == 13)
   3815        {
   3816            instruction->disp_size = 8;
   3817            instruction->disp = 0;
   3818            instruction->mod = 1;
   3819        }
   3820        break;
   3821    case 8:
   3822        instruction->mod = 1;
   3823        break;
   3824    case 16:
   3825        instruction->disp_size = 32;
   3826        ZYAN_FALLTHROUGH;
   3827    case 32:
   3828        instruction->mod = 2;
   3829        break;
   3830    default:
   3831        ZYAN_UNREACHABLE;
   3832    }
   3833    if ((user_op->mem.index == ZYDIS_REGISTER_NONE) &&
   3834        (reg_base_id != 4) &&
   3835        (reg_base_id != 12) &&
   3836        ((match->definition->modrm & 7) != 4))
   3837    {
   3838        instruction->rm = reg_base_id;
   3839        return;
   3840    }
   3841    instruction->rm = 4;
   3842    instruction->attributes |= ZYDIS_ATTRIB_HAS_SIB;
   3843    if (reg_base_id != 0xFF)
   3844    {
   3845        instruction->base = reg_base_id;
   3846    }
   3847    else
   3848    {
   3849        instruction->base = 5;
   3850        instruction->mod = 0;
   3851        instruction->disp_size = 32;
   3852    }
   3853    if (reg_index_id != 0xFF)
   3854    {
   3855        instruction->index = reg_index_id;
   3856    }
   3857    else
   3858    {
   3859        instruction->index = 4;
   3860    }
   3861    switch (user_op->mem.scale)
   3862    {
   3863    case 0:
   3864    case 1:
   3865        break;
   3866    case 2:
   3867        instruction->scale = 1;
   3868        break;
   3869    case 4:
   3870        instruction->scale = 2;
   3871        break;
   3872    case 8:
   3873        instruction->scale = 3;
   3874        break;
   3875    default:
   3876        ZYAN_UNREACHABLE;
   3877    }
   3878 }
   3879 
   3880 /**
   3881 * Encodes instruction as emittable `ZydisEncoderInstruction` struct.
   3882 *
   3883 * @param   match       A pointer to `ZydisEncoderInstructionMatch` struct.
   3884 * @param   instruction A pointer to `ZydisEncoderInstruction` struct.
   3885 *
   3886 * @return  A zyan status code.
   3887 */
   3888 static ZyanStatus ZydisBuildInstruction(ZydisEncoderInstructionMatch *match,
   3889    ZydisEncoderInstruction *instruction)
   3890 {
   3891    ZYAN_MEMSET(instruction, 0, sizeof(ZydisEncoderInstruction));
   3892    instruction->attributes = match->attributes;
   3893    instruction->encoding = match->definition->encoding;
   3894    instruction->opcode_map = match->definition->opcode_map;
   3895    instruction->opcode = match->definition->opcode;
   3896    instruction->rex_w = match->definition->rex_w;
   3897    instruction->mod = (match->definition->modrm >> 6) & 3;
   3898    instruction->reg = (match->definition->modrm >> 3) & 7;
   3899    instruction->rm = match->definition->modrm & 7;
   3900    if (match->definition->modrm)
   3901    {
   3902        instruction->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
   3903    }
   3904 
   3905    switch (match->definition->vector_length)
   3906    {
   3907    case ZYDIS_VECTOR_LENGTH_INVALID:
   3908    case ZYDIS_VECTOR_LENGTH_128:
   3909        instruction->vector_length = 0;
   3910        break;
   3911    case ZYDIS_VECTOR_LENGTH_256:
   3912        instruction->vector_length = 1;
   3913        break;
   3914    case ZYDIS_VECTOR_LENGTH_512:
   3915        instruction->vector_length = 2;
   3916        break;
   3917    default:
   3918        ZYAN_UNREACHABLE;
   3919    }
   3920 
   3921    if (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX)
   3922    {
   3923        const ZydisInstructionDefinitionEVEX *evex_def =
   3924            (const ZydisInstructionDefinitionEVEX *)match->base_definition;
   3925        if (evex_def->mask_override != ZYDIS_MASK_OVERRIDE_ZEROING)
   3926        {
   3927            instruction->zeroing = match->request->evex.zeroing_mask;
   3928        }
   3929        if ((match->request->evex.sae) ||
   3930            (match->request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID))
   3931        {
   3932            instruction->attributes |= ZYDIS_ATTRIB_HAS_EVEX_B;
   3933        }
   3934        if (match->request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID)
   3935        {
   3936            instruction->attributes |= ZYDIS_ATTRIB_HAS_EVEX_B;
   3937            switch (match->request->evex.rounding)
   3938            {
   3939            case ZYDIS_ROUNDING_MODE_RN:
   3940                instruction->vector_length = 0;
   3941                break;
   3942            case ZYDIS_ROUNDING_MODE_RD:
   3943                instruction->vector_length = 1;
   3944                break;
   3945            case ZYDIS_ROUNDING_MODE_RU:
   3946                instruction->vector_length = 2;
   3947                break;
   3948            case ZYDIS_ROUNDING_MODE_RZ:
   3949                instruction->vector_length = 3;
   3950                break;
   3951            default:
   3952                ZYAN_UNREACHABLE;
   3953            }
   3954        }
   3955    }
   3956    else if (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
   3957    {
   3958        instruction->sss |= ZydisEncodeMvexBroadcastMode(match->request->mvex.broadcast);
   3959        instruction->sss |= ZydisEncodeMvexConversionMode(match->request->mvex.conversion);
   3960 
   3961        switch (match->request->mvex.rounding)
   3962        {
   3963        case ZYDIS_ROUNDING_MODE_INVALID:
   3964            break;
   3965        case ZYDIS_ROUNDING_MODE_RN:
   3966        case ZYDIS_ROUNDING_MODE_RD:
   3967        case ZYDIS_ROUNDING_MODE_RU:
   3968        case ZYDIS_ROUNDING_MODE_RZ:
   3969            instruction->sss |= match->request->mvex.rounding - ZYDIS_ROUNDING_MODE_RN;
   3970            break;
   3971        default:
   3972            ZYAN_UNREACHABLE;
   3973        }
   3974 
   3975        switch (match->request->mvex.swizzle)
   3976        {
   3977        case ZYDIS_SWIZZLE_MODE_INVALID:
   3978            break;
   3979        case ZYDIS_SWIZZLE_MODE_DCBA:
   3980        case ZYDIS_SWIZZLE_MODE_CDAB:
   3981        case ZYDIS_SWIZZLE_MODE_BADC:
   3982        case ZYDIS_SWIZZLE_MODE_DACB:
   3983        case ZYDIS_SWIZZLE_MODE_AAAA:
   3984        case ZYDIS_SWIZZLE_MODE_BBBB:
   3985        case ZYDIS_SWIZZLE_MODE_CCCC:
   3986        case ZYDIS_SWIZZLE_MODE_DDDD:
   3987            instruction->sss |= match->request->mvex.swizzle - ZYDIS_SWIZZLE_MODE_DCBA;
   3988            break;
   3989        default:
   3990            ZYAN_UNREACHABLE;
   3991        }
   3992 
   3993        if ((match->request->mvex.sae) ||
   3994            (match->request->mvex.eviction_hint) ||
   3995            (match->request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
   3996        {
   3997            instruction->eviction_hint = ZYAN_TRUE;
   3998        }
   3999        if (match->request->mvex.sae)
   4000        {
   4001            instruction->sss |= 4;
   4002        }
   4003 
   4004        // Following instructions violate general `MVEX.EH` handling rules. In all other cases this
   4005        // bit is used either as eviction hint (memory operands present) or to encode MVEX-specific
   4006        // functionality (register forms). Instructions listed below use `MVEX.EH` to identify
   4007        // different instructions with memory operands and don't treat it as eviction hint.
   4008        switch (match->request->mnemonic)
   4009        {
   4010        case ZYDIS_MNEMONIC_VMOVNRAPD:
   4011        case ZYDIS_MNEMONIC_VMOVNRAPS:
   4012            instruction->eviction_hint = ZYAN_FALSE;
   4013            break;
   4014        case ZYDIS_MNEMONIC_VMOVNRNGOAPD:
   4015        case ZYDIS_MNEMONIC_VMOVNRNGOAPS:
   4016            instruction->eviction_hint = ZYAN_TRUE;
   4017            break;
   4018        default:
   4019            break;
   4020        }
   4021    }
   4022 
   4023    switch (match->definition->mandatory_prefix)
   4024    {
   4025    case ZYDIS_MANDATORY_PREFIX_NONE:
   4026        break;
   4027    case ZYDIS_MANDATORY_PREFIX_66:
   4028        instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
   4029        break;
   4030    case ZYDIS_MANDATORY_PREFIX_F2:
   4031        instruction->attributes |= ZYDIS_ATTRIB_HAS_REPNE;
   4032        break;
   4033    case ZYDIS_MANDATORY_PREFIX_F3:
   4034        instruction->attributes |= ZYDIS_ATTRIB_HAS_REP;
   4035        break;
   4036    default:
   4037        ZYAN_UNREACHABLE;
   4038    }
   4039 
   4040    const ZyanU8 mode_width = ZydisGetMachineModeWidth(match->request->machine_mode);
   4041    if (match->easz != mode_width)
   4042    {
   4043        instruction->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE;
   4044    }
   4045    if ((match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
   4046        (match->base_definition->operand_size_map != ZYDIS_OPSIZE_MAP_FORCE64))
   4047    {
   4048        switch (match->eosz)
   4049        {
   4050        case 16:
   4051            instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
   4052            break;
   4053        case 32:
   4054            break;
   4055        case 64:
   4056            instruction->rex_w =
   4057                match->base_definition->operand_size_map != ZYDIS_OPSIZE_MAP_DEFAULT64;
   4058            break;
   4059        default:
   4060            ZYAN_UNREACHABLE;
   4061        }
   4062    }
   4063    else
   4064    {
   4065        if (match->eosz != mode_width)
   4066        {
   4067            instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
   4068        }
   4069    }
   4070 
   4071    for (ZyanU8 i = 0; i < match->request->operand_count; ++i)
   4072    {
   4073        const ZydisEncoderOperand *user_op = &match->request->operands[i];
   4074        const ZydisOperandDefinition *def_op = &match->operands[i];
   4075        switch (user_op->type)
   4076        {
   4077        case ZYDIS_OPERAND_TYPE_REGISTER:
   4078            ZydisBuildRegisterOperand(user_op, def_op, instruction);
   4079            break;
   4080        case ZYDIS_OPERAND_TYPE_MEMORY:
   4081            if (def_op->type != ZYDIS_SEMANTIC_OPTYPE_MOFFS)
   4082            {
   4083                ZydisBuildMemoryOperand(match, user_op, instruction);
   4084                if ((match->cd8_scale) &&
   4085                    (instruction->disp_size == 8))
   4086                {
   4087                    instruction->disp >>= match->cd8_scale;
   4088                }
   4089            }
   4090            else
   4091            {
   4092                instruction->disp_size = match->disp_size;
   4093                instruction->disp = (ZyanU64)user_op->mem.displacement;
   4094            }
   4095            break;
   4096        case ZYDIS_OPERAND_TYPE_POINTER:
   4097            instruction->disp_size = match->disp_size;
   4098            instruction->disp = user_op->ptr.offset;
   4099            instruction->imm_size = match->imm_size;
   4100            instruction->imm = user_op->ptr.segment;
   4101            break;
   4102        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
   4103            if (def_op->type == ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1)
   4104            {
   4105                break;
   4106            }
   4107            if (def_op->op.encoding != ZYDIS_OPERAND_ENCODING_IS4)
   4108            {
   4109                if (instruction->imm_size)
   4110                {
   4111                    ZYAN_ASSERT(instruction->disp_size == 0);
   4112                    instruction->disp_size = match->disp_size;
   4113                    instruction->disp = instruction->imm;
   4114                }
   4115                instruction->imm_size = match->imm_size;
   4116                instruction->imm = user_op->imm.u;
   4117            }
   4118            else
   4119            {
   4120                ZYAN_ASSERT(instruction->imm_size == 8);
   4121                instruction->imm |= user_op->imm.u;
   4122            }
   4123            break;
   4124        default:
   4125            ZYAN_UNREACHABLE;
   4126        }
   4127    }
   4128 
   4129    return ZYAN_STATUS_SUCCESS;
   4130 }
   4131 
   4132 /**
   4133 * Performs a set of sanity checks that must be satisfied for every valid encoder request.
   4134 *
   4135 * @param   request A pointer to `ZydisEncoderRequest` struct.
   4136 *
   4137 * @return  A zyan status code.
   4138 */
   4139 static ZyanStatus ZydisEncoderCheckRequestSanity(const ZydisEncoderRequest *request)
   4140 {
   4141    if (((ZyanUSize)request->machine_mode > ZYDIS_MACHINE_MODE_MAX_VALUE) ||
   4142        ((ZyanUSize)request->allowed_encodings > ZYDIS_ENCODABLE_ENCODING_MAX_VALUE) ||
   4143        ((ZyanUSize)request->mnemonic > ZYDIS_MNEMONIC_MAX_VALUE) ||
   4144        ((ZyanUSize)request->branch_type > ZYDIS_BRANCH_TYPE_MAX_VALUE) ||
   4145        ((ZyanUSize)request->branch_width > ZYDIS_BRANCH_WIDTH_MAX_VALUE) ||
   4146        ((ZyanUSize)request->address_size_hint > ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE) ||
   4147        ((ZyanUSize)request->operand_size_hint > ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE) ||
   4148        ((ZyanUSize)request->evex.broadcast > ZYDIS_BROADCAST_MODE_MAX_VALUE) ||
   4149        ((ZyanUSize)request->evex.rounding > ZYDIS_ROUNDING_MODE_MAX_VALUE) ||
   4150        ((ZyanUSize)request->mvex.broadcast > ZYDIS_BROADCAST_MODE_MAX_VALUE) ||
   4151        ((ZyanUSize)request->mvex.conversion > ZYDIS_CONVERSION_MODE_MAX_VALUE) ||
   4152        ((ZyanUSize)request->mvex.rounding > ZYDIS_ROUNDING_MODE_MAX_VALUE) ||
   4153        ((ZyanUSize)request->mvex.swizzle > ZYDIS_SWIZZLE_MODE_MAX_VALUE) ||
   4154        (request->operand_count > ZYDIS_ENCODER_MAX_OPERANDS) ||
   4155        (request->mnemonic == ZYDIS_MNEMONIC_INVALID) ||
   4156        (request->prefixes & ~ZYDIS_ENCODABLE_PREFIXES))
   4157    {
   4158        return ZYAN_STATUS_INVALID_ARGUMENT;
   4159    }
   4160 
   4161    if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT)
   4162    {
   4163        if ((request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
   4164            (request->prefixes & ZYDIS_LEGACY_SEGMENTS))
   4165        {
   4166            return ZYAN_STATUS_INVALID_ARGUMENT;
   4167        }
   4168 
   4169        ZyanU8 seg_override_count = 0;
   4170        if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_CS)
   4171        {
   4172            ++seg_override_count;
   4173        }
   4174        if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_SS)
   4175        {
   4176            ++seg_override_count;
   4177        }
   4178        if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_DS)
   4179        {
   4180            ++seg_override_count;
   4181        }
   4182        if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_ES)
   4183        {
   4184            ++seg_override_count;
   4185        }
   4186        if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_FS)
   4187        {
   4188            ++seg_override_count;
   4189        }
   4190        if (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_GS)
   4191        {
   4192            ++seg_override_count;
   4193        }
   4194        if (seg_override_count != 1)
   4195        {
   4196            return ZYAN_STATUS_INVALID_ARGUMENT;
   4197        }
   4198    }
   4199    ZyanU8 rep_family_count = 0;
   4200    if (request->prefixes & ZYDIS_ATTRIB_HAS_REP)
   4201    {
   4202        ++rep_family_count;
   4203    }
   4204    if (request->prefixes & ZYDIS_ATTRIB_HAS_REPE)
   4205    {
   4206        ++rep_family_count;
   4207    }
   4208    if (request->prefixes & ZYDIS_ATTRIB_HAS_REPNE)
   4209    {
   4210        ++rep_family_count;
   4211    }
   4212    if (rep_family_count > 1)
   4213    {
   4214        return ZYAN_STATUS_INVALID_ARGUMENT;
   4215    }
   4216    if ((request->prefixes & ZYDIS_ATTRIB_HAS_XACQUIRE) &&
   4217        (request->prefixes & ZYDIS_ATTRIB_HAS_XRELEASE))
   4218    {
   4219        return ZYAN_STATUS_INVALID_ARGUMENT;
   4220    }
   4221    if ((request->prefixes & ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN) &&
   4222        (request->prefixes & ZYDIS_ATTRIB_HAS_BRANCH_TAKEN))
   4223    {
   4224        return ZYAN_STATUS_INVALID_ARGUMENT;
   4225    }
   4226    if ((request->prefixes & ZYDIS_ATTRIB_HAS_NOTRACK) &&
   4227        (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT))
   4228    {
   4229        return ZYAN_STATUS_INVALID_ARGUMENT;
   4230    }
   4231 
   4232    static const ZyanBool branch_lookup
   4233        [ZYDIS_BRANCH_WIDTH_MAX_VALUE + 1][ZYDIS_BRANCH_TYPE_MAX_VALUE + 1] =
   4234    {
   4235        /* NONE */ { ZYAN_TRUE,  ZYAN_TRUE,  ZYAN_TRUE,  ZYAN_TRUE  },
   4236        /* 8    */ { ZYAN_TRUE,  ZYAN_TRUE,  ZYAN_FALSE, ZYAN_FALSE },
   4237        /* 16   */ { ZYAN_TRUE,  ZYAN_FALSE, ZYAN_TRUE,  ZYAN_TRUE  },
   4238        /* 32   */ { ZYAN_TRUE,  ZYAN_FALSE, ZYAN_TRUE,  ZYAN_TRUE  },
   4239        /* 64   */ { ZYAN_TRUE,  ZYAN_FALSE, ZYAN_TRUE,  ZYAN_TRUE  },
   4240    };
   4241    if (!branch_lookup[request->branch_width][request->branch_type])
   4242    {
   4243        return ZYAN_STATUS_INVALID_ARGUMENT;
   4244    }
   4245 
   4246    if (request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
   4247    {
   4248        if (request->address_size_hint == ZYDIS_ADDRESS_SIZE_HINT_16)
   4249        {
   4250            return ZYAN_STATUS_INVALID_ARGUMENT;
   4251        }
   4252    }
   4253    else
   4254    {
   4255        if ((request->branch_width == ZYDIS_BRANCH_WIDTH_64) ||
   4256            (request->address_size_hint == ZYDIS_ADDRESS_SIZE_HINT_64) ||
   4257            (request->operand_size_hint == ZYDIS_OPERAND_SIZE_HINT_64))
   4258        {
   4259            return ZYAN_STATUS_INVALID_ARGUMENT;
   4260        }
   4261    }
   4262 
   4263    for (ZyanU8 i = 0; i < request->operand_count; ++i)
   4264    {
   4265        const ZydisEncoderOperand *op = &request->operands[i];
   4266        if ((op->type == ZYDIS_OPERAND_TYPE_UNUSED) ||
   4267            ((ZyanUSize)op->type > ZYDIS_OPERAND_TYPE_MAX_VALUE))
   4268        {
   4269            return ZYAN_STATUS_INVALID_ARGUMENT;
   4270        }
   4271 
   4272        switch (op->type)
   4273        {
   4274        case ZYDIS_OPERAND_TYPE_REGISTER:
   4275            if (op->reg.value > ZYDIS_REGISTER_MAX_VALUE)
   4276            {
   4277                return ZYAN_STATUS_INVALID_ARGUMENT;
   4278            }
   4279            break;
   4280        case ZYDIS_OPERAND_TYPE_MEMORY:
   4281            if (((ZyanUSize)op->mem.base > ZYDIS_REGISTER_MAX_VALUE) ||
   4282                ((ZyanUSize)op->mem.index > ZYDIS_REGISTER_MAX_VALUE) ||
   4283                !ZydisIsScaleValid(op->mem.scale))
   4284            {
   4285                return ZYAN_STATUS_INVALID_ARGUMENT;
   4286            }
   4287            break;
   4288        case ZYDIS_OPERAND_TYPE_POINTER:
   4289        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
   4290            break;
   4291        default:
   4292            return ZYAN_STATUS_INVALID_ARGUMENT;
   4293        }
   4294    }
   4295 
   4296    return ZYAN_STATUS_SUCCESS;
   4297 }
   4298 
   4299 /**
   4300 * Encodes instruction with semantics specified in encoder request structure.
   4301 *
   4302 * @param   request     A pointer to the `ZydisEncoderRequest` struct. Must be validated before
   4303 *                      calling this function.
   4304 * @param   buffer      A pointer to the output buffer receiving encoded instruction.
   4305 * @param   length      A pointer to the variable containing length of the output buffer. Upon
   4306 *                      successful return this variable receives length of the encoded instruction.
   4307 * @param   instruction Internal state of the encoder.
   4308 *
   4309 * @return  A zyan status code.
   4310 */
   4311 static ZyanStatus ZydisEncoderEncodeInstructionInternal(const ZydisEncoderRequest *request,
   4312    void *buffer, ZyanUSize *length, ZydisEncoderInstruction *instruction)
   4313 {
   4314    ZydisEncoderInstructionMatch match;
   4315    ZYAN_CHECK(ZydisFindMatchingDefinition(request, &match));
   4316    ZydisEncoderBuffer output;
   4317    output.buffer = (ZyanU8 *)buffer;
   4318    output.size = *length;
   4319    output.offset = 0;
   4320    ZYAN_CHECK(ZydisBuildInstruction(&match, instruction));
   4321    ZYAN_CHECK(ZydisEmitInstruction(instruction, &output));
   4322    *length = output.offset;
   4323    return ZYAN_STATUS_SUCCESS;
   4324 }
   4325 
   4326 /* ============================================================================================== */
   4327 /* Exported functions                                                                             */
   4328 /* ============================================================================================== */
   4329 
   4330 ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstruction(const ZydisEncoderRequest *request,
   4331    void *buffer, ZyanUSize *length)
   4332 {
   4333    if (!request || !buffer || !length)
   4334    {
   4335        return ZYAN_STATUS_INVALID_ARGUMENT;
   4336    }
   4337    ZYAN_CHECK(ZydisEncoderCheckRequestSanity(request));
   4338 
   4339    ZydisEncoderInstruction instruction;
   4340    return ZydisEncoderEncodeInstructionInternal(request, buffer, length, &instruction);
   4341 }
   4342 
   4343 ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstructionAbsolute(ZydisEncoderRequest *request,
   4344    void *buffer, ZyanUSize *length, ZyanU64 runtime_address)
   4345 {
   4346    if (!request || !buffer || !length)
   4347    {
   4348        return ZYAN_STATUS_INVALID_ARGUMENT;
   4349    }
   4350    ZYAN_CHECK(ZydisEncoderCheckRequestSanity(request));
   4351 
   4352    const ZydisEncoderRelInfo *rel_info = ZydisGetRelInfo(request->mnemonic);
   4353    ZydisEncoderOperand *op_rip_rel = ZYAN_NULL;
   4354    ZyanBool adjusted_rel = ZYAN_FALSE;
   4355    ZyanU64 absolute_address = 0;
   4356    ZyanU8 mode_index = ZydisGetMachineModeWidth(request->machine_mode) >> 5;
   4357    for (ZyanU8 i = 0; i < request->operand_count; ++i)
   4358    {
   4359        ZydisEncoderOperand *op = &request->operands[i];
   4360        if ((op->type == ZYDIS_OPERAND_TYPE_IMMEDIATE) && rel_info)
   4361        {
   4362            if (adjusted_rel)
   4363            {
   4364                return ZYAN_STATUS_INVALID_ARGUMENT;
   4365            }
   4366 
   4367            switch (rel_info->accepts_scaling_hints)
   4368            {
   4369            case ZYDIS_SIZE_HINT_NONE:
   4370            case ZYDIS_SIZE_HINT_OSZ:
   4371            {
   4372                static const ZyanI8 asz_priority[3][3] =
   4373                {
   4374                    { 0, 1, 2 },
   4375                    { 0, 2, 1 },
   4376                    { 0, 2, -1 },
   4377                };
   4378                static const ZyanI8 osz_priority[3][3] =
   4379                {
   4380                    { 0, 1, 2 },
   4381                    { 0, 2, 1 },
   4382                    { 0, 2, 1 },
   4383                };
   4384                ZyanI8 forced_priority_row[3] = { -1, -1, -1 };
   4385                ZyanI8 *priority_row = ZYAN_NULL;
   4386                ZyanU8 extra_length = 0;
   4387                ZyanU8 start_offset = 0;
   4388                if (rel_info->accepts_scaling_hints == ZYDIS_SIZE_HINT_NONE)
   4389                {
   4390                    if ((request->branch_type == ZYDIS_BRANCH_TYPE_FAR) ||
   4391                        (request->branch_width == ZYDIS_BRANCH_WIDTH_64))
   4392                    {
   4393                        return ZYAN_STATUS_INVALID_ARGUMENT;
   4394                    }
   4395                    if ((rel_info->accepts_branch_hints) &&
   4396                        (request->prefixes & (ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN |
   4397                                              ZYDIS_ATTRIB_HAS_BRANCH_TAKEN)))
   4398                    {
   4399                        extra_length += 1;
   4400                    }
   4401                    if ((rel_info->accepts_bound) && (request->prefixes & ZYDIS_ATTRIB_HAS_BND))
   4402                    {
   4403                        extra_length += 1;
   4404                        // `BND` prefix is not accepted for short `JMP` (Intel SDM Vol. 1)
   4405                        if ((request->mnemonic == ZYDIS_MNEMONIC_JMP) &&
   4406                            (request->branch_type == ZYDIS_BRANCH_TYPE_NONE) &&
   4407                            (request->branch_width == ZYDIS_BRANCH_WIDTH_NONE))
   4408                        {
   4409                            start_offset = 1;
   4410                        }
   4411                    }
   4412                    if (request->branch_width == ZYDIS_BRANCH_WIDTH_NONE)
   4413                    {
   4414                        if (request->branch_type == ZYDIS_BRANCH_TYPE_NEAR)
   4415                        {
   4416                            start_offset = 1;
   4417                        }
   4418                        priority_row = (ZyanI8 *)&asz_priority[mode_index];
   4419                    }
   4420                    else
   4421                    {
   4422                        forced_priority_row[0] = (ZyanI8)(request->branch_width - 1);
   4423                        priority_row = (ZyanI8 *)&forced_priority_row;
   4424                    }
   4425                }
   4426                else
   4427                {
   4428                    if (request->operand_size_hint == ZYDIS_OPERAND_SIZE_HINT_NONE)
   4429                    {
   4430                        priority_row = (ZyanI8 *)&osz_priority[mode_index];
   4431                    }
   4432                    else
   4433                    {
   4434                        if (request->operand_size_hint == ZYDIS_OPERAND_SIZE_HINT_64)
   4435                        {
   4436                            extra_length = 1;
   4437                            forced_priority_row[0] = 2;
   4438                        }
   4439                        else
   4440                        {
   4441                            forced_priority_row[0] = (ZyanI8)(request->operand_size_hint - 1);
   4442                        }
   4443                        priority_row = (ZyanI8 *)&forced_priority_row;
   4444                    }
   4445                }
   4446                ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(asz_priority[0]) ==
   4447                            ZYAN_ARRAY_LENGTH(osz_priority[0]));
   4448                for (ZyanU8 j = start_offset; j < ZYAN_ARRAY_LENGTH(asz_priority[0]); ++j)
   4449                {
   4450                    ZyanI8 size_index = priority_row[j];
   4451                    if (size_index < 0)
   4452                    {
   4453                        break;
   4454                    }
   4455                    ZyanU8 base_size = rel_info->size[mode_index][size_index];
   4456                    if (base_size == 0)
   4457                    {
   4458                        continue;
   4459                    }
   4460                    ZyanU8 predicted_size = base_size + extra_length;
   4461                    if (runtime_address > ZYAN_UINT64_MAX - predicted_size + 1)
   4462                    {
   4463                        continue;
   4464                    }
   4465                    ZyanI64 rel = (ZyanI64)(op->imm.u - (runtime_address + predicted_size));
   4466                    ZyanU8 rel_size = ZydisGetSignedImmSize(rel);
   4467                    if (rel_size > (8 << size_index))
   4468                    {
   4469                        continue;
   4470                    }
   4471                    op->imm.s = rel;
   4472                    adjusted_rel = ZYAN_TRUE;
   4473                    if (rel_info->accepts_scaling_hints == ZYDIS_SIZE_HINT_NONE)
   4474                    {
   4475                        if (request->branch_width == ZYDIS_BRANCH_WIDTH_NONE)
   4476                        {
   4477                            request->branch_width =
   4478                                (ZydisBranchWidth)(ZYDIS_BRANCH_WIDTH_8 + size_index);
   4479                        }
   4480                    }
   4481                    else
   4482                    {
   4483                        if (request->operand_size_hint == ZYDIS_OPERAND_SIZE_HINT_NONE)
   4484                        {
   4485                            request->operand_size_hint =
   4486                                (ZydisOperandSizeHint)(ZYDIS_OPERAND_SIZE_HINT_8 + size_index);
   4487                        }
   4488                    }
   4489                    break;
   4490                }
   4491                break;
   4492            }
   4493            case ZYDIS_SIZE_HINT_ASZ:
   4494            {
   4495                static const ZyanI8 asz_prefix_lookup[3][ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE + 1] =
   4496                {
   4497                    { 0, 0, 1, -1 },
   4498                    { 0, 1, 0, -1 },
   4499                    { 0, -1, 1, 0 },
   4500                };
   4501                ZyanI8 extra_length = asz_prefix_lookup[mode_index][request->address_size_hint];
   4502                if (extra_length < 0)
   4503                {
   4504                    return ZYAN_STATUS_INVALID_ARGUMENT;
   4505                }
   4506                ZyanU8 asz_index = (request->address_size_hint == ZYDIS_ADDRESS_SIZE_HINT_NONE)
   4507                    ? mode_index
   4508                    : ZydisGetAszFromHint(request->address_size_hint) >> 5;
   4509                ZYAN_ASSERT((rel_info->size[asz_index][0] != 0) &&
   4510                            (rel_info->size[asz_index][1] == 0) &&
   4511                            (rel_info->size[asz_index][2] == 0) &&
   4512                            !rel_info->accepts_branch_hints);
   4513                ZyanU8 predicted_size = rel_info->size[asz_index][0] + extra_length;
   4514                if (runtime_address > ZYAN_UINT64_MAX - predicted_size + 1)
   4515                {
   4516                    return ZYAN_STATUS_INVALID_ARGUMENT;
   4517                }
   4518                ZyanI64 rel = (ZyanI64)(op->imm.u - (runtime_address + predicted_size));
   4519                ZyanU8 rel_size = ZydisGetSignedImmSize(rel);
   4520                if (rel_size > 8)
   4521                {
   4522                    return ZYAN_STATUS_INVALID_ARGUMENT;
   4523                }
   4524                op->imm.s = rel;
   4525                adjusted_rel = ZYAN_TRUE;
   4526                break;
   4527            }
   4528            default:
   4529                ZYAN_UNREACHABLE;
   4530            }
   4531            if (!adjusted_rel)
   4532            {
   4533                return ZYAN_STATUS_INVALID_ARGUMENT;
   4534            }
   4535        }
   4536        else if ((op->type == ZYDIS_OPERAND_TYPE_MEMORY) &&
   4537                 ((op->mem.base == ZYDIS_REGISTER_EIP) ||
   4538                  (op->mem.base == ZYDIS_REGISTER_RIP)))
   4539        {
   4540            if (op_rip_rel)
   4541            {
   4542                return ZYAN_STATUS_INVALID_ARGUMENT;
   4543            }
   4544 
   4545            absolute_address = op->mem.displacement;
   4546            op->mem.displacement = 0;
   4547            op_rip_rel = op;
   4548        }
   4549    }
   4550 
   4551    ZydisEncoderInstruction instruction;
   4552    ZYAN_CHECK(ZydisEncoderEncodeInstructionInternal(request, buffer, length, &instruction));
   4553    if (op_rip_rel)
   4554    {
   4555        ZyanUSize instruction_size = *length;
   4556        if (runtime_address > ZYAN_UINT64_MAX - instruction_size + 1)
   4557        {
   4558            return ZYAN_STATUS_INVALID_ARGUMENT;
   4559        }
   4560        ZyanI64 rip_rel = (ZyanI64)(absolute_address - (runtime_address + instruction_size));
   4561        if (ZydisGetSignedImmSize(rip_rel) > 32)
   4562        {
   4563            return ZYAN_STATUS_INVALID_ARGUMENT;
   4564        }
   4565        ZYAN_ASSERT(instruction.disp_size != 0);
   4566        ZyanU8 disp_offset = (instruction.disp_size >> 3) + (instruction.imm_size >> 3);
   4567        if (instruction.encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
   4568        {
   4569            disp_offset += 1;
   4570        }
   4571        ZYAN_ASSERT(instruction_size > disp_offset);
   4572        ZYAN_MEMCPY((ZyanU8 *)buffer + instruction_size - disp_offset, &rip_rel, sizeof(ZyanI32));
   4573        op_rip_rel->mem.displacement = rip_rel;
   4574    }
   4575 
   4576    return ZYAN_STATUS_SUCCESS;
   4577 }
   4578 
   4579 ZYDIS_EXPORT ZyanStatus ZydisEncoderDecodedInstructionToEncoderRequest(
   4580    const ZydisDecodedInstruction *instruction, const ZydisDecodedOperand* operands, 
   4581    ZyanU8 operand_count, ZydisEncoderRequest *request)
   4582 {
   4583    if (!instruction || !request || (operand_count && !operands))
   4584    {
   4585        return ZYAN_STATUS_INVALID_ARGUMENT;
   4586    }
   4587 
   4588    ZYAN_MEMSET(request, 0, sizeof(ZydisEncoderRequest));
   4589    request->machine_mode = instruction->machine_mode;
   4590    request->mnemonic = instruction->mnemonic;
   4591    request->prefixes = instruction->attributes & ZYDIS_ENCODABLE_PREFIXES;
   4592    request->branch_type = instruction->meta.branch_type;
   4593    if (!(instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_SEGMENT))
   4594    {
   4595        request->prefixes &= ~ZYDIS_ATTRIB_HAS_SEGMENT;
   4596    }
   4597 
   4598    switch (instruction->address_width)
   4599    {
   4600    case 16:
   4601        request->address_size_hint = ZYDIS_ADDRESS_SIZE_HINT_16;
   4602        break;
   4603    case 32:
   4604        request->address_size_hint = ZYDIS_ADDRESS_SIZE_HINT_32;
   4605        break;
   4606    case 64:
   4607        request->address_size_hint = ZYDIS_ADDRESS_SIZE_HINT_64;
   4608        break;
   4609    default:
   4610        return ZYAN_STATUS_INVALID_ARGUMENT;
   4611    }
   4612 
   4613    switch (instruction->operand_width)
   4614    {
   4615    case 8:
   4616        request->operand_size_hint = ZYDIS_OPERAND_SIZE_HINT_8;
   4617        break;
   4618    case 16:
   4619        request->operand_size_hint = ZYDIS_OPERAND_SIZE_HINT_16;
   4620        break;
   4621    case 32:
   4622        request->operand_size_hint = ZYDIS_OPERAND_SIZE_HINT_32;
   4623        break;
   4624    case 64:
   4625        request->operand_size_hint = ZYDIS_OPERAND_SIZE_HINT_64;
   4626        break;
   4627    default:
   4628        return ZYAN_STATUS_INVALID_ARGUMENT;
   4629    }
   4630 
   4631    switch (request->branch_type)
   4632    {
   4633    case ZYDIS_BRANCH_TYPE_NONE:
   4634        request->branch_width = ZYDIS_BRANCH_WIDTH_NONE;
   4635        break;
   4636    case ZYDIS_BRANCH_TYPE_SHORT:
   4637        request->branch_width = ZYDIS_BRANCH_WIDTH_8;
   4638        break;
   4639    case ZYDIS_BRANCH_TYPE_NEAR:
   4640    case ZYDIS_BRANCH_TYPE_FAR:
   4641        switch (instruction->operand_width)
   4642        {
   4643        case 16:
   4644            request->branch_width = ZYDIS_BRANCH_WIDTH_16;
   4645            break;
   4646        case 32:
   4647            request->branch_width = ZYDIS_BRANCH_WIDTH_32;
   4648            break;
   4649        case 64:
   4650            request->branch_width = ZYDIS_BRANCH_WIDTH_64;
   4651            break;
   4652        default:
   4653            ZYAN_UNREACHABLE;
   4654        }
   4655        break;
   4656    default:
   4657        return ZYAN_STATUS_INVALID_ARGUMENT;
   4658    }
   4659 
   4660    switch (instruction->encoding)
   4661    {
   4662    case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
   4663    case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
   4664    case ZYDIS_INSTRUCTION_ENCODING_XOP:
   4665    case ZYDIS_INSTRUCTION_ENCODING_VEX:
   4666        break;
   4667    case ZYDIS_INSTRUCTION_ENCODING_EVEX:
   4668        request->evex.broadcast = !instruction->avx.broadcast.is_static ?
   4669            instruction->avx.broadcast.mode : ZYDIS_BROADCAST_MODE_INVALID;
   4670        request->evex.rounding = instruction->avx.rounding.mode;
   4671        request->evex.sae = instruction->avx.has_sae;
   4672        request->evex.zeroing_mask = (instruction->avx.mask.mode == ZYDIS_MASK_MODE_ZEROING ||
   4673            instruction->avx.mask.mode == ZYDIS_MASK_MODE_CONTROL_ZEROING) &&
   4674            (instruction->raw.evex.z) ? ZYAN_TRUE : ZYAN_FALSE;
   4675        break;
   4676    case ZYDIS_INSTRUCTION_ENCODING_MVEX:
   4677        request->mvex.broadcast = !instruction->avx.broadcast.is_static ?
   4678            instruction->avx.broadcast.mode : ZYDIS_BROADCAST_MODE_INVALID;
   4679        request->mvex.conversion = instruction->avx.conversion.mode;
   4680        request->mvex.rounding = instruction->avx.rounding.mode;
   4681        request->mvex.swizzle = instruction->avx.swizzle.mode;
   4682        request->mvex.sae = instruction->avx.has_sae;
   4683        request->mvex.eviction_hint = instruction->avx.has_eviction_hint;
   4684        break;
   4685    default:
   4686        return ZYAN_STATUS_INVALID_ARGUMENT;
   4687    }
   4688    request->allowed_encodings = 1 << instruction->encoding;
   4689 
   4690    if ((operand_count > ZYDIS_ENCODER_MAX_OPERANDS) || 
   4691        (operand_count > instruction->operand_count_visible))
   4692    {
   4693        return ZYAN_STATUS_INVALID_ARGUMENT;
   4694    }
   4695    request->operand_count = operand_count;
   4696    for (ZyanU8 i = 0; i < operand_count; ++i)
   4697    {
   4698        const ZydisDecodedOperand *dec_op = &operands[i];
   4699        ZydisEncoderOperand *enc_op = &request->operands[i];
   4700 
   4701        enc_op->type = dec_op->type;
   4702        switch (dec_op->type)
   4703        {
   4704        case ZYDIS_OPERAND_TYPE_REGISTER:
   4705            enc_op->reg.value = dec_op->reg.value;
   4706            enc_op->reg.is4 = dec_op->encoding == ZYDIS_OPERAND_ENCODING_IS4;
   4707            break;
   4708        case ZYDIS_OPERAND_TYPE_MEMORY:
   4709            enc_op->mem.base = dec_op->mem.base;
   4710            enc_op->mem.index = dec_op->mem.index;
   4711            enc_op->mem.scale = dec_op->mem.type != ZYDIS_MEMOP_TYPE_MIB ? dec_op->mem.scale : 0;
   4712            if (dec_op->mem.disp.has_displacement)
   4713            {
   4714                enc_op->mem.displacement = dec_op->mem.disp.value;
   4715            }
   4716            enc_op->mem.size = dec_op->size / 8;
   4717            break;
   4718        case ZYDIS_OPERAND_TYPE_POINTER:
   4719            enc_op->ptr.segment = dec_op->ptr.segment;
   4720            enc_op->ptr.offset = dec_op->ptr.offset;
   4721            break;
   4722        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
   4723            enc_op->imm.u = dec_op->imm.value.u;
   4724            // `XBEGIN` is an ISA-wide unique instruction because it's not a branching instruction
   4725            // but it has a relative operand which behaves differently from all other relatives
   4726            // (no truncating behavior in 16-bit mode). Encoder treats it as non-branching
   4727            // instruction that scales with hidden operand size.
   4728            if ((dec_op->imm.is_relative) &&
   4729                (instruction->mnemonic != ZYDIS_MNEMONIC_XBEGIN))
   4730            {
   4731                switch (instruction->raw.imm->size)
   4732                {
   4733                case 8:
   4734                    request->branch_width = ZYDIS_BRANCH_WIDTH_8;
   4735                    break;
   4736                case 16:
   4737                    request->branch_width = ZYDIS_BRANCH_WIDTH_16;
   4738                    break;
   4739                case 32:
   4740                    request->branch_width = ZYDIS_BRANCH_WIDTH_32;
   4741                    break;
   4742                default:
   4743                    return ZYAN_STATUS_INVALID_ARGUMENT;
   4744                }
   4745            }
   4746            break;
   4747        default:
   4748            return ZYAN_STATUS_INVALID_ARGUMENT;
   4749        }
   4750    }
   4751 
   4752    return ZYAN_STATUS_SUCCESS;
   4753 }
   4754 
   4755 ZYDIS_EXPORT ZyanStatus ZydisEncoderNopFill(void *buffer, ZyanUSize length)
   4756 {
   4757    if (!buffer)
   4758    {
   4759        return ZYAN_STATUS_INVALID_ARGUMENT;
   4760    }
   4761 
   4762    // Intel SDM Vol. 2B "Recommended Multi-Byte Sequence of NOP Instruction"
   4763    static const ZyanU8 nops[9][9] =
   4764    {
   4765        { 0x90 },
   4766        { 0x66, 0x90 },
   4767        { 0x0F, 0x1F, 0x00 },
   4768        { 0x0F, 0x1F, 0x40, 0x00 },
   4769        { 0x0F, 0x1F, 0x44, 0x00, 0x00 },
   4770        { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 },
   4771        { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 },
   4772        { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
   4773        { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
   4774    };
   4775 
   4776    ZyanU8 *output = (ZyanU8 *)buffer;
   4777    while (length)
   4778    {
   4779        ZyanUSize nop_size = (length > 9) ? 9 : length;
   4780        ZYAN_MEMCPY(output, nops[nop_size - 1], nop_size);
   4781        output += nop_size;
   4782        length -= nop_size;
   4783    }
   4784 
   4785    return ZYAN_STATUS_SUCCESS;
   4786 }
   4787 
   4788 /* ============================================================================================== */