Coverage Report

Created: 2025-11-16 06:43

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