* Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
/** * Usage of `REX.W` prefix makes it impossible to use some byte-sized registers. Values of this * enum are used to track and facilitate enforcement of these restrictions.
*/ typedefenum ZydisEncoderRexType_
{
ZYDIS_REX_TYPE_UNKNOWN,
ZYDIS_REX_TYPE_REQUIRED,
ZYDIS_REX_TYPE_FORBIDDEN,
/** * Maximum value of this enum.
*/
ZYDIS_REX_TYPE_MAX_VALUE = ZYDIS_REX_TYPE_FORBIDDEN, /** * The minimum number of bits required to represent all values of this enum.
*/
ZYDIS_REX_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REX_TYPE_MAX_VALUE)
} ZydisEncoderRexType;
/** * Primary structure used during instruction matching phase. Once filled it contains information * about matched instruction definition and some values deduced from encoder request. It gets * converted to `ZydisEncoderInstruction` during instruction building phase.
*/ typedefstruct ZydisEncoderInstructionMatch_
{ /** * A pointer to the `ZydisEncoderRequest` instance.
*/ const ZydisEncoderRequest *request; /** * A pointer to the `ZydisEncodableInstruction` instance.
*/ const ZydisEncodableInstruction *definition; /** * A pointer to the `ZydisInstructionDefinition` instance.
*/ const ZydisInstructionDefinition *base_definition; /** * A pointer to the `ZydisOperandDefinition` array.
*/ const ZydisOperandDefinition *operands; /** * Encodable attributes for this instruction.
*/
ZydisInstructionAttributes attributes; /** * Effective operand size attribute.
*/
ZyanU8 eosz; /** * Effective address size attribute.
*/
ZyanU8 easz; /** * Effective displacement size.
*/
ZyanU8 disp_size; /** * Effective immediate size.
*/
ZyanU8 imm_size; /** * Exponent of compressed displacement scale factor (2^cd8_scale)
*/
ZyanU8 cd8_scale; /** * `REX` prefix constraints.
*/
ZydisEncoderRexType rex_type; /** * True for special cases where operand size attribute must be lower than 64 bits.
*/
ZyanBool eosz64_forbidden; /** * True when instruction definition has relative operand (used for branching instructions).
*/
ZyanBool has_rel_operand;
} ZydisEncoderInstructionMatch;
/** * Encapsulates information about writable buffer.
*/ typedefstruct ZydisEncoderBuffer_
{ /** * A pointer to actual data buffer.
*/
ZyanU8 *buffer; /** * Size of this buffer.
*/
ZyanUSize size; /** * Current write offset.
*/
ZyanUSize offset;
} ZydisEncoderBuffer;
/** * Low-level instruction representation. Once filled this structure contains all information * required for final instruction emission phase.
*/ typedefstruct ZydisEncoderInstruction_
{ /** * Encodable attributes for this instruction.
*/
ZydisInstructionAttributes attributes; /** * The instruction encoding.
*/
ZydisInstructionEncoding encoding; /** * The opcode map.
*/
ZydisOpcodeMap opcode_map; /** * The opcode.
*/
ZyanU8 opcode; /** * The `vvvv` field (`VEX`, `EVEX`, `MVEX`, `XOP`).
*/
ZyanU8 vvvv; /** * The `sss` field (`MVEX`).
*/
ZyanU8 sss; /** * The mask register ID.
*/
ZyanU8 mask; /** * The vector length.
*/
ZyanU8 vector_length; /** * The `mod` component of Mod/RM byte.
*/
ZyanU8 mod; /** * The `reg` component of Mod/RM byte.
*/
ZyanU8 reg; /** * The `rm` component of Mod/RM byte.
*/
ZyanU8 rm; /** * The scale component of SIB byte.
*/
ZyanU8 scale; /** * The index component of SIB byte.
*/
ZyanU8 index; /** * The base component of SIB byte.
*/
ZyanU8 base; /** * The `REX.W` bit.
*/
ZyanBool rex_w; /** * True if using zeroing mask (`EVEX`).
*/
ZyanBool zeroing; /** * True if using eviction hint (`MVEX`).
*/
ZyanBool eviction_hint; /** * Size of displacement value.
*/
ZyanU8 disp_size; /** * Size of immediate value.
*/
ZyanU8 imm_size; /** * The displacement value.
*/
ZyanU64 disp; /** * The immediate value.
*/
ZyanU64 imm;
} ZydisEncoderInstruction;
/** * Calculates size of smallest integral type able to represent provided signed value. * * @param imm Immediate to be represented. * * @return Size of smallest integral type able to represent provided signed value.
*/ static ZyanU8 ZydisGetSignedImmSize(ZyanI64 imm)
{ if (imm >= ZYAN_INT8_MIN && imm <= ZYAN_INT8_MAX)
{ return 8;
} if (imm >= ZYAN_INT16_MIN && imm <= ZYAN_INT16_MAX)
{ return 16;
} if (imm >= ZYAN_INT32_MIN && imm <= ZYAN_INT32_MAX)
{ return 32;
}
return 64;
}
/** * Calculates size of smallest integral type able to represent provided unsigned value. * * @param imm Immediate to be represented. * * @return Size of smallest integral type able to represent provided unsigned value.
*/ static ZyanU8 ZydisGetUnsignedImmSize(ZyanU64 imm)
{ if (imm <= ZYAN_UINT8_MAX)
{ return 8;
} if (imm <= ZYAN_UINT16_MAX)
{ return 16;
} if (imm <= ZYAN_UINT32_MAX)
{ return 32;
}
return 64;
}
/** * Checks if operand encoding encodes a signed immediate value. * * @param encoding Operand encoding for immediate value. * * @return True for encodings that represent signed values, false otherwise.
*/ static ZyanBool ZydisIsImmSigned(ZydisOperandEncoding encoding)
{ switch (encoding)
{ case ZYDIS_OPERAND_ENCODING_SIMM8: case ZYDIS_OPERAND_ENCODING_SIMM16: case ZYDIS_OPERAND_ENCODING_SIMM32: case ZYDIS_OPERAND_ENCODING_SIMM64: case ZYDIS_OPERAND_ENCODING_SIMM16_32_64: case ZYDIS_OPERAND_ENCODING_SIMM32_32_64: case ZYDIS_OPERAND_ENCODING_SIMM16_32_32: case ZYDIS_OPERAND_ENCODING_JIMM8: case ZYDIS_OPERAND_ENCODING_JIMM16: case ZYDIS_OPERAND_ENCODING_JIMM32: case ZYDIS_OPERAND_ENCODING_JIMM64: case ZYDIS_OPERAND_ENCODING_JIMM16_32_64: case ZYDIS_OPERAND_ENCODING_JIMM32_32_64: case ZYDIS_OPERAND_ENCODING_JIMM16_32_32: case ZYDIS_OPERAND_ENCODING_DISP8: case ZYDIS_OPERAND_ENCODING_DISP16: case ZYDIS_OPERAND_ENCODING_DISP32: case ZYDIS_OPERAND_ENCODING_DISP64: case ZYDIS_OPERAND_ENCODING_DISP16_32_64: case ZYDIS_OPERAND_ENCODING_DISP32_32_64: case ZYDIS_OPERAND_ENCODING_DISP16_32_32: return ZYAN_TRUE; case ZYDIS_OPERAND_ENCODING_UIMM8: case ZYDIS_OPERAND_ENCODING_UIMM16: case ZYDIS_OPERAND_ENCODING_UIMM32: case ZYDIS_OPERAND_ENCODING_UIMM64: case ZYDIS_OPERAND_ENCODING_UIMM16_32_64: case ZYDIS_OPERAND_ENCODING_UIMM32_32_64: case ZYDIS_OPERAND_ENCODING_UIMM16_32_32: case ZYDIS_OPERAND_ENCODING_IS4: return ZYAN_FALSE; default:
ZYAN_UNREACHABLE;
}
}
/** * Calculates effective immediate size. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param imm Immediate value to encode. * @param def_op Operand definition for immediate operand. * * @return Effective operand size in bits (0 if function failed).
*/ static ZyanU8 ZydisGetEffectiveImmSize(ZydisEncoderInstructionMatch *match, ZyanI64 imm, const ZydisOperandDefinition *def_op)
{
ZyanU8 eisz = 0;
ZyanU8 min_size = ZydisIsImmSigned((ZydisOperandEncoding)def_op->op.encoding)
? ZydisGetSignedImmSize(imm)
: ZydisGetUnsignedImmSize((ZyanU64)imm);
switch (def_op->op.encoding)
{ case ZYDIS_OPERAND_ENCODING_UIMM8: case ZYDIS_OPERAND_ENCODING_SIMM8:
eisz = 8; break; case ZYDIS_OPERAND_ENCODING_IS4:
ZYAN_ASSERT(def_op->element_type == ZYDIS_IELEMENT_TYPE_UINT8);
eisz = ((ZyanU64)imm <= 15) ? 8 : 0; break; case ZYDIS_OPERAND_ENCODING_UIMM16: case ZYDIS_OPERAND_ENCODING_SIMM16:
eisz = 16; break; case ZYDIS_OPERAND_ENCODING_UIMM32: case ZYDIS_OPERAND_ENCODING_SIMM32:
eisz = 32; break; case ZYDIS_OPERAND_ENCODING_UIMM64: case ZYDIS_OPERAND_ENCODING_SIMM64:
eisz = 64; break; case ZYDIS_OPERAND_ENCODING_UIMM16_32_64: case ZYDIS_OPERAND_ENCODING_SIMM16_32_64:
{ staticconst ZyanU16 simm16_32_64_sizes[3] = { 16, 32, 64 }; return ZydisGetScaledImmSize(match, simm16_32_64_sizes, min_size);
} case ZYDIS_OPERAND_ENCODING_UIMM32_32_64: case ZYDIS_OPERAND_ENCODING_SIMM32_32_64:
{ staticconst ZyanU16 simm32_32_64_sizes[3] = { 32, 32, 64 }; return ZydisGetScaledImmSize(match, simm32_32_64_sizes, min_size);
} case ZYDIS_OPERAND_ENCODING_UIMM16_32_32: case ZYDIS_OPERAND_ENCODING_SIMM16_32_32:
{ staticconst ZyanU16 simm16_32_32_sizes[3] = { 16, 32, 32 }; return ZydisGetScaledImmSize(match, simm16_32_32_sizes, min_size);
} case ZYDIS_OPERAND_ENCODING_DISP16_32_64:
{
ZYAN_ASSERT(match->easz == 0); const ZyanU8 addr_size = ZydisGetMaxAddressSize(match->request); const ZyanU64 uimm = imm & (~(0xFFFFFFFFFFFFFFFFULL << (addr_size - 1) << 1)); if (min_size < addr_size && ZydisGetUnsignedImmSize(uimm) > min_size)
{
min_size = addr_size;
} if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
{ if (min_size < 32)
{
min_size = 32;
}
match->easz = eisz = min_size;
} else
{ if (min_size < 16)
{
min_size = 16;
} if (min_size == 16 || min_size == 32)
{
match->easz = eisz = min_size;
}
} break;
} case ZYDIS_OPERAND_ENCODING_JIMM8: case ZYDIS_OPERAND_ENCODING_JIMM16: case ZYDIS_OPERAND_ENCODING_JIMM32: case ZYDIS_OPERAND_ENCODING_JIMM64:
{
ZyanU8 jimm_index = def_op->op.encoding - ZYDIS_OPERAND_ENCODING_JIMM8; if ((match->request->branch_width != ZYDIS_BRANCH_WIDTH_NONE) &&
(match->request->branch_width != (ZydisBranchWidth)(ZYDIS_BRANCH_WIDTH_8 + jimm_index)))
{ return 0;
}
eisz = 8 << jimm_index; break;
} case ZYDIS_OPERAND_ENCODING_JIMM16_32_32: switch (match->request->branch_width)
{ case ZYDIS_BRANCH_WIDTH_NONE:
{ staticconst ZyanU16 jimm16_32_32_sizes[3] = { 16, 32, 32 }; return ZydisGetScaledImmSize(match, jimm16_32_32_sizes, min_size);
} case ZYDIS_BRANCH_WIDTH_16:
eisz = 16; break; case ZYDIS_BRANCH_WIDTH_32:
eisz = 32; break; case ZYDIS_BRANCH_WIDTH_8: case ZYDIS_BRANCH_WIDTH_64: return 0; default:
ZYAN_UNREACHABLE;
} break; default:
ZYAN_UNREACHABLE;
}
return eisz >= min_size ? eisz : 0;
}
/** * Checks if register width is compatible with effective operand size. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param reg_width Register width in bits. * * @return True if width is compatible, false otherwise.
*/ static ZyanBool ZydisCheckOsz(ZydisEncoderInstructionMatch *match, ZydisRegisterWidth reg_width)
{
ZYAN_ASSERT(reg_width <= ZYAN_UINT8_MAX); if (match->eosz == 0)
{ if (reg_width == 8)
{ return ZYAN_FALSE;
}
match->eosz = (ZyanU8)reg_width; return ZYAN_TRUE;
}
/** * Checks if specified register is valid for provided register class, encoding and machine mode. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param reg `ZydisRegister` value. * @param reg_class Register class. * * @return True if register value is allowed, false otherwise.
*/ static ZyanBool ZydisIsRegisterAllowed(ZydisEncoderInstructionMatch *match, ZydisRegister reg,
ZydisRegisterClass reg_class)
{ const ZyanI8 reg_id = ZydisRegisterGetId(reg);
ZYAN_ASSERT(reg_id >= 0 && reg_id <= 31); if (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
{ if ((match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_EVEX) &&
(match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_MVEX) &&
(reg_class != ZYDIS_REGCLASS_GPR8) &&
(reg_id >= 16))
{ return ZYAN_FALSE;
}
} else
{ if (reg_class == ZYDIS_REGCLASS_GPR64)
{ return ZYAN_FALSE;
} if (reg_id >= 8)
{ return ZYAN_FALSE;
}
}
return ZYAN_TRUE;
}
/** * Checks if specified scale value is valid for use with SIB addressing. * * @param scale Scale value. * * @return True if value is valid, false otherwise.
*/ static ZyanBool ZydisIsScaleValid(ZyanU8 scale)
{ switch (scale)
{ case 0: case 1: case 2: case 4: case 8: return ZYAN_TRUE; default: return ZYAN_FALSE;
}
}
/** * Enforces register usage constraints associated with usage of `REX` prefix. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param reg `ZydisRegister` value. * @param addressing_mode True if checked address is used for address calculations. This * implies more permissive checks. * * @return True if register usage is allowed, false otherwise.
*/ static ZyanBool ZydisValidateRexType(ZydisEncoderInstructionMatch *match, ZydisRegister reg,
ZyanBool addressing_mode)
{ switch (reg)
{ case ZYDIS_REGISTER_AL: case ZYDIS_REGISTER_CL: case ZYDIS_REGISTER_DL: case ZYDIS_REGISTER_BL: return ZYAN_TRUE; case ZYDIS_REGISTER_AH: case ZYDIS_REGISTER_CH: case ZYDIS_REGISTER_DH: case ZYDIS_REGISTER_BH: if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
{
match->rex_type = ZYDIS_REX_TYPE_FORBIDDEN;
} elseif (match->rex_type == ZYDIS_REX_TYPE_REQUIRED)
{ return ZYAN_FALSE;
} break; case ZYDIS_REGISTER_SPL: case ZYDIS_REGISTER_BPL: case ZYDIS_REGISTER_SIL: case ZYDIS_REGISTER_DIL: case ZYDIS_REGISTER_R8B: case ZYDIS_REGISTER_R9B: case ZYDIS_REGISTER_R10B: case ZYDIS_REGISTER_R11B: case ZYDIS_REGISTER_R12B: case ZYDIS_REGISTER_R13B: case ZYDIS_REGISTER_R14B: case ZYDIS_REGISTER_R15B: if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
{
match->rex_type = ZYDIS_REX_TYPE_REQUIRED;
} elseif (match->rex_type == ZYDIS_REX_TYPE_FORBIDDEN)
{ return ZYAN_FALSE;
} break; default: if ((ZydisRegisterGetId(reg) > 7) ||
(!addressing_mode && (ZydisRegisterGetClass(reg) == ZYDIS_REGCLASS_GPR64)))
{ if (match->rex_type == ZYDIS_REX_TYPE_UNKNOWN)
{
match->rex_type = ZYDIS_REX_TYPE_REQUIRED;
} elseif (match->rex_type == ZYDIS_REX_TYPE_FORBIDDEN)
{ return ZYAN_FALSE;
}
} break;
}
return ZYAN_TRUE;
}
/** * Checks if specified register is valid for use with SIB addressing. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param reg_class Register class. * @param reg `ZydisRegister` value. * * @return True if register value is allowed, false otherwise.
*/ static ZyanBool ZydisIsValidAddressingClass(ZydisEncoderInstructionMatch *match,
ZydisRegisterClass reg_class, ZydisRegister reg)
{
ZyanBool result; const ZyanBool is_64 = (match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64); switch (reg_class)
{ case ZYDIS_REGCLASS_INVALID: return ZYAN_TRUE; case ZYDIS_REGCLASS_GPR16:
result = !is_64; break; case ZYDIS_REGCLASS_GPR32:
result = is_64 || ZydisRegisterGetId(reg) < 8; break; case ZYDIS_REGCLASS_GPR64:
result = is_64; break; default: return ZYAN_FALSE;
}
return result && ZydisValidateRexType(match, reg, ZYAN_TRUE);
}
/** * Helper function that determines correct `ModR/M.RM` value for 16-bit addressing mode. * * @param base `ZydisRegister` used as `SIB.base`. * @param index `ZydisRegister` used as `SIB.index`. * * @return `ModR/M.RM` value (-1 if function failed).
*/ static ZyanI8 ZydisGetRm16(ZydisRegister base, ZydisRegister index)
{ staticconst ZydisRegister modrm16_lookup[8][2] =
{
{ ZYDIS_REGISTER_BX, ZYDIS_REGISTER_SI },
{ ZYDIS_REGISTER_BX, ZYDIS_REGISTER_DI },
{ ZYDIS_REGISTER_BP, ZYDIS_REGISTER_SI },
{ ZYDIS_REGISTER_BP, ZYDIS_REGISTER_DI },
{ ZYDIS_REGISTER_SI, ZYDIS_REGISTER_NONE },
{ ZYDIS_REGISTER_DI, ZYDIS_REGISTER_NONE },
{ ZYDIS_REGISTER_BP, ZYDIS_REGISTER_NONE },
{ ZYDIS_REGISTER_BX, ZYDIS_REGISTER_NONE },
}; for (ZyanI8 i = 0; i < (ZyanI8)ZYAN_ARRAY_LENGTH(modrm16_lookup); ++i)
{ if ((modrm16_lookup[i][0] == base) &&
(modrm16_lookup[i][1] == index))
{ return i;
}
}
return -1;
}
/** * Encodes `MVEX.sss` field for specified broadcast mode. * * @param broadcast Broadcast mode. * * @return Corresponding `MVEX.sss` value.
*/ static ZyanU8 ZydisEncodeMvexBroadcastMode(ZydisBroadcastMode broadcast)
{ switch (broadcast)
{ case ZYDIS_BROADCAST_MODE_INVALID: return 0; case ZYDIS_BROADCAST_MODE_1_TO_16: case ZYDIS_BROADCAST_MODE_1_TO_8: return 1; case ZYDIS_BROADCAST_MODE_4_TO_16: case ZYDIS_BROADCAST_MODE_4_TO_8: return 2; default:
ZYAN_UNREACHABLE;
}
}
/** * Encodes `MVEX.sss` field for specified conversion mode. * * @param conversion Conversion mode. * * @return Corresponding `MVEX.sss` value.
*/ static ZyanU8 ZydisEncodeMvexConversionMode(ZydisConversionMode conversion)
{ switch (conversion)
{ case ZYDIS_CONVERSION_MODE_INVALID: return 0; case ZYDIS_CONVERSION_MODE_FLOAT16: return 3; case ZYDIS_CONVERSION_MODE_UINT8: return 4; case ZYDIS_CONVERSION_MODE_SINT8: return 5; case ZYDIS_CONVERSION_MODE_UINT16: return 6; case ZYDIS_CONVERSION_MODE_SINT16: return 7; default:
ZYAN_UNREACHABLE;
}
}
/** * Determines scale factor for compressed 8-bit displacement (`EVEX` instructions only). * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return log2(scale factor)
*/ static ZyanU8 ZydisGetCompDispScaleEvex(const ZydisEncoderInstructionMatch *match)
{ const ZydisInstructionDefinitionEVEX *evex_def =
(const ZydisInstructionDefinitionEVEX *)match->base_definition;
/** * Determines scale factor for compressed 8-bit displacement (`MVEX` instructions only). * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return log2(scale factor)
*/ static ZyanU8 ZydisGetCompDispScaleMvex(const ZydisEncoderInstructionMatch *match)
{ const ZydisInstructionDefinitionMVEX *mvex_def =
(const ZydisInstructionDefinitionMVEX *)match->base_definition;
ZyanU8 index = mvex_def->has_element_granularity;
ZYAN_ASSERT(!index || !mvex_def->broadcast); if (!index && mvex_def->broadcast)
{ switch (mvex_def->broadcast)
{ case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8: case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16:
index = 1; break; case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8: case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16:
index = 2; break; default:
ZYAN_UNREACHABLE;
}
}
const ZyanU8 sss = ZydisEncodeMvexBroadcastMode(match->request->mvex.broadcast) |
ZydisEncodeMvexConversionMode(match->request->mvex.conversion); switch (mvex_def->functionality)
{ case ZYDIS_MVEX_FUNC_IGNORED: case ZYDIS_MVEX_FUNC_INVALID: case ZYDIS_MVEX_FUNC_RC: case ZYDIS_MVEX_FUNC_SAE: case ZYDIS_MVEX_FUNC_SWIZZLE_32: case ZYDIS_MVEX_FUNC_SWIZZLE_64: return 0; case ZYDIS_MVEX_FUNC_F_32: case ZYDIS_MVEX_FUNC_I_32: case ZYDIS_MVEX_FUNC_F_64: case ZYDIS_MVEX_FUNC_I_64: return 6; case ZYDIS_MVEX_FUNC_SF_32: case ZYDIS_MVEX_FUNC_SF_32_BCST: case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16: case ZYDIS_MVEX_FUNC_UF_32:
{ staticconst ZyanU8 lookup[3][8] =
{
{ 6, 2, 4, 5, 4, 4, 5, 5 },
{ 2, 0, 0, 1, 0, 0, 1, 1 },
{ 4, 0, 0, 3, 2, 2, 3, 3 }
};
ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index])); return lookup[index][sss];
} case ZYDIS_MVEX_FUNC_SI_32: case ZYDIS_MVEX_FUNC_UI_32: case ZYDIS_MVEX_FUNC_SI_32_BCST: case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
{ staticconst ZyanU8 lookup[3][8] =
{
{ 6, 2, 4, 0, 4, 4, 5, 5 },
{ 2, 0, 0, 0, 0, 0, 1, 1 },
{ 4, 0, 0, 0, 2, 2, 3, 3 }
};
ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index])); return lookup[index][sss];
} case ZYDIS_MVEX_FUNC_SF_64: case ZYDIS_MVEX_FUNC_UF_64: case ZYDIS_MVEX_FUNC_SI_64: case ZYDIS_MVEX_FUNC_UI_64:
{ staticconst ZyanU8 lookup[3][3] =
{
{ 6, 3, 5 },
{ 3, 0, 0 },
{ 5, 0, 0 }
};
ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index])); return lookup[index][sss];
} case ZYDIS_MVEX_FUNC_DF_32: case ZYDIS_MVEX_FUNC_DI_32:
{ staticconst ZyanU8 lookup[2][8] =
{
{ 6, 0, 0, 5, 4, 4, 5, 5 },
{ 2, 0, 0, 1, 0, 0, 1, 1 }
};
ZYAN_ASSERT(index < 2);
ZYAN_ASSERT(sss < ZYAN_ARRAY_LENGTH(lookup[index])); return lookup[index][sss];
} case ZYDIS_MVEX_FUNC_DF_64: case ZYDIS_MVEX_FUNC_DI_64:
ZYAN_ASSERT(index < 2); return index == 0 ? 6 : 3; default:
ZYAN_UNREACHABLE;
}
}
/** * Determines scale factor for compressed 8-bit displacement. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return log2(scale factor)
*/ static ZyanU8 ZydisGetCompDispScale(const ZydisEncoderInstructionMatch *match)
{ switch (match->definition->encoding)
{ case ZYDIS_INSTRUCTION_ENCODING_LEGACY: case ZYDIS_INSTRUCTION_ENCODING_3DNOW: case ZYDIS_INSTRUCTION_ENCODING_XOP: case ZYDIS_INSTRUCTION_ENCODING_VEX: return 0; case ZYDIS_INSTRUCTION_ENCODING_EVEX: return ZydisGetCompDispScaleEvex(match); case ZYDIS_INSTRUCTION_ENCODING_MVEX: return ZydisGetCompDispScaleMvex(match); default:
ZYAN_UNREACHABLE;
}
}
/** * Checks if requested operand matches register operand from instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param user_op Operand definition from `ZydisEncoderRequest` structure. * @param def_op Decoder's operand definition from current instruction definition. * * @return True if operands match, false otherwise.
*/ static ZyanBool ZydisIsRegisterOperandCompatible(ZydisEncoderInstructionMatch *match, const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
{ const ZydisRegisterClass reg_class = ZydisRegisterGetClass(user_op->reg.value); const ZydisRegisterWidth reg_width = ZydisRegisterClassGetWidth(match->request->machine_mode,
reg_class); if (reg_width == 0)
{ return ZYAN_FALSE;
}
ZyanBool is4_expected_value = ZYAN_FALSE; switch (def_op->type)
{ case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG: switch (def_op->op.reg.type)
{ case ZYDIS_IMPLREG_TYPE_STATIC: if (def_op->op.reg.reg.reg != user_op->reg.value)
{ return ZYAN_FALSE;
} break; case ZYDIS_IMPLREG_TYPE_GPR_OSZ: if ((reg_class != ZYDIS_REGCLASS_GPR8) &&
(reg_class != ZYDIS_REGCLASS_GPR16) &&
(reg_class != ZYDIS_REGCLASS_GPR32) &&
(reg_class != ZYDIS_REGCLASS_GPR64))
{ return ZYAN_FALSE;
} if (def_op->op.reg.reg.id != ZydisRegisterGetId(user_op->reg.value))
{ return ZYAN_FALSE;
} if (!ZydisCheckOsz(match, reg_width))
{ return ZYAN_FALSE;
} break; case ZYDIS_IMPLREG_TYPE_GPR_ASZ: if ((reg_class != ZYDIS_REGCLASS_GPR8) &&
(reg_class != ZYDIS_REGCLASS_GPR16) &&
(reg_class != ZYDIS_REGCLASS_GPR32) &&
(reg_class != ZYDIS_REGCLASS_GPR64))
{ return ZYAN_FALSE;
} if (def_op->op.reg.reg.id != ZydisRegisterGetId(user_op->reg.value))
{ return ZYAN_FALSE;
} if (!ZydisCheckAsz(match, reg_width))
{ return ZYAN_FALSE;
} break; default:
ZYAN_UNREACHABLE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR8: if (reg_class != ZYDIS_REGCLASS_GPR8)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR16: if (reg_class != ZYDIS_REGCLASS_GPR16)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR32: if (reg_class != ZYDIS_REGCLASS_GPR32)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR64: if (reg_class != ZYDIS_REGCLASS_GPR64)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64: if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
(reg_class != ZYDIS_REGCLASS_GPR32) &&
(reg_class != ZYDIS_REGCLASS_GPR64))
{ return ZYAN_FALSE;
} if (!ZydisCheckOsz(match, reg_width))
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64: if ((reg_class != ZYDIS_REGCLASS_GPR32) &&
(reg_class != ZYDIS_REGCLASS_GPR64))
{ return ZYAN_FALSE;
} if (match->eosz == 0)
{ if (reg_class == ZYDIS_REGCLASS_GPR64)
{
match->eosz = 64;
} else
{
match->eosz64_forbidden = ZYAN_TRUE;
}
} elseif (match->eosz != (ZyanU8)reg_width)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} if (!ZydisValidateRexType(match, user_op->reg.value, ZYAN_FALSE))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32: if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
(reg_class != ZYDIS_REGCLASS_GPR32))
{ return ZYAN_FALSE;
} if (!ZydisCheckOsz(match, reg_width))
{ if (match->eosz != 64 || reg_class != ZYDIS_REGCLASS_GPR32)
{ return ZYAN_FALSE;
}
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ: if ((reg_class != ZYDIS_REGCLASS_GPR16) &&
(reg_class != ZYDIS_REGCLASS_GPR32) &&
(reg_class != ZYDIS_REGCLASS_GPR64))
{ return ZYAN_FALSE;
} if (!ZydisCheckAsz(match, reg_width))
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_FPR: if (reg_class != ZYDIS_REGCLASS_X87)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_MMX: if (reg_class != ZYDIS_REGCLASS_MMX)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_XMM: if (reg_class != ZYDIS_REGCLASS_XMM)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
}
is4_expected_value = def_op->op.encoding == ZYDIS_OPERAND_ENCODING_IS4; break; case ZYDIS_SEMANTIC_OPTYPE_YMM: if (reg_class != ZYDIS_REGCLASS_YMM)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
}
is4_expected_value = def_op->op.encoding == ZYDIS_OPERAND_ENCODING_IS4; break; case ZYDIS_SEMANTIC_OPTYPE_ZMM: if (reg_class != ZYDIS_REGCLASS_ZMM)
{ return ZYAN_FALSE;
} if (!ZydisIsRegisterAllowed(match, user_op->reg.value, reg_class))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_TMM: if (reg_class != ZYDIS_REGCLASS_TMM)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_BND: if (reg_class != ZYDIS_REGCLASS_BOUND)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_SREG: if (reg_class != ZYDIS_REGCLASS_SEGMENT)
{ return ZYAN_FALSE;
} if ((def_op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE) &&
(user_op->reg.value == ZYDIS_REGISTER_CS))
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_CR:
{ if (reg_class != ZYDIS_REGCLASS_CONTROL)
{ return ZYAN_FALSE;
} staticconst ZyanU8 cr_lookup[16] =
{
1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
}; const ZyanI8 reg_id = ZydisRegisterGetId(user_op->reg.value); if ((match->request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) &&
(reg_id == 8))
{ return ZYAN_FALSE;
} if (!cr_lookup[reg_id])
{ return ZYAN_FALSE;
} break;
} case ZYDIS_SEMANTIC_OPTYPE_DR: if (reg_class != ZYDIS_REGCLASS_DEBUG)
{ return ZYAN_FALSE;
} if (user_op->reg.value >= ZYDIS_REGISTER_DR8)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_MASK: if (reg_class != ZYDIS_REGCLASS_MASK)
{ return ZYAN_FALSE;
}
/** * Checks if requested operand matches immediate operand from instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param user_op Operand definition from `ZydisEncoderRequest` structure. * @param def_op Decoder's operand definition from current instruction definition. * * @return True if operands match, false otherwise.
*/ static ZyanBool ZydisIsImmediateOperandCompabile(ZydisEncoderInstructionMatch *match, const ZydisEncoderOperand *user_op, const ZydisOperandDefinition *def_op)
{ switch (def_op->type)
{ case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1: if (user_op->imm.u != 1)
{ return ZYAN_FALSE;
} break; case ZYDIS_SEMANTIC_OPTYPE_IMM: case ZYDIS_SEMANTIC_OPTYPE_REL:
{ const ZyanU8 imm_size = ZydisGetEffectiveImmSize(match, user_op->imm.s, def_op); if (def_op->op.encoding != ZYDIS_OPERAND_ENCODING_IS4)
{ if (imm_size == 0)
{ return ZYAN_FALSE;
} if (match->imm_size)
{
ZYAN_ASSERT(match->disp_size == 0);
match->disp_size = match->imm_size;
}
} else
{
ZYAN_ASSERT(match->imm_size == 0); if (imm_size != 8)
{ return ZYAN_FALSE;
}
}
match->imm_size = imm_size;
match->has_rel_operand = (def_op->type == ZYDIS_SEMANTIC_OPTYPE_REL); break;
} default:
ZYAN_UNREACHABLE;
}
return ZYAN_TRUE;
}
/** * Checks if requested boardcast mode is compatible with instruction definition. * * @param evex_def Definition for `EVEX`-encoded instruction. * @param vector_length Vector length. * @param broadcast Requested broadcast mode. * * @return True if broadcast mode is compatible, false otherwise.
*/ static ZyanBool ZydisIsBroadcastModeCompatible(const ZydisInstructionDefinitionEVEX *evex_def,
ZydisVectorLength vector_length, ZydisBroadcastMode broadcast)
{ if (broadcast == ZYDIS_BROADCAST_MODE_INVALID)
{ return ZYAN_TRUE;
}
ZyanU8 vector_size = 0;
ZYAN_ASSERT(vector_length != ZYDIS_VECTOR_LENGTH_INVALID); switch (vector_length)
{ case ZYDIS_VECTOR_LENGTH_128:
vector_size = 16; break; case ZYDIS_VECTOR_LENGTH_256:
vector_size = 32; break; case ZYDIS_VECTOR_LENGTH_512:
vector_size = 64; break; default:
ZYAN_UNREACHABLE;
} switch (evex_def->tuple_type)
{ case ZYDIS_TUPLETYPE_FV: break; case ZYDIS_TUPLETYPE_HV:
vector_size /= 2; break; case ZYDIS_TUPLETYPE_QUARTER:
vector_size /= 4; break; default:
ZYAN_UNREACHABLE;
}
ZyanU8 element_size; switch (evex_def->element_size)
{ case ZYDIS_IELEMENT_SIZE_16:
element_size = 2; break; case ZYDIS_IELEMENT_SIZE_32:
element_size = 4; break; case ZYDIS_IELEMENT_SIZE_64:
element_size = 8; break; default:
ZYAN_UNREACHABLE;
}
ZydisBroadcastMode allowed_mode; const ZyanU8 element_count = vector_size / element_size; switch (element_count)
{ case 2:
allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_2; break; case 4:
allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_4; break; case 8:
allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_8; break; case 16:
allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_16; break; case 32:
allowed_mode = ZYDIS_BROADCAST_MODE_1_TO_32; break; default:
ZYAN_UNREACHABLE;
}
if (broadcast != allowed_mode)
{ return ZYAN_FALSE;
}
return ZYAN_TRUE;
}
/** * Checks if requested `EVEX`-specific features are compatible with instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param request A pointer to `ZydisEncoderRequest` struct. * * @return True if features are compatible, false otherwise.
*/ static ZyanBool ZydisAreEvexFeaturesCompatible(const ZydisEncoderInstructionMatch *match, const ZydisEncoderRequest *request)
{ if (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_EVEX)
{ return ZYAN_TRUE;
}
switch (evex_def->functionality)
{ case ZYDIS_EVEX_FUNC_INVALID: if ((request->evex.sae) ||
(request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
{ return ZYAN_FALSE;
} break; case ZYDIS_EVEX_FUNC_BC: if ((request->evex.sae) ||
(request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
{ return ZYAN_FALSE;
} if (!ZydisIsBroadcastModeCompatible(evex_def, match->definition->vector_length,
request->evex.broadcast))
{ return ZYAN_FALSE;
} break; case ZYDIS_EVEX_FUNC_RC: if (request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID)
{ return ZYAN_FALSE;
} if (request->evex.rounding == ZYDIS_ROUNDING_MODE_INVALID)
{ if (request->evex.sae)
{ return ZYAN_FALSE;
}
} else
{ if (!request->evex.sae)
{ return ZYAN_FALSE;
}
} break; case ZYDIS_EVEX_FUNC_SAE: if ((request->evex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->evex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
{ return ZYAN_FALSE;
} break; default:
ZYAN_UNREACHABLE;
}
return ZYAN_TRUE;
}
/** * Checks if requested `MVEX`-specific features are compatible with instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param request A pointer to `ZydisEncoderRequest` struct. * * @return True if features are compatible, false otherwise.
*/ static ZyanBool ZydisAreMvexFeaturesCompatible(const ZydisEncoderInstructionMatch *match, const ZydisEncoderRequest *request)
{ if (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_MVEX)
{ return ZYAN_TRUE;
} if (((match->definition->modrm >> 6) == 3) &&
(request->mvex.eviction_hint))
{ return ZYAN_FALSE;
}
const ZydisInstructionDefinitionMVEX *mvex_def =
(const ZydisInstructionDefinitionMVEX *)match->base_definition; switch (mvex_def->functionality)
{ case ZYDIS_MVEX_FUNC_IGNORED: case ZYDIS_MVEX_FUNC_INVALID: case ZYDIS_MVEX_FUNC_F_32: case ZYDIS_MVEX_FUNC_I_32: case ZYDIS_MVEX_FUNC_F_64: case ZYDIS_MVEX_FUNC_I_64: case ZYDIS_MVEX_FUNC_UF_64: case ZYDIS_MVEX_FUNC_UI_64: case ZYDIS_MVEX_FUNC_DF_64: case ZYDIS_MVEX_FUNC_DI_64: if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_RC: if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.eviction_hint))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SAE: if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.eviction_hint))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SWIZZLE_32: case ZYDIS_MVEX_FUNC_SWIZZLE_64: if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SF_32: if ((request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_16) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
{ return ZYAN_FALSE;
} if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_FLOAT16) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT8) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT16) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT16))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SI_32: if ((request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_16) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
{ return ZYAN_FALSE;
} if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT8) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT8) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT16) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT16))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SF_32_BCST: case ZYDIS_MVEX_FUNC_SI_32_BCST: if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_16) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16: case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16: if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_16))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_SF_64: case ZYDIS_MVEX_FUNC_SI_64: if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_1_TO_8) &&
(request->mvex.broadcast != ZYDIS_BROADCAST_MODE_4_TO_8))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_UF_32: case ZYDIS_MVEX_FUNC_DF_32: if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} break; case ZYDIS_MVEX_FUNC_UI_32: case ZYDIS_MVEX_FUNC_DI_32: if ((request->mvex.broadcast != ZYDIS_BROADCAST_MODE_INVALID) ||
(request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID) ||
(request->mvex.swizzle != ZYDIS_SWIZZLE_MODE_INVALID) ||
(request->mvex.sae))
{ return ZYAN_FALSE;
} if ((request->mvex.conversion != ZYDIS_CONVERSION_MODE_INVALID) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT8) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT8) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_UINT16) &&
(request->mvex.conversion != ZYDIS_CONVERSION_MODE_SINT16))
{ return ZYAN_FALSE;
} break; default:
ZYAN_UNREACHABLE;
}
return ZYAN_TRUE;
}
/** * Checks if operands specified in encoder request satisfy additional constraints mandated by * matched instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return True if operands passed the checks, false otherwise.
*/ static ZyanBool ZydisCheckConstraints(const ZydisEncoderInstructionMatch *match)
{ const ZydisEncoderOperand *operands = match->request->operands;
ZyanBool is_gather = ZYAN_FALSE; switch (match->definition->encoding)
{ case ZYDIS_INSTRUCTION_ENCODING_VEX:
{ const ZydisInstructionDefinitionVEX *vex_def =
(const ZydisInstructionDefinitionVEX *)match->base_definition; if (vex_def->is_gather)
{
ZYAN_ASSERT(match->request->operand_count == 3);
ZYAN_ASSERT(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER);
ZYAN_ASSERT(operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY);
ZYAN_ASSERT(operands[2].type == ZYDIS_OPERAND_TYPE_REGISTER); const ZyanI8 dest = ZydisRegisterGetId(operands[0].reg.value); const ZyanI8 index = ZydisRegisterGetId(operands[1].mem.index); const ZyanI8 mask = ZydisRegisterGetId(operands[2].reg.value); // If any pair of the index, mask, or destination registers are the same, the // instruction results a UD fault. if ((dest == index) || (dest == mask) || (index == mask))
{ return ZYAN_FALSE;
}
}
if ((is_gather) && (operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER))
{
ZYAN_ASSERT(match->request->operand_count == 3);
ZYAN_ASSERT(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER);
ZYAN_ASSERT(operands[2].type == ZYDIS_OPERAND_TYPE_MEMORY); const ZyanI8 dest = ZydisRegisterGetId(operands[0].reg.value); const ZyanI8 index = ZydisRegisterGetId(operands[2].mem.index); // EVEX: The instruction will #UD fault if the destination vector zmm1 is the same as // index vector VINDEX. // MVEX: The KNC GATHER instructions forbid using the same vector register for destination // and for the index. (https://github.com/intelxed/xed/issues/281#issuecomment-970074554) if (dest == index)
{ return ZYAN_FALSE;
}
}
return ZYAN_TRUE;
}
/** * Checks if operands and encoding-specific features from `ZydisEncoderRequest` match * encoder's instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * @param request A pointer to `ZydisEncoderRequest` struct. * * @return True if definition is compatible, false otherwise.
*/ static ZyanBool ZydisIsDefinitionCompatible(ZydisEncoderInstructionMatch *match, const ZydisEncoderRequest *request)
{
ZYAN_ASSERT(request->operand_count == match->base_definition->operand_count_visible);
match->operands = ZydisGetOperandDefinitions(match->base_definition);
if (!ZydisAreEvexFeaturesCompatible(match, request))
{ return ZYAN_FALSE;
} if (!ZydisAreMvexFeaturesCompatible(match, request))
{ return ZYAN_FALSE;
}
for (ZyanU8 i = 0; i < request->operand_count; ++i)
{ const ZydisEncoderOperand *user_op = &request->operands[i]; const ZydisOperandDefinition *def_op = &match->operands[i];
ZYAN_ASSERT(def_op->visibility != ZYDIS_OPERAND_VISIBILITY_HIDDEN);
ZyanBool is_compatible = ZYAN_FALSE; switch (user_op->type)
{ case ZYDIS_OPERAND_TYPE_REGISTER:
is_compatible = ZydisIsRegisterOperandCompatible(match, user_op, def_op); break; case ZYDIS_OPERAND_TYPE_MEMORY:
is_compatible = ZydisIsMemoryOperandCompatible(match, user_op, def_op); break; case ZYDIS_OPERAND_TYPE_POINTER:
is_compatible = ZydisIsPointerOperandCompatible(match, user_op); break; case ZYDIS_OPERAND_TYPE_IMMEDIATE:
is_compatible = ZydisIsImmediateOperandCompabile(match, user_op, def_op); break; default:
ZYAN_UNREACHABLE;
}
if (!is_compatible)
{ return ZYAN_FALSE;
}
}
ZyanU8 eosz = 0; if (match->base_definition->branch_type != ZYDIS_BRANCH_TYPE_NONE)
{ switch (request->branch_width)
{ case ZYDIS_BRANCH_WIDTH_NONE: break; case ZYDIS_BRANCH_WIDTH_8: if ((!match->has_rel_operand) ||
(match->base_definition->branch_type != ZYDIS_BRANCH_TYPE_SHORT))
{ return ZYAN_FALSE;
} break; case ZYDIS_BRANCH_WIDTH_16:
eosz = 16; break; case ZYDIS_BRANCH_WIDTH_32:
eosz = ((match->has_rel_operand) &&
(match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
(match->base_definition->operand_size_map == ZYDIS_OPSIZE_MAP_FORCE64))
? 64
: 32; break; case ZYDIS_BRANCH_WIDTH_64: if (match->has_rel_operand)
{ return ZYAN_FALSE;
}
eosz = 64; break; default:
ZYAN_UNREACHABLE;
}
} if (eosz)
{ if (match->eosz != 0)
{ if (match->eosz != eosz)
{ return ZYAN_FALSE;
}
} else
{
match->eosz = eosz;
}
}
if (!ZydisCheckConstraints(match))
{ return ZYAN_FALSE;
}
return ZYAN_TRUE;
}
/** * Checks if requested set of prefixes is compatible with instruction definition. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return A zyan status code.
*/ static ZyanBool ZydisArePrefixesCompatible(const ZydisEncoderInstructionMatch *match)
{ // Early-exit optimization for when no prefixes are requested at all. if (!(match->attributes & ZYDIS_ENCODABLE_PREFIXES))
{ return ZYAN_TRUE;
}
if ((!match->base_definition->accepts_segment) &&
(match->attributes & ZYDIS_ATTRIB_HAS_SEGMENT))
{ return ZYAN_FALSE;
} if (match->definition->encoding != ZYDIS_INSTRUCTION_ENCODING_LEGACY)
{ return !(match->attributes & ZYDIS_ENCODABLE_PREFIXES_NO_SEGMENTS);
}
/** * Returns operand mask containing information about operand count and types in a compressed form. * * @param request A pointer to `ZydisEncoderRequest` struct. * * @return Operand mask.
*/ static ZyanU16 ZydisGetOperandMask(const ZydisEncoderRequest *request)
{
ZyanU16 operand_mask = request->operand_count;
ZyanU8 bit_offset = ZYAN_BITS_TO_REPRESENT(ZYDIS_ENCODER_MAX_OPERANDS); for (ZyanU8 i = 0; i < request->operand_count; ++i)
{
operand_mask |= (request->operands[i].type - ZYDIS_OPERAND_TYPE_REGISTER) << bit_offset;
bit_offset += ZYAN_BITS_TO_REPRESENT(
ZYDIS_OPERAND_TYPE_MAX_VALUE - ZYDIS_OPERAND_TYPE_REGISTER);
}
return operand_mask;
}
/** * Handles optimization opportunities indicated by `swappable` field in instruction definition * structure. See `ZydisEncodableInstruction` for more information. * * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return True if definition has been swapped, false otherwise.
*/ static ZyanBool ZydisHandleSwappableDefinition(ZydisEncoderInstructionMatch *match)
{ if (!match->definition->swappable)
{ return ZYAN_FALSE;
}
// Special case for ISA-wide unique conflict between two `mov` variants // mov gpr16_32_64(encoding=opcode), imm(encoding=simm16_32_64,scale_factor=osz) // mov gpr16_32_64(encoding=modrm_rm), imm(encoding=simm16_32_32,scale_factor=osz) if (match->request->mnemonic == ZYDIS_MNEMONIC_MOV)
{ const ZyanU8 imm_size = ZydisGetSignedImmSize(match->request->operands[1].imm.s); if ((match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
(match->eosz == 64) &&
(imm_size < 64))
{ return ZYAN_TRUE;
}
}
/** * This function attempts to find a matching instruction definition for provided encoder request. * * @param request A pointer to `ZydisEncoderRequest` struct. * @param match A pointer to `ZydisEncoderInstructionMatch` struct. * * @return A zyan status code.
*/ static ZyanStatus ZydisFindMatchingDefinition(const ZydisEncoderRequest *request,
ZydisEncoderInstructionMatch *match)
{
ZYAN_MEMSET(match, 0, sizeof(ZydisEncoderInstructionMatch));
match->request = request;
match->attributes = request->prefixes;
/** * Emits a single byte. * * @param byte Value to emit. * @param buffer A pointer to `ZydisEncoderBuffer` struct. * * @return A zyan status code.
*/ static ZyanStatus ZydisEmitByte(ZyanU8 byte, ZydisEncoderBuffer *buffer)
{ return ZydisEmitUInt(byte, 1, buffer);
}
/** * Emits legact prefixes. * * @param instruction A pointer to `ZydisEncoderInstruction` struct. * @param buffer A pointer to `ZydisEncoderBuffer` struct. * * @return A zyan status code.
*/ static ZyanStatus ZydisEmitLegacyPrefixes(const ZydisEncoderInstruction *instruction,
ZydisEncoderBuffer *buffer)
{
ZyanBool compressed_prefixes = ZYAN_FALSE; switch (instruction->encoding)
{ case ZYDIS_INSTRUCTION_ENCODING_XOP: case ZYDIS_INSTRUCTION_ENCODING_VEX: case ZYDIS_INSTRUCTION_ENCODING_EVEX: case ZYDIS_INSTRUCTION_ENCODING_MVEX:
compressed_prefixes = ZYAN_TRUE; break; default: break;
}
// Group 1 if (instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK)
{
ZYAN_CHECK(ZydisEmitByte(0xF0, buffer));
} if (!compressed_prefixes)
{ if (instruction->attributes & (ZYDIS_ATTRIB_HAS_REPNE |
ZYDIS_ATTRIB_HAS_BND |
ZYDIS_ATTRIB_HAS_XACQUIRE))
{
ZYAN_CHECK(ZydisEmitByte(0xF2, buffer));
} if (instruction->attributes & (ZYDIS_ATTRIB_HAS_REP |
ZYDIS_ATTRIB_HAS_REPE |
ZYDIS_ATTRIB_HAS_XRELEASE))
{
ZYAN_CHECK(ZydisEmitByte(0xF3, buffer));
}
}
// Group 2 if (instruction->attributes & (ZYDIS_ATTRIB_HAS_SEGMENT_CS |
ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN))
{
ZYAN_CHECK(ZydisEmitByte(0x2E, buffer));
} if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS)
{
ZYAN_CHECK(ZydisEmitByte(0x36, buffer));
} if (instruction->attributes & (ZYDIS_ATTRIB_HAS_SEGMENT_DS |
ZYDIS_ATTRIB_HAS_BRANCH_TAKEN))
{
ZYAN_CHECK(ZydisEmitByte(0x3E, buffer));
} if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_ES)
{
ZYAN_CHECK(ZydisEmitByte(0x26, buffer));
} if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_FS)
{
ZYAN_CHECK(ZydisEmitByte(0x64, buffer));
} if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_GS)
{
ZYAN_CHECK(ZydisEmitByte(0x65, buffer));
} if (instruction->attributes & ZYDIS_ATTRIB_HAS_NOTRACK)
{
ZYAN_CHECK(ZydisEmitByte(0x3E, buffer));
}
// Group 3 if (!compressed_prefixes)
{ if (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE)
{
ZYAN_CHECK(ZydisEmitByte(0x66, buffer));
}
}
// Group 4 if (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE)
{
ZYAN_CHECK(ZydisEmitByte(0x67, buffer));
}
return ZYAN_STATUS_SUCCESS;
}
/** * Encodes low nibble of `REX` prefix. * * @param instruction A pointer to `ZydisEncoderInstruction` struct. * @param high_r A pointer to `ZyanBool` variable that will be set to true when the * highest `ModR/M.reg` bit cannot be encoded using `REX` prefix. * * @return A zyan status code.
*/ static ZyanU8 ZydisEncodeRexLowNibble(const ZydisEncoderInstruction *instruction, ZyanBool *high_r)
{ if (high_r)
{
*high_r = ZYAN_FALSE;
}
ZyanU8 rex = 0; if ((instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM) &&
(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB))
{ if (instruction->base & 0x08)
{
rex |= 1;
} if (instruction->index & 0x08)
{
rex |= 2;
} if (instruction->reg & 0x08)
{
rex |= 4;
} if (high_r && (instruction->reg & 0x10))
{
*high_r = ZYAN_TRUE;
}
} elseif (instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM)
{ if (instruction->rm & 0x08)
{
rex |= 1;
} if (instruction->rm & 0x10)
{
rex |= 2;
} if (instruction->reg & 0x08)
{
rex |= 4;
} if (high_r && (instruction->reg & 0x10))
{
*high_r = ZYAN_TRUE;
}
} else
{ if (instruction->rm & 0x08)
{
rex |= 1;
}
}
if (instruction->rex_w)
{
rex |= 8;
}
return rex;
}
/** * Emits `REX` prefix. * * @param instruction A pointer to `ZydisEncoderInstruction` struct. * @param buffer A pointer to `ZydisEncoderBuffer` struct. * * @return A zyan status code.
*/ static ZyanStatus ZydisEmitRex(const ZydisEncoderInstruction *instruction,
ZydisEncoderBuffer *buffer)
{ const ZyanU8 rex = ZydisEncodeRexLowNibble(instruction, ZYAN_NULL); if (rex || (instruction->attributes & ZYDIS_ATTRIB_HAS_REX))
{
ZYAN_CHECK(ZydisEmitByte(0x40 | rex, buffer));
}
return ZYAN_STATUS_SUCCESS;
}
/** * Encodes common parts of `VEX` prefix. * * @param instruction A pointer to `ZydisEncoderInstruction` struct. * @param mmmmm A pointer to `ZyanU8` variable that will receive `VEX.mmmmm` * @param pp A pointer to `ZyanU8` variable that will receive `VEX.pp` * @param vvvv A pointer to `ZyanU8` variable that will receive `VEX.vvvv` * @param rex A pointer to `ZyanU8` variable that will receive 'REX` * @param high_r A pointer to `ZyanBool` variable that will be set to true when the * highest `ModR/M.reg` bit cannot be encoded using `REX` prefix.
*/ staticvoid ZydisEncodeVexCommons(ZydisEncoderInstruction *instruction, ZyanU8 *mmmmm, ZyanU8 *pp,
ZyanU8 *vvvv, ZyanU8 *rex, ZyanBool *high_r)
{ switch (instruction->opcode_map)
{ case ZYDIS_OPCODE_MAP_DEFAULT: case ZYDIS_OPCODE_MAP_0F: case ZYDIS_OPCODE_MAP_0F38: case ZYDIS_OPCODE_MAP_0F3A: case ZYDIS_OPCODE_MAP_MAP5: case ZYDIS_OPCODE_MAP_MAP6:
*mmmmm = (ZyanU8)instruction->opcode_map; break; case ZYDIS_OPCODE_MAP_XOP8: case ZYDIS_OPCODE_MAP_XOP9: case ZYDIS_OPCODE_MAP_XOPA:
*mmmmm = 8 + ((ZyanU8)instruction->opcode_map - ZYDIS_OPCODE_MAP_XOP8); break; default:
ZYAN_UNREACHABLE;
}
instruction->opcode_map = ZYDIS_OPCODE_MAP_DEFAULT;
switch (match->request->mvex.rounding)
{ case ZYDIS_ROUNDING_MODE_INVALID: break; case ZYDIS_ROUNDING_MODE_RN: case ZYDIS_ROUNDING_MODE_RD: case ZYDIS_ROUNDING_MODE_RU: case ZYDIS_ROUNDING_MODE_RZ:
instruction->sss |= match->request->mvex.rounding - ZYDIS_ROUNDING_MODE_RN; break; default:
ZYAN_UNREACHABLE;
}
switch (match->request->mvex.swizzle)
{ case ZYDIS_SWIZZLE_MODE_INVALID: break; case ZYDIS_SWIZZLE_MODE_DCBA: case ZYDIS_SWIZZLE_MODE_CDAB: case ZYDIS_SWIZZLE_MODE_BADC: case ZYDIS_SWIZZLE_MODE_DACB: case ZYDIS_SWIZZLE_MODE_AAAA: case ZYDIS_SWIZZLE_MODE_BBBB: case ZYDIS_SWIZZLE_MODE_CCCC: case ZYDIS_SWIZZLE_MODE_DDDD:
instruction->sss |= match->request->mvex.swizzle - ZYDIS_SWIZZLE_MODE_DCBA; break; default:
ZYAN_UNREACHABLE;
}
if ((match->request->mvex.sae) ||
(match->request->mvex.eviction_hint) ||
(match->request->mvex.rounding != ZYDIS_ROUNDING_MODE_INVALID))
{
instruction->eviction_hint = ZYAN_TRUE;
} if (match->request->mvex.sae)
{
instruction->sss |= 4;
}
// Following instructions violate general `MVEX.EH` handling rules. In all other cases this // bit is used either as eviction hint (memory operands present) or to encode MVEX-specific // functionality (register forms). Instructions listed below use `MVEX.EH` to identify // different instructions with memory operands and don't treat it as eviction hint. switch (match->request->mnemonic)
{ case ZYDIS_MNEMONIC_VMOVNRAPD: case ZYDIS_MNEMONIC_VMOVNRAPS:
instruction->eviction_hint = ZYAN_FALSE; break; case ZYDIS_MNEMONIC_VMOVNRNGOAPD: case ZYDIS_MNEMONIC_VMOVNRNGOAPS:
instruction->eviction_hint = ZYAN_TRUE; break; default: break;
}
}
switch (match->definition->mandatory_prefix)
{ case ZYDIS_MANDATORY_PREFIX_NONE: break; case ZYDIS_MANDATORY_PREFIX_66:
instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE; break; case ZYDIS_MANDATORY_PREFIX_F2:
instruction->attributes |= ZYDIS_ATTRIB_HAS_REPNE; break; case ZYDIS_MANDATORY_PREFIX_F3:
instruction->attributes |= ZYDIS_ATTRIB_HAS_REP; break; default:
ZYAN_UNREACHABLE;
}
const ZyanU8 mode_width = ZydisGetMachineModeWidth(match->request->machine_mode); if (match->easz != mode_width)
{
instruction->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE;
} if ((match->request->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
(match->base_definition->operand_size_map != ZYDIS_OPSIZE_MAP_FORCE64))
{ switch (match->eosz)
{ case 16:
instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE; break; case 32: break; case 64:
instruction->rex_w =
match->base_definition->operand_size_map != ZYDIS_OPSIZE_MAP_DEFAULT64; break; default:
ZYAN_UNREACHABLE;
}
} else
{ if (match->eosz != mode_width)
{
instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
}
}
for (ZyanU8 i = 0; i < request->operand_count; ++i)
{ const ZydisEncoderOperand *op = &request->operands[i]; if ((op->type == ZYDIS_OPERAND_TYPE_UNUSED) ||
((ZyanUSize)op->type > ZYDIS_OPERAND_TYPE_MAX_VALUE))
{ return ZYAN_STATUS_INVALID_ARGUMENT;
}
switch (op->type)
{ case ZYDIS_OPERAND_TYPE_REGISTER: if (op->reg.value > ZYDIS_REGISTER_MAX_VALUE)
{ return ZYAN_STATUS_INVALID_ARGUMENT;
} break; case ZYDIS_OPERAND_TYPE_MEMORY: if (((ZyanUSize)op->mem.base > ZYDIS_REGISTER_MAX_VALUE) ||
((ZyanUSize)op->mem.index > ZYDIS_REGISTER_MAX_VALUE) ||
!ZydisIsScaleValid(op->mem.scale))
{ return ZYAN_STATUS_INVALID_ARGUMENT;
} break; case ZYDIS_OPERAND_TYPE_POINTER: case ZYDIS_OPERAND_TYPE_IMMEDIATE: break; default: return ZYAN_STATUS_INVALID_ARGUMENT;
}
}
return ZYAN_STATUS_SUCCESS;
}
/** * Encodes instruction with semantics specified in encoder request structure. * * @param request A pointer to the `ZydisEncoderRequest` struct. Must be validated before * calling this function. * @param buffer A pointer to the output buffer receiving encoded instruction. * @param length A pointer to the variable containing length of the output buffer. Upon * successful return this variable receives length of the encoded instruction. * @param instruction Internal state of the encoder. * * @return A zyan status code.
*/ static ZyanStatus ZydisEncoderEncodeInstructionInternal(const ZydisEncoderRequest *request, void *buffer, ZyanUSize *length, ZydisEncoderInstruction *instruction)
{
ZydisEncoderInstructionMatch match;
ZYAN_CHECK(ZydisFindMatchingDefinition(request, &match));
ZydisEncoderBuffer output;
output.buffer = (ZyanU8 *)buffer;
output.size = *length;
output.offset = 0;
ZYAN_CHECK(ZydisBuildInstruction(&match, instruction));
ZYAN_CHECK(ZydisEmitInstruction(instruction, &output));
*length = output.offset; return ZYAN_STATUS_SUCCESS;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.