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