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 /* ============================================================================================== */