void NaClJumpValidator(NaClValidatorState* vstate) { NaClRememberInstructionBoundary(vstate, vstate->cur_inst_state); if (vstate->cur_inst->flags & (NACL_IFLAG(JumpInstruction) | NACL_IFLAG(ConditionalJump))) { NaClAddExprJumpTarget(vstate); if (vstate->cur_inst->name == InstCall) { NaClValidateCallAlignment(vstate); } } }
/* Inspect the parsed instruction to print out the opcode sequence matched. */ static void NaClInstPrintOpcodeSeq(struct Gio* gout, const NaClInstState* state) { size_t count = 0; if (state->num_opcode_bytes == 0) { /* Hard coded bytes sequence for instruction. */ gprintf(gout, " %s", kHardCodedMessage); count = strlen(kHardCodedMessage) + 2; } else { /* Modeled instruction. Pull out parsed opcode bytes from parsed * instruction. */ int i; gprintf(gout, " "); count = 1; /* Add prefix selector if applicable. */ if (state->opcode_prefix) { gprintf(gout, " %02x", state->opcode_prefix); count += 3; } /* Add opcode bytes. */ for (i = 0; i < state->num_opcode_bytes; ++i) { gprintf(gout, " %02x", state->bytes.byte[state->num_prefix_bytes + i]); count += 3; } if (state->inst->flags & NACL_IFLAG(OpcodeInModRm)) { gprintf(gout, " / %d", modrm_opcode(state->modrm)); count += 4; } else if (state->inst->flags & NACL_IFLAG(OpcodePlusR)) { gprintf(gout, " - r%d", NaClGetOpcodePlusR(state->inst->opcode_ext)); count += 5; } if (state->inst->flags & NACL_IFLAG(OpcodeInModRmRm)) { gprintf(gout, " / %d", modrm_rm(state->modrm)); count += 4; } /* Add opcode for 0f0f instructions, where the opcode is the last * byte of the instruction. */ if ((state->num_opcode_bytes >= 2) && (0 == (state->inst->flags & NACL_IFLAG(Opcode0F0F))) && (0x0F == state->bytes.byte[state->num_prefix_bytes]) && (0x0F == state->bytes.byte[state->num_prefix_bytes + 1])) { gprintf(gout, " %02x", state->bytes.byte[state->bytes.length - 1]); count += 3; } } while (count < 30) { gprintf(gout, " "); ++count; } }
void NaClAddRepPrefixFlagsIfApplicable() { if (NaClInInstructionSet(kAllowableRepMnemonic, NACL_ARRAY_SIZE(kAllowableRepMnemonic), kAllowableRepMnemonicOpseq, NACL_ARRAY_SIZE(kAllowableRepMnemonicOpseq))) { NaClAddIFlags(NACL_IFLAG(OpcodeAllowsRep)); } if (NaClInInstructionSet(kAllowableRepneMnemonic, NACL_ARRAY_SIZE(kAllowableRepneMnemonic), NULL, 0)) { NaClAddIFlags(NACL_IFLAG(OpcodeAllowsRepne)); } }
/* Given an operand of the corresponding opcode instruction of the * given state, return what kind of register should be used, based * on the operand size. */ static NaClRegKind NaClExtractOpRegKind(NaClInstState* state, const NaClOp* operand) { NaClRegKind reg_kind = NaClGetOpKindRegKind(operand->kind); switch (reg_kind) { case RegSize8: case RegSize16: case RegSize32: case RegSize64: return reg_kind; case RegSizeZ: if (state->operand_size == 2) { return RegSize16; } else { return RegSize32; } default: /* Size not explicitly defined, pick up from operand size. */ if (state->inst->flags & NACL_IFLAG(OperandSize_b)) { return RegSize8; } else if (state->operand_size == 1) { return RegSize8; } else if (state->operand_size == 4) { return RegSize32; } else if (state->operand_size == 2) { return RegSize16; } else if (state->operand_size == 8) { return RegSize64; } else { return RegSize32; } } }
/* TODO(kschimpf): Delete this function if unneeded. */ static void NaClDefX87MrmNoOperands(const NaClInstPrefix prefix, const uint8_t opcode, const NaClOpKind opcode_in_modrm, const NaClMnemonic mnemonic) { NaClDefInstPrefix(prefix); NaClDefInst(opcode, NACLi_X87, NACL_IFLAG(OpcodeInModRm), mnemonic); NaClDefOp(opcode_in_modrm, NACL_OPFLAG(OperandExtendsOpcode)); NaClResetToDefaultInstPrefix(); }
/* Define an x87 instruction that has two operands, a memory pointer * and st0, and the memory pointer is defined by the value of st0. */ static void NaClDefX87LtC0MoveMemSt0(const NaClInstPrefix prefix, const uint8_t opcode, const NaClOpKind opcode_in_modrm, const NaClMnemonic mnemonic) { NaClDefInstPrefix(prefix); NaClDefInst(opcode, NACLi_X87, NACL_IFLAG(OpcodeLtC0InModRm), mnemonic); NaClDefOp(opcode_in_modrm, NACL_OPFLAG(OperandExtendsOpcode)); NaClDefOp(M_Operand, NACL_OPFLAG(OpSet)); NaClDefOp(RegST0, NACL_OPFLAG(OpUse)); NaClResetToDefaultInstPrefix(); }
/* Define an x87 instruction that uses a single memory pointer. */ static void NaClDefX87LtC0Mem(const NaClInstPrefix prefix, const uint8_t opcode, const NaClOpKind opcode_in_modrm, const NaClMnemonic mnemonic, const NaClOpFlags mfp_flags) { NaClDefInstPrefix(prefix); NaClDefInst(opcode, NACLi_X87, NACL_IFLAG(OpcodeLtC0InModRm), mnemonic); NaClDefOp(opcode_in_modrm, NACL_OPFLAG(OperandExtendsOpcode)); NaClDefOp(M_Operand, mfp_flags); NaClResetToDefaultInstPrefix(); }
/* TODO(kschimpf): Delete this function if unneeded. */ static void BrokenOldDefineX87St0(const NaClInstPrefix prefix, const uint8_t opcode, const NaClOpKind opcode_in_modrm, NaClMnemonic mnemonic, const NaClOpFlags st0_flags) { NaClDefInstPrefix(prefix); NaClDefInst(opcode, NACLi_X87, NACL_IFLAG(OpcodeInModRm), mnemonic); NaClDefOp(opcode_in_modrm, NACL_OPFLAG(OperandExtendsOpcode)); NaClDefOp(RegST0, st0_flags); NaClResetToDefaultInstPrefix(); }
/* Define an x87 instruction that updates sti, based on its previous value. */ static void NaClDefX87Sti(const NaClInstPrefix prefix, const uint8_t opcode, const int base_offset, const NaClMnemonic mnemonic, const NaClOpFlags sti_flags) { NaClDefInstPrefix(prefix); NaClDefInst(opcode + base_offset, NACLi_X87, NACL_IFLAG(OpcodePlusR), mnemonic); NaClDefOp(OpcodeBaseMinus0 + base_offset, NACL_OPFLAG(OperandExtendsOpcode)); NaClDefOp(St_Operand, sti_flags); NaClResetToDefaultInstPrefix(); }
/* Define an x87 binary instruction that has sti as its first argument, * and st0 as its second argument. */ static void NaClDefX87BinopStiSt0(const NaClInstPrefix prefix, const uint8_t opcode, const int base_offset, const NaClMnemonic mnemonic) { NaClDefInstPrefix(prefix); NaClDefInst(opcode + base_offset, NACLi_X87, NACL_IFLAG(OpcodePlusR), mnemonic); NaClDefOp(OpcodeBaseMinus0 + base_offset, NACL_OPFLAG(OperandExtendsOpcode)); NaClDefOp(St_Operand, NACL_OPFLAG(OpSet) | NACL_OPFLAG(OpUse)); NaClDefOp(RegST0, NACL_OPFLAG(OpUse)); NaClResetToDefaultInstPrefix(); }
/* Print instruction flags using a simplified (i.e. more human readable) form */ void NaClIFlagsPrint(struct Gio* f, NaClIFlags flags) { int i; Bool first = TRUE; for (i = 0; i < NaClIFlagEnumSize; ++i) { if (flags & NACL_IFLAG(i)) { if (first) { first = FALSE; } else { gprintf(f, " "); } gprintf(f, "%s", NaClIFlagName(i)); } } }
/* Add OperandZeroExtends_v to instruction, if it can hold * a 32 bit operand. */ static void AddZeroExtendToOpDestArgs(NaClModeledInst* inst) { if (inst->flags & NACL_IFLAG(OperandSize_v)) { int i; for (i = 0; i < inst->num_operands; ++i) { /* Note: we currently don't allow zero extends for * implicit arguments. This is done just to be extra * cautious on what we allow to be masks in the * NaCl x64-64 validator. */ if ((inst->operands[i].flags & NACL_OPFLAG(OpSet)) && (NACL_EMPTY_OPFLAGS == (inst->operands[i].flags & NACL_OPFLAG(OpImplicit)))) { NaClAddOpFlags(i, NACL_OPFLAG(OperandZeroExtends_v)); } } } }
static void NaCl3DNow0F0FInsts(struct NaClSymbolTable* st) { /* All 3DNOW instructions of form: 0f 0f [modrm] [sib] [displacement] * imm8_opcode * * These instructions encode into "OP Pq, Qq", based on the value of * imm8_opcode. We decode these instructions in two steps. The first * step uses a OF0F instruction to read in the bytes of the instruction. * These bytes are then inspected, and is replaced by the corresponding * 3DNOW instruction in the OFOF prefix table. If no such entry is found, * The original match is left so that the bytes are marked as an * invalid 3dnow instruction. * * Note: 3DNow instructions are defined in document 21928G/0-March 2000: * "3DNow!(TM) Technology Manual". */ NaClBegDef(" 0f0f: Invalid $Pq, $Qq, $Ib", NACLi_INVALID, st); NaClAddIFlags(NACL_IFLAG(Opcode0F0F)); NaClEndDef( Other); NaClDefine(" 0f0f..0c: Pi2fw $Pq, $Qq", NACLi_E3DNOW, st, Move); NaClDefine(" 0f0f..0d: Pi2fd $Pq, $Qq", NACLi_3DNOW, st, Move); NaClDefine(" 0f0f..1c: Pf2iw $Pq, $Qq", NACLi_E3DNOW, st, Move); NaClDefine(" 0f0f..1d: Pf2id $Pq, $Qq", NACLi_3DNOW, st, Move); NaClDefine(" 0f0f..8a: Pfnacc $Pq, $Qq", NACLi_E3DNOW, st, Binary); NaClDefine(" 0f0f..8e: Pfpnacc $Pq, $Qq", NACLi_E3DNOW, st, Binary); NaClDefine(" 0f0f..90: Pfcmpge $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..94: Pfmin $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..96: Pfrcp $Pq, $Qq", NACLi_3DNOW, st, Move); NaClDefine(" 0f0f..97: Pfrsqrt $Pq, $Qq", NACLi_3DNOW, st, Move); NaClDefine(" 0f0f..9a: Pfsub $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..9e: Pfadd $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..a0: Pfcmpgt $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..a4: Pfmax $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..a6: Pfrcpit1 $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..a7: Pfrsqit1 $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..aa: Pfsubr $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..ae: Pfacc $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..b0: Pfcmpeq $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..b4: Pfmul $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..b6: Pfrcpit2 $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..b7: Pmulhrw $Pq, $Qq", NACLi_3DNOW, st, Binary); NaClDefine(" 0f0f..bb: Pswapd $Pq, $Qq", NACLi_E3DNOW, st, Move); NaClDefine(" 0f0f..bf: Pavgusb $Pq, $Qq", NACLi_3DNOW, st, Binary); }
/* Print the given instruction opcode of the give state, to the * given file. */ static void NaClPrintDisassembled(struct Gio* file, NaClInstState* state, const NaClInst* inst) { uint32_t tree_index = 0; Bool is_first = TRUE; Bool not_printed_prefix_segment = TRUE; NaClExp* node; NaClExpVector* vector = NaClInstStateExpVector(state); /* Print the name of the instruction. */ if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) { /* Instruction has been simplified. Print out corresponding * hints to the reader, so that they know that the instruction * has been simplified. */ gprintf(file, "[P] "); NaClPrintLower(file, (char*) NaClMnemonicName(inst->name)); if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) { gprintf(file, "(illegal)"); } } else { NaClPrintLower(file, (char*) NaClMnemonicName(inst->name)); } /* Use the generated expression tree to print out (non-implicit) operands * of the instruction. */ while (tree_index < vector->number_expr_nodes) { node = &vector->node[tree_index]; if (node->kind != OperandReference || (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) { if (is_first) { gprintf(file, " "); is_first = FALSE; } else { gprintf(file, ", "); } NaClPrintDisassembledExp(file, state, tree_index); /* If this is a partial instruction, add set/use information * so that that it is more clear what was matched. */ if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) && node->kind == OperandReference) { const NaClOp* op = NaClGetInstOperandInline(state->decoder_tables, inst, (uint8_t) NaClGetExprUnsignedValue(node)); if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) | NACL_OPFLAG(OpUse) | NACL_OPFLAG(OperandZeroExtends_v)))) { gprintf(file, " ("); NaClPrintAddOperandFlag(file, op, OpSet, "s"); NaClPrintAddOperandFlag(file, op, OpUse, "u"); NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z"); gprintf(file, ")"); } } } else if (not_printed_prefix_segment && (OperandReference == node->kind) && (node->flags & NACL_EFLAG(ExprImplicit))) { /* Print out segment override of implicit segment address, if * applicable. */ if (OperandReference == node->kind) { int seg_addr_index = tree_index + 1; if (ExprSegmentAddress == vector->node[seg_addr_index].kind) { if (NaClHasSegmentOverride(vector, seg_addr_index, ExprDSrCase, RegDS)) { NaClPrintSegmentOverride(file, &is_first, state, vector, seg_addr_index); } else if (NaClHasSegmentOverride(vector, seg_addr_index, ExprESrCase, RegES)) { NaClPrintSegmentOverride(file, &is_first, state, vector, seg_addr_index); } } } } /* Skip over expression to next expresssion. */ tree_index += NaClExpWidth(vector, tree_index); } }
static void NaClAddJumpFlags(NaClIFlag flag, const NaClMnemonic* name, size_t name_size) { if (NaClInInstructionSet(name, name_size, NULL, 0)) { NaClGetDefInst()->flags |= NACL_IFLAG(flag); } }
/* Add LongMode instruction flag if applicable. */ void NaClAddLongModeIfApplicable() { if (NaClInInstructionSet(kLongModeOp, NACL_ARRAY_SIZE(kLongModeOp), NULL, 0)) { NaClAddIFlags(NACL_IFLAG(LongMode)); } }
void NaClCpuCheck(struct NaClValidatorState* state, struct NaClInstIter* iter) { Bool squash_me = FALSE; switch (state->cur_inst->insttype) { case NACLi_X87: case NACLi_X87_FSINCOS: NaClCheckFeature(NaClCPUFeatureX86_x87, state, &squash_me); break; case NACLi_SFENCE_CLFLUSH: /* TODO(bradchen): distinguish between SFENCE and CLFLUSH */ NaClCheckFeature(NaClCPUFeatureX86_CLFLUSH, state, &squash_me); NaClCheckFeature(NaClCPUFeatureX86_FXSR, state, &squash_me); break; case NACLi_CMPXCHG8B: NaClCheckFeature(NaClCPUFeatureX86_CX8, state, &squash_me); break; case NACLi_CMPXCHG16B: NaClCheckFeature(NaClCPUFeatureX86_CX16, state, &squash_me); break; case NACLi_CMOV: NaClCheckFeature(NaClCPUFeatureX86_CMOV, state, &squash_me); break; case NACLi_FCMOV: if (!(NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_CMOV) && NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_x87))) { if (!state->cpu_checks.f_CMOV_and_x87) { NaClValidatorInstMessage( LOG_WARNING, state, state->cur_inst_state, "CPU model does not support CMOV and x87 instructions.\n"); state->cpu_checks.f_CMOV_and_x87 = TRUE; } squash_me = TRUE; } break; case NACLi_RDTSC: NaClCheckFeature(NaClCPUFeatureX86_TSC, state, &squash_me); break; case NACLi_MMX: NaClCheckFeature(NaClCPUFeatureX86_MMX, state, &squash_me); break; case NACLi_MMXSSE2: /* Note: We accept these instructions if either MMX or SSE2 bits */ /* are set, in case MMX instructions go away someday... */ if (!(NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_MMX) || NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_SSE2))) { if (!state->cpu_checks.f_MMX_or_SSE2) { NaClValidatorInstMessage( LOG_WARNING, state, state->cur_inst_state, "CPU model does not support MMX or SSE2 instructions.\n"); state->cpu_checks.f_MMX_or_SSE2 = TRUE; } } squash_me = TRUE; break; case NACLi_SSE: NaClCheckFeature(NaClCPUFeatureX86_SSE, state, &squash_me); break; case NACLi_SSE2: NaClCheckFeature(NaClCPUFeatureX86_SSE2, state, &squash_me); break; case NACLi_SSE3: NaClCheckFeature(NaClCPUFeatureX86_SSE3, state, &squash_me); break; case NACLi_SSE4A: NaClCheckFeature(NaClCPUFeatureX86_SSE4A, state, &squash_me); break; case NACLi_SSE41: NaClCheckFeature(NaClCPUFeatureX86_SSE41, state, &squash_me); break; case NACLi_SSE42: NaClCheckFeature(NaClCPUFeatureX86_SSE42, state, &squash_me); break; case NACLi_MOVBE: NaClCheckFeature(NaClCPUFeatureX86_MOVBE, state, &squash_me); break; case NACLi_POPCNT: NaClCheckFeature(NaClCPUFeatureX86_POPCNT, state, &squash_me); break; case NACLi_LZCNT: NaClCheckFeature(NaClCPUFeatureX86_LZCNT, state, &squash_me); break; case NACLi_SSSE3: NaClCheckFeature(NaClCPUFeatureX86_SSSE3, state, &squash_me); break; case NACLi_3DNOW: NaClCheckFeature(NaClCPUFeatureX86_3DNOW, state, &squash_me); break; case NACLi_E3DNOW: NaClCheckFeature(NaClCPUFeatureX86_E3DNOW, state, &squash_me); break; case NACLi_LONGMODE: /* TODO(karl): Remove this when NACLi_LONGMODE is no longer needed */ NaClCheckFeature(NaClCPUFeatureX86_LM, state, &squash_me); break; case NACLi_SSE2x: /* This case requires CPUID checking code */ /* DATA16 prefix required */ if (!(state->cur_inst_state->prefix_mask & kPrefixDATA16)) { NaClValidatorInstMessage( LOG_ERROR, state, state->cur_inst_state, "SSEx instruction must use prefix 0x66.\n"); } NaClCheckFeature(NaClCPUFeatureX86_SSE2, state, &squash_me); break; default: /* This instruction could be either legal or illegal, but if we * get here it is not CPU-dependent. */ break; } if (state->cur_inst->flags & NACL_IFLAG(LongMode)) { NaClCheckFeature(NaClCPUFeatureX86_LM, state, &squash_me); } if (squash_me) { if (state->readonly_text) { NaClValidatorInstMessage( LOG_ERROR, state, state->cur_inst_state, "Read-only text: cannot squash unsupported instruction.\n"); } else { /* Replace all bytes of the instruction with the HLT instruction. */ NCStubOutMem(state, NaClInstIterGetInstMemoryInline(iter), NaClInstStateLength(state->cur_inst_state)); } } }
static void NaClInstLayoutCheck(NaClValidatorState* vstate) { NaClPcAddress start; NaClPcAddress end; NaClPcAddress i; if (NULL == vstate->cur_inst_state) return; DEBUG(NaClLog(LOG_INFO, "Jump layout check: "); NaClInstStateInstPrint(NaClLogGetGio(), vstate->cur_inst_state)); /* Check basic block boundaries. */ start = vstate->cur_inst_state->inst_addr; /* Check that if first instruction in a basic block, it isn't in the * middle of a pattern. */ if ((0 == (start & vstate->bundle_mask)) && NaClAddressSetContains(vstate->jump_sets.removed_targets, start, vstate)) { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Instruction begins basic block, but in middle of nacl pattern\n"); } /* Check that instruction doesn't cross block boundaries. */ end = (NaClPcAddress) (start + vstate->cur_inst_state->bytes.length); for (i = start + 1; i < end; ++i) { if (0 == (i & vstate->bundle_mask)) { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Instruction crosses basic block alignment\n"); } } /* Check jump targets. */ if (NaClHasBit(vstate->cur_inst_state->inst->flags, NACL_IFLAG(JumpInstruction) | NACL_IFLAG(ConditionalJump))) { uint32_t i; NaClExpVector* vector = NaClInstStateExpVector(vstate->cur_inst_state); for (i = 0; i < vector->number_expr_nodes; ++i) { NaClExp* node = &vector->node[i]; if (NaClHasBit(node->flags, NACL_EFLAG(ExprJumpTarget)) && node->kind == ExprConstant) { /* Explicit jump value. Check if legal! */ NaClPcAddress target = end + (NaClPcNumber) NaClGetExprSignedValue(node); /* Don't report targets that are out of range. They should have * been reported in the first pass! */ if (NaClCheckAddressRange(target, vstate)) { if (NaClAddressSetContains(vstate->jump_sets.possible_targets, target, vstate)) { if (NaClAddressSetContains(vstate->jump_sets.removed_targets, target, vstate)) { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Jumps into middle of nacl pattern\n"); } } else { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Doesn't jump to instruction address\n"); } } } } } }
void NaClDef0FInsts(struct NaClSymbolTable* st) { int i; NaClDefPrefixInstMrmChoices(Prefix0F, 0x01, 1, 4); NaClDefPrefixInstMrmChoices(Prefix0F, 0x01, 3, 9); NaClDefPrefixInstMrmChoices_32_64(Prefix0F, 0x01, 7, 2, 4); NaClDefPrefixInstMrmChoices_32_64(Prefix0F, 0xc7, 1, 1, 2); NaClDefPrefixInstMrmChoices(Prefix0F, 0xae, 5, 8); NaClDefPrefixInstMrmChoices(Prefix0F, 0xae, 6, 8); NaClDefPrefixInstMrmChoices(Prefix0F, 0xae, 7, 9); NaClDefine(" 0f00/0: Sldt $Mw/Rv", NACLi_SYSTEM, st, Sets); NaClDefine(" 0f00/1: Str $Mw/Rv", NACLi_SYSTEM, st, Sets); NaClDefine(" 0f00/2: Lldt $Ew", NACLi_SYSTEM, st, Uses); NaClDefine(" 0f00/3: Ltr $Ew", NACLi_SYSTEM, st, Uses); NaClDefine(" 0f00/4: Verr $Ew", NACLi_SYSTEM, st, Other); NaClDefine(" 0f00/5: Verw $Ew", NACLi_SYSTEM, st, Other); NaClDefIter(" 0f00/@i: Invalid", 6, 7, NACLi_INVALID, st, Other); NaClDefine(" 0f01/0: Sgdt $Ms", NACLi_SYSTEM, st, Sets); NaClDefine(" 0f01/1: Sidt $Ms", NACLi_SYSTEM, st, Sets); NaClDefine(" 0f01/1/0: Monitor %reax, %ecx, %edx", NACLi_SYSTEM, st, Uses); NaClDefine(" 0f01/1/1: Mwait %eax, %ecx", NACLi_SYSTEM, st, Other); NaClDefine(" 0f01/1: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0f01/2: Lgdt $Ms", NACLi_SYSTEM, st, Uses); NaClDefine(" 0f01/3: Lidt $Ms", NACLi_SYSTEM, st, Uses); NaClDef_64(" 0f01/3/0: Vmrun $rAXva", NACLi_SVM, st, Uses); NaClDefine(" 0f01/3/1: Vmmcall", NACLi_SVM, st, Other); NaClDefine(" 0f01/3/2: Vmload $rAXva", NACLi_SVM, st, Uses); NaClDefine(" 0f01/3/3: Vmsave $rAXva", NACLi_SVM, st, Uses); NaClDefine(" 0f01/3/4: Stgi", NACLi_SVM, st, Other); NaClDefine(" 0f01/3/5: Clgi", NACLi_SVM, st, Other); NaClDefine(" 0f01/3/6: Skinit {%eip}, %eax", NACLi_SVM, st, Jump); NaClDefine(" 0f01/3/7: Invlpga $rAXva, %ecx", NACLi_SVM, st, Uses); NaClDef_32(" 0f01/3: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0f01/4: Smsw $Mw/Rv", NACLi_SYSTEM, st, Sets); NaClDefine(" 0f01/5: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0f01/6: Lmsw $Ew", NACLi_INVALID, st, Uses); NaClDefine(" 0f01/7: Invlpg $Mb", NACLi_SYSTEM, st, Uses); NaClDef_64(" 0f01/7/0: Swapgs {%gs}", NACLi_SYSTEM, st, Sets); NaClDef_64(" 0f01/7/1: Rdtscp {%rdx}, {%rax}, {%rcx}", NACLi_RDTSCP, st, Sets); NaClDefine(" 0f01/7: Invalid", NACLi_INVALID, st, Other); /* Note: Xed appears to use Ev for second argument for Lar aand Lsl. */ NaClDefine(" 0f02: Lar $Gv, $Ew", NACLi_SYSTEM, st, Other); NaClDefine(" 0f03: Lsl $Gv, $Ew", NACLi_SYSTEM, st, Other); NaClDefine(" 0f04: Invalid", NACLi_INVALID, st, Other); NaClDef_64(" 0f05: Syscall {%rip}, {%rcx}", NACLi_SYSCALL, st, SysCall); NaClDefine(" 0f06: Clts", NACLi_SYSTEM, st, Other); NaClDef_64(" 0f07: Sysret {%rip}, {%rcx}", NACLi_SYSTEM, st, SysRet); NaClDefine(" 0f08: Invd", NACLi_SYSTEM, st, Other); NaClDefine(" 0f09: Wbinvd", NACLi_SYSTEM, st, Other); NaClDefine(" 0f0a: Invalid", NACLi_INVALID, st, Other); /* Note: ud2 with no prefix bytes is currently understood as a NOP sequence. * The definition here only applies to cases where prefix bytes are added. */ NaClDefine(" 0f0b: Ud2", NACLi_386, st, Other); NaClDefine(" 0f0c: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0f0d/0: Prefetch_exclusive $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/1: Prefetch_modified $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/2: Prefetch_reserved $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/3: Prefetch_modified $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/4: Prefetch_reserved $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/5: Prefetch_reserved $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/6: Prefetch_reserved $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0d/7: Prefetch_reserved $Mb", NACLi_3DNOW, st, Other); NaClDefine(" 0f0e: Femms", NACLi_3DNOW, st, Other); NaCl3DNow0F0FInsts(st); NaClDefIter(" f20f13+@i: Invalid", 0, 4, NACLi_INVALID, st, Other); NaClDefine(" 0f18/0: Prefetchnta $Mb", NACLi_MMX, st, Other); NaClDefine(" 0f18/1: Prefetcht0 $Mb", NACLi_MMX, st, Other); NaClDefine(" 0f18/2: Prefetcht1 $Mb", NACLi_MMX, st, Other); NaClDefine(" 0f18/3: Prefetcht2 $Mb", NACLi_MMX, st, Other); /* The following 4 are reserved for future prefetch instructions. */ NaClDefIter(" 0f18/@i: Invalid", 4, 7, NACLi_INVALID, st, Other); NaClDefine(" 0f1f/0: Nop", NACLi_386, st, Other); NaClDefIter(" 0f19+@i/r: Nop", 0, 6, NACLi_386, st, Other); NaClDefine(" 0f20: Mov $Rd/q, $Cd/q", NACLi_SYSTEM, st, Move); NaClDefine(" 0f21: Mov $Rd/q, $Dd/q", NACLi_SYSTEM, st, Move); NaClDefine(" 0f22: Mov $Cd/q, $Rd/q", NACLi_SYSTEM, st, Move); NaClDefine(" 0f23: Mov $Dd/q, $Rd/q", NACLi_SYSTEM, st, Move); NaClDefIter(" 0f24+@i: Invalid", 0, 3, NACLi_INVALID, st, Other); NaClDefine(" 0f30: Wrmsr {%eax}, {%edx}, {%ecx}", NACLi_RDMSR, st, Uses); NaClDefine(" 0f31: Rdtsc {%eax}, {%edx}", NACLi_RDTSC, st, Sets); NaClDefine(" 0f32: Rdmsr {%eax}, {%edx}, {%ecx}", NACLi_RDMSR, st, O2Move); NaClDefine(" 0f33: Rdpmc {%eax}, {%edx}, {%ecx}", NACLi_SYSTEM, st, O2Move); NaClDefine(" 0f34: Sysenter {%eip}, {%esp}, {%cs}, {%ss}", NACLi_SYSENTER,st, SysJump); NaClDefine(" 0f35: Sysexit {%eip}, {%esp}, {%cs}, {%ss}, " "{%edx}, {%ecx}", NACLi_SYSENTER,st, SysJump); NaClDefIter(" 0f36+@i: Invalid", 0, 9, NACLi_INVALID, st, Other); NaClDefine(" 0f40: Cmovo $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f41: Cmovno $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f42: Cmovb $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f43: Cmovnb $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f44: Cmovz $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f45: Cmovnz $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f46: Cmovbe $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f47: Cmovnbe $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f48: Cmovs $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f49: Cmovns $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f4a: Cmovp $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f4b: Cmovnp $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f4c: Cmovl $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f4d: Cmovnl $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f4e: Cmovle $Gv, $Ev", NACLi_CMOV, st, Move); NaClDefine(" 0f4f: Cmovnle $Gv, $Ev", NACLi_CMOV, st, Move); /* Note: We special case the 66 prefix on direct conditional jumps, by * explicitly disallowing 16-bit direct jumps. This is done partly because * some versions (within x86-64) are not supported in such cases. However, * NaCl also doesn't want to allow 16-bit direct jumps. */ NaClDefine(" 0f80: Jo {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f81: Jno {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f82: Jb {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f83: Jnb {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f84: Jz {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f85: Jnz {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f86: Jbe {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f87: Jnbe {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f88: Js {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f89: Jns {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f8a: Jp {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f8b: Jnp {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f8c: Jl {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f8d: Jnl {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f8e: Jle {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f8f: Jnle {%@ip}, $Jzd", NACLi_386, st, Jump); NaClDefine(" 0f90: Seto $Eb", NACLi_386, st, Sets); NaClDefine(" 0f91: Setno $Eb", NACLi_386, st, Sets); NaClDefine(" 0f92: Setb $Eb", NACLi_386, st, Sets); NaClDefine(" 0f93: Setnb $Eb", NACLi_386, st, Sets); NaClDefine(" 0f94: Setz $Eb", NACLi_386, st, Sets); NaClDefine(" 0f95: Setnz $Eb", NACLi_386, st, Sets); NaClDefine(" 0f96: Setbe $Eb", NACLi_386, st, Sets); NaClDefine(" 0f97: Setnbe $Eb", NACLi_386, st, Sets); NaClDefine(" 0f98: Sets $Eb", NACLi_386, st, Sets); NaClDefine(" 0f99: Setns $Eb", NACLi_386, st, Sets); NaClDefine(" 0f9a: Setp $Eb", NACLi_386, st, Sets); NaClDefine(" 0f9b: Setnp $Eb", NACLi_386, st, Sets); NaClDefine(" 0f9c: Setl $Eb", NACLi_386, st, Sets); NaClDefine(" 0f9d: Setnl $Eb", NACLi_386, st, Sets); NaClDefine(" 0f9e: Setle $Eb", NACLi_386, st, Sets); NaClDefine(" 0f9f: Setnle $Eb", NACLi_386, st, Sets); NaClDefine(" 0fa0: Push {%@sp}, %fs", NACLi_386, st, Push); NaClDefine(" 0fa1: Pop {%@sp}, %fs", NACLi_386, st, Pop); NaClDefine(" 0fa2: Cpuid {%ebx}, {%edx}, {%eax}, {%ecx}", NACLi_386, st, Cpuid); NaClDefine(" 0fa3: Bt $Ev, $Gv", NACLi_386, st, Compare); NaClDefine(" 0fa4: Shld $Ev, $Gv, $Ib", NACLi_386, st, Binary); NaClDefine(" 0fa5: Shld $Ev, $Gv, %cl", NACLi_386, st, Binary); NaClDefIter(" 0fa6+@i: Invalid", 0, 1, NACLi_INVALID, st, Other); NaClDefine(" 0fa8: Push {%@sp}, %gs", NACLi_386, st, Push); NaClDefine(" 0fa9: Pop {%@sp}, %gs", NACLi_386, st, Pop); NaClDefine(" 0faa: Rsm", NACLi_SYSTEM, st, Other); NaClDefine(" 0fab: Bts $Ev, $Gv", NACLi_386, st, Binary); NaClDefine(" 0fac: Shrd $Ev, $Gv, $Ib", NACLi_386, st, Nary); NaClDefine(" 0fad: Shrd $Ev, $Gv, %cl", NACLi_386, st, Nary); NaClDefine(" 0fae/0: Fxsave $Mf", NACLi_FXSAVE, st, Sets); NaClDefine(" 0fae/1: Fxrstor $Mf", NACLi_FXSAVE, st, Uses); NaClDefine(" 0fae/2: Ldmxcsr $Md", NACLi_SSE, st, Uses); NaClDefine(" 0fae/3: Stmxcsr $Md", NACLi_SSE, st, Sets); NaClDefine(" 0fae/4: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0fae/5/0: Lfence", NACLi_SSE2, st, Other); NaClDefine(" 0fae/6/0: Mfence", NACLi_SSE2, st, Other); NaClDefine(" 0fae/7/0: Sfence", NACLi_SFENCE_CLFLUSH, st, Other); NaClDefIter(" 0fae/5/@i: Invalid", 1, 7, NACLi_INVALID, st, Other); NaClDefIter(" 0fae/6/@i: Invalid", 1, 7, NACLi_INVALID, st, Other); NaClDefIter(" 0fae/7/@i: Invalid", 1, 7, NACLi_INVALID, st, Other); NaClDefine(" 0fae/7: Clflush $Mb", NACLi_SFENCE_CLFLUSH, st, Uses); NaClDefine(" f20fae: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 660fae: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0faf: Imul $Gv, $Ev", NACLi_386, st, Binary); NaClDefine(" 0fb0: Cmpxchg {%al}, $Eb, $Gb", NACLi_386, st, Exchange); NaClDefine(" 0fb1: Cmpxchg {$rAXv}, $Ev, $Gv", NACLi_386, st, Exchange); NaClDefine(" 0fb2: Lss $SGz, $Mp", NACLi_386, st, Lea); NaClDefine(" 0fb3: Btr $Ev, $Gv", NACLi_386, st, Binary); NaClDefine(" 0fb4: Lfs $SGz, $Mp", NACLi_386, st, Lea); NaClDefine(" 0fb5: Lgs $SGz, $Mp", NACLi_386, st, Lea); NaClDefine(" 0fb6: Movzx $Gv, $Eb", NACLi_386, st, Move); NaClDefine(" 0fb7: Movzx $Gv, $Ew", NACLi_386, st, Move); NaClDefine(" 0fb8: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0fb9/r: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0fba/4: Bt $Ev, $Ib", NACLi_386, st, Compare); NaClDefine(" 0fba/5: Bts $Ev, $Ib", NACLi_386, st, Binary); NaClDefine(" 0fba/6: Btr $Ev, $Ib", NACLi_386, st, Binary); NaClDefine(" 0fba/7: Btc $Ev, $Ib", NACLi_386, st, Binary); NaClDefine(" 0fba/r: Invalid", NACLi_INVALID, st, Other); NaClDefine(" 0fbb: Btc $Ev, $Gv", NACLi_386, st, Binary); NaClDefine(" 0fbc: Bsf $Gv, $Ev", NACLi_386, st, Move); NaClDefine(" 0fbd: Bsr $Gv, $Ev", NACLi_386, st, Move); NaClDefine(" 0fbe: Movsx $Gv, $Eb", NACLi_386, st, Move); NaClDefine(" 0fbf: Movsx $Gv, $Ew", NACLi_386, st, Move); NaClDefine(" 0fc0: Xadd $Eb, $Gb", NACLi_386, st, Exchange); NaClDefine(" 0fc1: Xadd $Ev, $Gv", NACLi_386, st, Exchange); NaClBegDef(" 0fc7/1: Cmpxchg8b {%edx}, {%eax}, $Mq", NACLi_CMPXCHG8B, st); NaClAddIFlags(NACL_IFLAG(OperandSize_v)); NaClEndDef( Exchange); NaClBegD64(" 0fc7/1: Cmpxchg16b {%rdx}, {%eax}, $Mdq", NACLi_CMPXCHG16B, st); NaClAddIFlags(NACL_IFLAG(OperandSize_o)); NaClEndDef( Exchange); NaClDefine(" 0fc7/r: Invalid", NACLi_INVALID, st, Other); for (i = 0; i <= 7; ++i) { NaClDefPrefixInstChoices(Prefix0F, 0xc8 + i, 2); } NaClDefReg(" 0fc8+@reg: Bswap $r8vd", 0, 7, NACLi_386, st, UnaryUpdate); NaClDefReg(" 0fc8+@reg: Bswap $r8vq", 0, 7, NACLi_386, st, UnaryUpdate); }