* 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;
}
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.