diff --git a/.gitattributes b/.gitattributes index df0eef64a3ea2f49f7cf7f3879ef118533f40bc8..c533adcbbce2b33dc5f5a1d4aac57f1060669dd0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,5 +3,6 @@ /README.txt -text /SMP-analyze.sh -text /SMP.idc -text +/SMPStaticAnalyzer.cpp -text /makefile -text /plugin.script -text diff --git a/SMPStaticAnalyzer.cpp b/SMPStaticAnalyzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28c3f82797ce23f98e944afbb08827cbb3f66ad0 --- /dev/null +++ b/SMPStaticAnalyzer.cpp @@ -0,0 +1,1085 @@ +// +// SMPStaticAnalyzer.cpp +// +// This plugin performs the static analyses needed for the SMP project +// (Software Memory Protection). +// + +#include <ida.hpp> +#include <idp.hpp> +#include <allins.hpp> +#include <auto.hpp> +#include <bytes.hpp> +#include <funcs.hpp> +#include <intel.hpp> +#include <loader.hpp> +#include <lines.hpp> +#include <name.hpp> +#include <ua.hpp> + +#include "SMPStaticAnalyzer.h" +#include "SMPDataFlowAnalysis.h" + + +// Set to 1 for debugging output +#define SMP_DEBUG 1 +#define SMP_DEBUG2 1 // verbose +#define SMP_DEBUG3 0 // verbose +#define SMP_DEBUG_MEM 0 // print memory operands +#define SMP_DEBUG_TYPE0 0 // Output instr info for OptType = 0 + +// Set to 1 when doing a binary search using SMP_DEBUG_COUNT to find +// which function is causing a problem. +#define SMP_BINARY_DEBUG 0 +#define SMP_DEBUG_COUNT 356 // How many funcs to process in problem search +int FuncsProcessed = 0; + + +// Define optimization categories for instructions. +int OptCategory[NN_last+1]; +// Initialize the OptCategory[] array. +void InitOptCategory(void); + +// Keep statistics on how many instructions we saw in each optimization +// category, and how many optimizing annotations were emitted for +// each category. +int OptCount[LAST_OPT_CATEGORY + 1]; +int AnnotationCount[LAST_OPT_CATEGORY + 1]; + +static char *RegNames[R_of + 1] = + { "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", + "SPL", "BPL", "SIL", "DIL", "EIP", "ES", "CS", "SS", + "DS", "FS", "GS", "CF", "ZF", "SF", "OF" + }; + +// The types of data objects based on their first operand flags. +static char *DataTypes[] = { "VOID", "NUMHEX", "NUMDEC", "CHAR", + "SEG", "OFFSET", "NUMBIN", "NUMOCT", "ENUM", "FORCED", + "STRUCTOFFSET", "STACKVAR", "NUMFLOAT", "UNKNOWN", + "UNKNOWN", "UNKNOWN", 0}; + + +void IDAP_run(int); + + + + +static int idaapi idp_callback(void *, int event_id, va_list va) { + if (event_id == ph.auto_empty_finally) { // IDA analysis is done + IDAP_run(0); + qexit(0); + } + return 0; +} + +int IDAP_init(void) { +#if 0 // We are now calling from the SMP.idc script. + // Skip this plugin if it was not specified by the user on the + // command line. + if (get_plugin_options("SMPStaticAnalyzer") == NULL) { + msg("IDAP_init point 2.\n"); + return PLUGIN_SKIP; + } +#endif + // Ensure correct working environment. + if ((inf.filetype != f_ELF) && (inf.filetype != f_PE)) { + error("Executable format must be PE or ELF."); + return PLUGIN_SKIP; + } + if (ph.id != PLFM_386) { + error("Processor must be x86."); + return PLUGIN_SKIP; + } + hook_to_notification_point(HT_IDP, idp_callback, NULL); + InitOptCategory(); + InitDFACategory(); + return PLUGIN_KEEP; +} // end of IDAP_init + +void IDAP_term(void) { + unhook_from_notification_point(HT_IDP, idp_callback, NULL); + return; +} + +void IDAP_run(int arg) { + + segment_t *seg; + char buf[MAXSTR]; + ea_t ea; + flags_t ObjFlags; + bool ReadOnlyFlag; + FILE *SymsFile; + char FuncName[MAXSTR]; + SMPFunction *CurrFunc = NULL; + bool FuncsDumped = false; + +#if SMP_DEBUG + msg("Beginning IDAP_run.\n"); +#endif + // Open the output file. + SymsFile = qfopen("SMP.annot", "w"); + if (NULL == SymsFile) { + error("FATAL: Cannot open output file SMP.annot\n"); + return; + } + + (void) memset(OptCount, 0, sizeof(OptCount)); + (void) memset(AnnotationCount, 0, sizeof(AnnotationCount)); + + // First, examine the data segments and print info about static + // data, such as name/address/size. Do the same for functions in + // code segments. + // Loop through all segments. + for (int SegIndex = 0; SegIndex < get_segm_qty(); ++SegIndex) { + seg = getnseg(SegIndex); + + // We are only interested in the data segments of type + // SEG_DATA, SEG_BSS and SEG_COMM. + if ((seg->type == SEG_DATA) || (seg->type == SEG_BSS) + || (seg->type == SEG_COMM)) { + // Loop through each of the segments we are interested in, + // examining all data objects (effective addresses). + ReadOnlyFlag = ((seg->perm & SEGPERM_READ) && (!(seg->perm & SEGPERM_WRITE))); +#if SMP_DEBUG + msg("Starting data segment of type %d\n", seg->type); + if (ReadOnlyFlag) { + msg("Read-only data segment.\n"); + } +#endif + ea = seg->startEA; + while (ea < seg->endEA) { + ObjFlags = get_flags_novalue(ea); + // Only process head bytes of data objects, i.e. isData(). + if (isData(ObjFlags)) { + // Compute the size of the data object. + ea_t NextEA = ea; + do { + NextEA = nextaddr(NextEA); + } while ((NextEA < seg->endEA) && (!isHead(get_flags_novalue(NextEA)))); + size_t ObjSize = (size_t) (NextEA - ea); + // Get the data object name using its address. + char *TrueName = get_true_name(BADADDR, ea, buf, sizeof(buf)); + if (NULL == TrueName) { + qstrncpy(buf, "SMP_dummy0", 12); + } + // Output the name, address, size, and type info. + if (ReadOnlyFlag) { + qfprintf(SymsFile, + "%x %d OBJECT GLOBAL %s %s RO\n", ea, ObjSize, + buf, DataTypes[get_optype_flags0(ObjFlags) >> 20]); + } + else { + qfprintf(SymsFile, + "%x %d OBJECT GLOBAL %s %s RW\n", ea, ObjSize, + buf, DataTypes[get_optype_flags0(ObjFlags) >> 20]); + } + // Move on to next data object + ea = NextEA; + } + else { + ea = nextaddr(ea); + } + } // end while (ea < seg->endEA) + } // end if (seg->type == SEG_DATA ...) + else if (seg->type == SEG_CODE) { +#if SMP_DEBUG + msg("Starting code segment.\n"); +#endif +#if SMP_DEBUG2 + if (!FuncsDumped) { + for (size_t FuncIndex = 0; FuncIndex < get_func_qty(); ++FuncIndex) { + func_t *FuncInfo = getn_func(FuncIndex); + get_func_name(FuncInfo->startEA, FuncName, MAXSTR-1); + msg("FuncName dump: %s\n", FuncName); + } + for (size_t ChunkIndex = 0; ChunkIndex < get_fchunk_qty(); ++ChunkIndex) { + func_t *ChunkInfo = getn_fchunk((int) ChunkIndex); + get_func_name(ChunkInfo->startEA, FuncName, MAXSTR-1); + if (0 == strcmp(FuncName, "fflush")) { + msg("fflush chunk: address %x", ChunkInfo->startEA); + if (is_func_tail(ChunkInfo)) + msg(" TAIL\n"); + else + msg(" ENTRY\n"); + } + else if ((0x81498f0 < ChunkInfo->startEA) + && (0x8149cb6 > ChunkInfo->startEA)) { + msg("Missing fflush chunk: %s %x", + FuncName, ChunkInfo->startEA); + if (is_func_tail(ChunkInfo)) + msg(" TAIL\n"); + else + msg(" ENTRY\n"); + } + } // end for (size_t ChunkIndex = ...) + func_t *FuncInfo = get_func(0x8149be0); + if (NULL == FuncInfo) + msg("No func at 0x8149be0\n"); + else { + get_func_name(FuncInfo->startEA, FuncName, MAXSTR-1); + msg("Func at 0x8149be0: %s\n", FuncName); + } + FuncsDumped = true; + } +#endif + for (size_t FuncIndex = 0; FuncIndex < get_func_qty(); ++FuncIndex) { + func_t *FuncInfo = getn_func(FuncIndex); + + // If more than one SEG_CODE segment, only process + // functions within the current segment. Don't know + // if multiple code segments are possible, but + // get_func_qty() is for the whole program, not just + // the current segment. + if (FuncInfo->startEA < seg->startEA) { + // Already processed this func in earlier segment. + continue; + } + else if (FuncInfo->startEA >= seg->endEA) { +#if SMP_DEBUG2 + get_func_name(FuncInfo->startEA, FuncName, MAXSTR-1); + msg("Skipping function until we reach its segment: %s\n", + FuncName); +#endif + break; + } + + // Create a function object. + if (NULL != CurrFunc){ + delete CurrFunc; + CurrFunc = NULL; + } + CurrFunc = new SMPFunction(FuncInfo); + + +#if SMP_BINARY_DEBUG + if (FuncsProcessed++ > SMP_DEBUG_COUNT) { + get_func_name(FuncInfo->startEA, FuncName, MAXSTR-1); + msg("Debug termination. FuncName = %s \n", FuncName); + msg("Function startEA: %x endEA: %x \n", + FuncInfo->startEA, + FuncInfo->endEA); + break; + } +#endif +#if SMP_BINARY_DEBUG + if (FuncsProcessed > SMP_DEBUG_COUNT) { + get_func_name(FuncInfo->startEA, FuncName, MAXSTR-1); + msg("Final FuncName: %s \n", FuncName); + SMPBinaryDebug = true; + } +#endif + CurrFunc->Analyze(); + CurrFunc->EmitAnnotations(SymsFile); + delete CurrFunc; + CurrFunc = NULL; + } // end for (size_t FuncIndex = 0; ...) + } // end else if (seg->type === SEG_CODE) + else { +#if SMP_DEBUG + msg("Not processing segment of type %d \n", seg->type); +#endif + } + } // end for (int SegIndex = 0; ... ) + + for (int OptType = 0; OptType <= LAST_OPT_CATEGORY; ++OptType) { + msg("Optimization Category Count %d: %d Annotations: %d\n", + OptType, OptCount[OptType], AnnotationCount[OptType]); + } + + qfclose(SymsFile); + return; +} // end IDAP_run() + +char IDAP_comment[] = "UVa SMP/NICECAP Project"; +char IDAP_help[] = "Good luck"; +char IDAP_name[] = "SMPStaticAnalyzer"; +char IDAP_hotkey[] = "Alt-J"; + +plugin_t PLUGIN = { + IDP_INTERFACE_VERSION, + 0, + IDAP_init, + IDAP_term, + IDAP_run, + IDAP_comment, + IDAP_help, + IDAP_name, + IDAP_hotkey +}; + + + +// Initialize the OptCategory[] array to define how we emit +// optimizing annotations. +void InitOptCategory(void) { + // Default category is 0, no optimization without knowing context. + (void) memset(OptCategory, 0, sizeof(OptCategory)); + // Category 1 instructions never need updating of their memory + // metadata by the Memory Monitor SDT. Currently, this is because + // these instructions only have effects on registers we do not maintain + // metadata for, such as the EIP and the FLAGS, e.g. jumps, compares. + // Category 2 instructions always have a result type of 'n' (number). + // Category 3 instructions have a result type of 'n' (number) + // whenever the second source operand is an immediate operand of type 'n'. + // NOTE: MOV is only current example, and this will take some thought if + // other examples arise. + // Category 4 instructions have a result type identical to the 1st source operand type. + // NOTE: This is currently set for single-operand instructions such as + // INC, DEC. As a result, these are treated pretty much as if + // they were category 1 instructions, as there is no metadata update, + // unless the operand is a memory operand (i.e. mem or [reg]). + // If new instructions are added to this category that are not single + // operand and do require some updating, the category should be split. + // Category 5 instructions have a result type identical to the 1st source operand + // type whenever the 2nd source operand is an operand of type 'n'. + // If the destination is memory, metadata still needs to be checked; if + // not, no metadata check is needed, so it becomes category 1. + // Category 6 instructions always have a result type of 'p' (pointer). + // Category 7 instructions are category 2 instructions with two destinations, + // such as multiply and divide instructions that affect EDX:EAX. There are + // forms of these instructions that only have one destination, so they have + // to be distinguished via the operand info. + // Category 8 instructions implicitly write a numeric value to EDX:EAX, but + // EDX and EAX are not listed as operands. RDTSC, RDPMC, RDMSR, and other + // instructions that copy machine registers into EDX:EAX are category 8. + // Category 9 instructions are floating point instructions that either + // have a memory destination (treat as category 0) or a FP reg destination + // (treat as category 1). + + // NOTE: The Memory Monitor SDT needs just three categories, corresponding + // to categories 0, 1, and all others. For all categories > 1, the + // annotation should tell the SDT exactly how to update its metadata. + // For example, a division instruction will write type 'n' (NUM) as + // the metadata for result registers EDX:EAX. So, the annotation should + // list 'n', EDX, EAX, and a terminator of '/'. CWD (convert word to + // doubleword) should have a list of 'n', EAX, '/'. + +OptCategory[NN_null] = 0; // Unknown Operation +OptCategory[NN_aaa] = 2; // ASCII Adjust after Addition +OptCategory[NN_aad] = 2; // ASCII Adjust AX before Division +OptCategory[NN_aam] = 2; // ASCII Adjust AX after Multiply +OptCategory[NN_aas] = 2; // ASCII Adjust AL after Subtraction +OptCategory[NN_adc] = 5; // Add with Carry +OptCategory[NN_add] = 5; // Add +OptCategory[NN_and] = 0; // Logical AND +OptCategory[NN_arpl] = 1; // Adjust RPL Field of Selector +OptCategory[NN_bound] = 1; // Check Array Index Against Bounds +OptCategory[NN_bsf] = 2; // Bit Scan Forward +OptCategory[NN_bsr] = 2; // Bit Scan Reverse +OptCategory[NN_bt] = 2; // Bit Test +OptCategory[NN_btc] = 2; // Bit Test and Complement +OptCategory[NN_btr] = 2; // Bit Test and Reset +OptCategory[NN_bts] = 2; // Bit Test and Set +OptCategory[NN_call] = 1; // Call Procedure +OptCategory[NN_callfi] = 1; // Indirect Call Far Procedure +OptCategory[NN_callni] = 1; // Indirect Call Near Procedure +OptCategory[NN_cbw] = 2; // AL -> AX (with sign) ** No ops? +OptCategory[NN_cwde] = 2; // AX -> EAX (with sign) ** +OptCategory[NN_cdqe] = 2; // EAX -> RAX (with sign) ** +OptCategory[NN_clc] = 1; // Clear Carry Flag +OptCategory[NN_cld] = 1; // Clear Direction Flag +OptCategory[NN_cli] = 1; // Clear Interrupt Flag +OptCategory[NN_clts] = 1; // Clear Task-Switched Flag in CR0 +OptCategory[NN_cmc] = 1; // Complement Carry Flag +OptCategory[NN_cmp] = 1; // Compare Two Operands +OptCategory[NN_cmps] = 1; // Compare Strings +OptCategory[NN_cwd] = 2; // AX -> DX:AX (with sign) +OptCategory[NN_cdq] = 2; // EAX -> EDX:EAX (with sign) +OptCategory[NN_cqo] = 2; // RAX -> RDX:RAX (with sign) +OptCategory[NN_daa] = 2; // Decimal Adjust AL after Addition +OptCategory[NN_das] = 2; // Decimal Adjust AL after Subtraction +OptCategory[NN_dec] = 4; // Decrement by 1 +OptCategory[NN_div] = 7; // Unsigned Divide +OptCategory[NN_enterw] = 0; // Make Stack Frame for Procedure Parameters ** +OptCategory[NN_enter] = 0; // Make Stack Frame for Procedure Parameters ** +OptCategory[NN_enterd] = 0; // Make Stack Frame for Procedure Parameters ** +OptCategory[NN_enterq] = 0; // Make Stack Frame for Procedure Parameters ** +OptCategory[NN_hlt] = 0; // Halt +OptCategory[NN_idiv] = 7; // Signed Divide +OptCategory[NN_imul] = 7; // Signed Multiply +OptCategory[NN_in] = 0; // Input from Port ** +OptCategory[NN_inc] = 4; // Increment by 1 +OptCategory[NN_ins] = 2; // Input Byte(s) from Port to String ** +OptCategory[NN_int] = 1; // Call to Interrupt Procedure +OptCategory[NN_into] = 1; // Call to Interrupt Procedure if Overflow Flag = 1 +OptCategory[NN_int3] = 1; // Trap to Debugger +OptCategory[NN_iretw] = 1; // Interrupt Return +OptCategory[NN_iret] = 1; // Interrupt Return +OptCategory[NN_iretd] = 1; // Interrupt Return (use32) +OptCategory[NN_iretq] = 1; // Interrupt Return (use64) +OptCategory[NN_ja] = 1; // Jump if Above (CF=0 & ZF=0) +OptCategory[NN_jae] = 1; // Jump if Above or Equal (CF=0) +OptCategory[NN_jb] = 1; // Jump if Below (CF=1) +OptCategory[NN_jbe] = 1; // Jump if Below or Equal (CF=1 | ZF=1) +OptCategory[NN_jc] = 1; // Jump if Carry (CF=1) +OptCategory[NN_jcxz] = 1; // Jump if CX is 0 +OptCategory[NN_jecxz] = 1; // Jump if ECX is 0 +OptCategory[NN_jrcxz] = 1; // Jump if RCX is 0 +OptCategory[NN_je] = 1; // Jump if Equal (ZF=1) +OptCategory[NN_jg] = 1; // Jump if Greater (ZF=0 & SF=OF) +OptCategory[NN_jge] = 1; // Jump if Greater or Equal (SF=OF) +OptCategory[NN_jl] = 1; // Jump if Less (SF!=OF) +OptCategory[NN_jle] = 1; // Jump if Less or Equal (ZF=1 | SF!=OF) +OptCategory[NN_jna] = 1; // Jump if Not Above (CF=1 | ZF=1) +OptCategory[NN_jnae] = 1; // Jump if Not Above or Equal (CF=1) +OptCategory[NN_jnb] = 1; // Jump if Not Below (CF=0) +OptCategory[NN_jnbe] = 1; // Jump if Not Below or Equal (CF=0 & ZF=0) +OptCategory[NN_jnc] = 1; // Jump if Not Carry (CF=0) +OptCategory[NN_jne] = 1; // Jump if Not Equal (ZF=0) +OptCategory[NN_jng] = 1; // Jump if Not Greater (ZF=1 | SF!=OF) +OptCategory[NN_jnge] = 1; // Jump if Not Greater or Equal (ZF=1) +OptCategory[NN_jnl] = 1; // Jump if Not Less (SF=OF) +OptCategory[NN_jnle] = 1; // Jump if Not Less or Equal (ZF=0 & SF=OF) +OptCategory[NN_jno] = 1; // Jump if Not Overflow (OF=0) +OptCategory[NN_jnp] = 1; // Jump if Not Parity (PF=0) +OptCategory[NN_jns] = 1; // Jump if Not Sign (SF=0) +OptCategory[NN_jnz] = 1; // Jump if Not Zero (ZF=0) +OptCategory[NN_jo] = 1; // Jump if Overflow (OF=1) +OptCategory[NN_jp] = 1; // Jump if Parity (PF=1) +OptCategory[NN_jpe] = 1; // Jump if Parity Even (PF=1) +OptCategory[NN_jpo] = 1; // Jump if Parity Odd (PF=0) +OptCategory[NN_js] = 1; // Jump if Sign (SF=1) +OptCategory[NN_jz] = 1; // Jump if Zero (ZF=1) +OptCategory[NN_jmp] = 1; // Jump +OptCategory[NN_jmpfi] = 1; // Indirect Far Jump +OptCategory[NN_jmpni] = 1; // Indirect Near Jump +OptCategory[NN_jmpshort] = 1; // Jump Short (not used) +OptCategory[NN_lahf] = 2; // Load Flags into AH Register +OptCategory[NN_lar] = 2; // Load Access Rights Byte +OptCategory[NN_lea] = 0; // Load Effective Address ** +OptCategory[NN_leavew] = 0; // High Level Procedure Exit ** +OptCategory[NN_leave] = 0; // High Level Procedure Exit ** +OptCategory[NN_leaved] = 0; // High Level Procedure Exit ** +OptCategory[NN_leaveq] = 0; // High Level Procedure Exit ** +OptCategory[NN_lgdt] = 0; // Load Global Descriptor Table Register +OptCategory[NN_lidt] = 0; // Load Interrupt Descriptor Table Register +OptCategory[NN_lgs] = 6; // Load Full Pointer to GS:xx +OptCategory[NN_lss] = 6; // Load Full Pointer to SS:xx +OptCategory[NN_lds] = 6; // Load Full Pointer to DS:xx +OptCategory[NN_les] = 6; // Load Full Pointer to ES:xx +OptCategory[NN_lfs] = 6; // Load Full Pointer to FS:xx +OptCategory[NN_lldt] = 0; // Load Local Descriptor Table Register +OptCategory[NN_lmsw] = 1; // Load Machine Status Word +OptCategory[NN_lock] = 1; // Assert LOCK# Signal Prefix +OptCategory[NN_lods] = 0; // Load String +OptCategory[NN_loopw] = 1; // Loop while ECX != 0 +OptCategory[NN_loop] = 1; // Loop while CX != 0 +OptCategory[NN_loopd] = 1; // Loop while ECX != 0 +OptCategory[NN_loopq] = 1; // Loop while RCX != 0 +OptCategory[NN_loopwe] = 1; // Loop while CX != 0 and ZF=1 +OptCategory[NN_loope] = 1; // Loop while rCX != 0 and ZF=1 +OptCategory[NN_loopde] = 1; // Loop while ECX != 0 and ZF=1 +OptCategory[NN_loopqe] = 1; // Loop while RCX != 0 and ZF=1 +OptCategory[NN_loopwne] = 1; // Loop while CX != 0 and ZF=0 +OptCategory[NN_loopne] = 1; // Loop while rCX != 0 and ZF=0 +OptCategory[NN_loopdne] = 1; // Loop while ECX != 0 and ZF=0 +OptCategory[NN_loopqne] = 1; // Loop while RCX != 0 and ZF=0 +OptCategory[NN_lsl] = 6; // Load Segment Limit +OptCategory[NN_ltr] = 1; // Load Task Register +OptCategory[NN_mov] = 3; // Move Data +OptCategory[NN_movsp] = 3; // Move to/from Special Registers +OptCategory[NN_movs] = 0; // Move Byte(s) from String to String +OptCategory[NN_movsx] = 3; // Move with Sign-Extend +OptCategory[NN_movzx] = 3; // Move with Zero-Extend +OptCategory[NN_mul] = 7; // Unsigned Multiplication of AL or AX +OptCategory[NN_neg] = 2; // Two's Complement Negation +OptCategory[NN_nop] = 1; // No Operation +OptCategory[NN_not] = 2; // One's Complement Negation +OptCategory[NN_or] = 0; // Logical Inclusive OR +OptCategory[NN_out] = 0; // Output to Port +OptCategory[NN_outs] = 0; // Output Byte(s) to Port +OptCategory[NN_pop] = 0; // Pop a word from the Stack +OptCategory[NN_popaw] = 0; // Pop all General Registers +OptCategory[NN_popa] = 0; // Pop all General Registers +OptCategory[NN_popad] = 0; // Pop all General Registers (use32) +OptCategory[NN_popaq] = 0; // Pop all General Registers (use64) +OptCategory[NN_popfw] = 1; // Pop Stack into Flags Register ** +OptCategory[NN_popf] = 1; // Pop Stack into Flags Register ** +OptCategory[NN_popfd] = 1; // Pop Stack into Eflags Register ** +OptCategory[NN_popfq] = 1; // Pop Stack into Rflags Register ** +OptCategory[NN_push] = 0; // Push Operand onto the Stack +OptCategory[NN_pushaw] = 0; // Push all General Registers +OptCategory[NN_pusha] = 0; // Push all General Registers +OptCategory[NN_pushad] = 0; // Push all General Registers (use32) +OptCategory[NN_pushaq] = 0; // Push all General Registers (use64) +OptCategory[NN_pushfw] = 0; // Push Flags Register onto the Stack +OptCategory[NN_pushf] = 0; // Push Flags Register onto the Stack +OptCategory[NN_pushfd] = 0; // Push Flags Register onto the Stack (use32) +OptCategory[NN_pushfq] = 0; // Push Flags Register onto the Stack (use64) +OptCategory[NN_rcl] = 2; // Rotate Through Carry Left +OptCategory[NN_rcr] = 2; // Rotate Through Carry Right +OptCategory[NN_rol] = 2; // Rotate Left +OptCategory[NN_ror] = 2; // Rotate Right +OptCategory[NN_rep] = 0; // Repeat String Operation +OptCategory[NN_repe] = 0; // Repeat String Operation while ZF=1 +OptCategory[NN_repne] = 0; // Repeat String Operation while ZF=0 +OptCategory[NN_retn] = 0; // Return Near from Procedure +OptCategory[NN_retf] = 0; // Return Far from Procedure +OptCategory[NN_sahf] = 1; // Store AH into Flags Register +OptCategory[NN_sal] = 2; // Shift Arithmetic Left +OptCategory[NN_sar] = 2; // Shift Arithmetic Right +OptCategory[NN_shl] = 2; // Shift Logical Left +OptCategory[NN_shr] = 2; // Shift Logical Right +OptCategory[NN_sbb] = 5; // Integer Subtraction with Borrow +OptCategory[NN_scas] = 1; // Compare String +OptCategory[NN_seta] = 2; // Set Byte if Above (CF=0 & ZF=0) +OptCategory[NN_setae] = 2; // Set Byte if Above or Equal (CF=0) +OptCategory[NN_setb] = 2; // Set Byte if Below (CF=1) +OptCategory[NN_setbe] = 2; // Set Byte if Below or Equal (CF=1 | ZF=1) +OptCategory[NN_setc] = 2; // Set Byte if Carry (CF=1) +OptCategory[NN_sete] = 2; // Set Byte if Equal (ZF=1) +OptCategory[NN_setg] = 2; // Set Byte if Greater (ZF=0 & SF=OF) +OptCategory[NN_setge] = 2; // Set Byte if Greater or Equal (SF=OF) +OptCategory[NN_setl] = 2; // Set Byte if Less (SF!=OF) +OptCategory[NN_setle] = 2; // Set Byte if Less or Equal (ZF=1 | SF!=OF) +OptCategory[NN_setna] = 2; // Set Byte if Not Above (CF=1 | ZF=1) +OptCategory[NN_setnae] = 2; // Set Byte if Not Above or Equal (CF=1) +OptCategory[NN_setnb] = 2; // Set Byte if Not Below (CF=0) +OptCategory[NN_setnbe] = 2; // Set Byte if Not Below or Equal (CF=0 & ZF=0) +OptCategory[NN_setnc] = 2; // Set Byte if Not Carry (CF=0) +OptCategory[NN_setne] = 2; // Set Byte if Not Equal (ZF=0) +OptCategory[NN_setng] = 2; // Set Byte if Not Greater (ZF=1 | SF!=OF) +OptCategory[NN_setnge] = 2; // Set Byte if Not Greater or Equal (ZF=1) +OptCategory[NN_setnl] = 2; // Set Byte if Not Less (SF=OF) +OptCategory[NN_setnle] = 2; // Set Byte if Not Less or Equal (ZF=0 & SF=OF) +OptCategory[NN_setno] = 2; // Set Byte if Not Overflow (OF=0) +OptCategory[NN_setnp] = 2; // Set Byte if Not Parity (PF=0) +OptCategory[NN_setns] = 2; // Set Byte if Not Sign (SF=0) +OptCategory[NN_setnz] = 2; // Set Byte if Not Zero (ZF=0) +OptCategory[NN_seto] = 2; // Set Byte if Overflow (OF=1) +OptCategory[NN_setp] = 2; // Set Byte if Parity (PF=1) +OptCategory[NN_setpe] = 2; // Set Byte if Parity Even (PF=1) +OptCategory[NN_setpo] = 2; // Set Byte if Parity Odd (PF=0) +OptCategory[NN_sets] = 2; // Set Byte if Sign (SF=1) +OptCategory[NN_setz] = 2; // Set Byte if Zero (ZF=1) +OptCategory[NN_sgdt] = 0; // Store Global Descriptor Table Register +OptCategory[NN_sidt] = 0; // Store Interrupt Descriptor Table Register +OptCategory[NN_shld] = 2; // Double Precision Shift Left +OptCategory[NN_shrd] = 2; // Double Precision Shift Right +OptCategory[NN_sldt] = 6; // Store Local Descriptor Table Register +OptCategory[NN_smsw] = 2; // Store Machine Status Word +OptCategory[NN_stc] = 1; // Set Carry Flag +OptCategory[NN_std] = 1; // Set Direction Flag +OptCategory[NN_sti] = 1; // Set Interrupt Flag +OptCategory[NN_stos] = 0; // Store String +OptCategory[NN_str] = 6; // Store Task Register +OptCategory[NN_sub] = 5; // Integer Subtraction +OptCategory[NN_test] = 1; // Logical Compare +OptCategory[NN_verr] = 1; // Verify a Segment for Reading +OptCategory[NN_verw] = 1; // Verify a Segment for Writing +OptCategory[NN_wait] = 1; // Wait until BUSY# Pin is Inactive (HIGH) +OptCategory[NN_xchg] = 0; // Exchange Register/Memory with Register +OptCategory[NN_xlat] = 0; // Table Lookup Translation +OptCategory[NN_xor] = 2; // Logical Exclusive OR + +// +// 486 instructions +// + +OptCategory[NN_cmpxchg] = 0; // Compare and Exchange +OptCategory[NN_bswap] = 1; // Swap bytes in register +OptCategory[NN_xadd] = 0; // t<-dest; dest<-src+dest; src<-t +OptCategory[NN_invd] = 1; // Invalidate Data Cache +OptCategory[NN_wbinvd] = 1; // Invalidate Data Cache (write changes) +OptCategory[NN_invlpg] = 1; // Invalidate TLB entry + +// +// Pentium instructions +// + +OptCategory[NN_rdmsr] = 8; // Read Machine Status Register +OptCategory[NN_wrmsr] = 1; // Write Machine Status Register +OptCategory[NN_cpuid] = 8; // Get CPU ID +OptCategory[NN_cmpxchg8b] = 0; // Compare and Exchange Eight Bytes +OptCategory[NN_rdtsc] = 8; // Read Time Stamp Counter +OptCategory[NN_rsm] = 1; // Resume from System Management Mode + +// +// Pentium Pro instructions +// + +OptCategory[NN_cmova] = 0; // Move if Above (CF=0 & ZF=0) +OptCategory[NN_cmovb] = 0; // Move if Below (CF=1) +OptCategory[NN_cmovbe] = 0; // Move if Below or Equal (CF=1 | ZF=1) +OptCategory[NN_cmovg] = 0; // Move if Greater (ZF=0 & SF=OF) +OptCategory[NN_cmovge] = 0; // Move if Greater or Equal (SF=OF) +OptCategory[NN_cmovl] = 0; // Move if Less (SF!=OF) +OptCategory[NN_cmovle] = 0; // Move if Less or Equal (ZF=1 | SF!=OF) +OptCategory[NN_cmovnb] = 0; // Move if Not Below (CF=0) +OptCategory[NN_cmovno] = 0; // Move if Not Overflow (OF=0) +OptCategory[NN_cmovnp] = 0; // Move if Not Parity (PF=0) +OptCategory[NN_cmovns] = 0; // Move if Not Sign (SF=0) +OptCategory[NN_cmovnz] = 0; // Move if Not Zero (ZF=0) +OptCategory[NN_cmovo] = 0; // Move if Overflow (OF=1) +OptCategory[NN_cmovp] = 0; // Move if Parity (PF=1) +OptCategory[NN_cmovs] = 0; // Move if Sign (SF=1) +OptCategory[NN_cmovz] = 0; // Move if Zero (ZF=1) +OptCategory[NN_fcmovb] = 1; // Floating Move if Below +OptCategory[NN_fcmove] = 1; // Floating Move if Equal +OptCategory[NN_fcmovbe] = 1; // Floating Move if Below or Equal +OptCategory[NN_fcmovu] = 1; // Floating Move if Unordered +OptCategory[NN_fcmovnb] = 1; // Floating Move if Not Below +OptCategory[NN_fcmovne] = 1; // Floating Move if Not Equal +OptCategory[NN_fcmovnbe] = 1; // Floating Move if Not Below or Equal +OptCategory[NN_fcmovnu] = 1; // Floating Move if Not Unordered +OptCategory[NN_fcomi] = 1; // FP Compare, result in EFLAGS +OptCategory[NN_fucomi] = 1; // FP Unordered Compare, result in EFLAGS +OptCategory[NN_fcomip] = 1; // FP Compare, result in EFLAGS, pop stack +OptCategory[NN_fucomip] = 1; // FP Unordered Compare, result in EFLAGS, pop stack +OptCategory[NN_rdpmc] = 8; // Read Performance Monitor Counter + +// +// FPP instructuions +// + +OptCategory[NN_fld] = 1; // Load Real ** Infer src is 'n' +OptCategory[NN_fst] = 9; // Store Real +OptCategory[NN_fstp] = 9; // Store Real and Pop +OptCategory[NN_fxch] = 1; // Exchange Registers +OptCategory[NN_fild] = 1; // Load Integer ** Infer src is 'n' +OptCategory[NN_fist] = 0; // Store Integer +OptCategory[NN_fistp] = 0; // Store Integer and Pop +OptCategory[NN_fbld] = 1; // Load BCD +OptCategory[NN_fbstp] = 1; // Store BCD and Pop +OptCategory[NN_fadd] = 1; // Add Real +OptCategory[NN_faddp] = 1; // Add Real and Pop +OptCategory[NN_fiadd] = 1; // Add Integer +OptCategory[NN_fsub] = 1; // Subtract Real +OptCategory[NN_fsubp] = 1; // Subtract Real and Pop +OptCategory[NN_fisub] = 1; // Subtract Integer +OptCategory[NN_fsubr] = 1; // Subtract Real Reversed +OptCategory[NN_fsubrp] = 1; // Subtract Real Reversed and Pop +OptCategory[NN_fisubr] = 1; // Subtract Integer Reversed +OptCategory[NN_fmul] = 1; // Multiply Real +OptCategory[NN_fmulp] = 1; // Multiply Real and Pop +OptCategory[NN_fimul] = 1; // Multiply Integer +OptCategory[NN_fdiv] = 1; // Divide Real +OptCategory[NN_fdivp] = 1; // Divide Real and Pop +OptCategory[NN_fidiv] = 1; // Divide Integer +OptCategory[NN_fdivr] = 1; // Divide Real Reversed +OptCategory[NN_fdivrp] = 1; // Divide Real Reversed and Pop +OptCategory[NN_fidivr] = 1; // Divide Integer Reversed +OptCategory[NN_fsqrt] = 1; // Square Root +OptCategory[NN_fscale] = 1; // Scale: st(0) <- st(0) * 2^st(1) +OptCategory[NN_fprem] = 1; // Partial Remainder +OptCategory[NN_frndint] = 1; // Round to Integer +OptCategory[NN_fxtract] = 1; // Extract exponent and significand +OptCategory[NN_fabs] = 1; // Absolute value +OptCategory[NN_fchs] = 1; // Change Sign +OptCategory[NN_fcom] = 1; // Compare Real +OptCategory[NN_fcomp] = 1; // Compare Real and Pop +OptCategory[NN_fcompp] = 1; // Compare Real and Pop Twice +OptCategory[NN_ficom] = 1; // Compare Integer +OptCategory[NN_ficomp] = 1; // Compare Integer and Pop +OptCategory[NN_ftst] = 1; // Test +OptCategory[NN_fxam] = 1; // Examine +OptCategory[NN_fptan] = 1; // Partial tangent +OptCategory[NN_fpatan] = 1; // Partial arctangent +OptCategory[NN_f2xm1] = 1; // 2^x - 1 +OptCategory[NN_fyl2x] = 1; // Y * lg2(X) +OptCategory[NN_fyl2xp1] = 1; // Y * lg2(X+1) +OptCategory[NN_fldz] = 1; // Load +0.0 +OptCategory[NN_fld1] = 1; // Load +1.0 +OptCategory[NN_fldpi] = 1; // Load PI=3.14... +OptCategory[NN_fldl2t] = 1; // Load lg2(10) +OptCategory[NN_fldl2e] = 1; // Load lg2(e) +OptCategory[NN_fldlg2] = 1; // Load lg10(2) +OptCategory[NN_fldln2] = 1; // Load ln(2) +OptCategory[NN_finit] = 1; // Initialize Processor +OptCategory[NN_fninit] = 1; // Initialize Processor (no wait) +OptCategory[NN_fsetpm] = 1; // Set Protected Mode +OptCategory[NN_fldcw] = 1; // Load Control Word +OptCategory[NN_fstcw] = 0; // Store Control Word +OptCategory[NN_fnstcw] = 0; // Store Control Word (no wait) +OptCategory[NN_fstsw] = 2; // Store Status Word to memory or AX +OptCategory[NN_fnstsw] = 2; // Store Status Word (no wait) to memory or AX +OptCategory[NN_fclex] = 1; // Clear Exceptions +OptCategory[NN_fnclex] = 1; // Clear Exceptions (no wait) +OptCategory[NN_fstenv] = 0; // Store Environment +OptCategory[NN_fnstenv] = 0; // Store Environment (no wait) +OptCategory[NN_fldenv] = 1; // Load Environment +OptCategory[NN_fsave] = 0; // Save State +OptCategory[NN_fnsave] = 0; // Save State (no wait) +OptCategory[NN_frstor] = 1; // Restore State ** infer src is 'n' +OptCategory[NN_fincstp] = 1; // Increment Stack Pointer +OptCategory[NN_fdecstp] = 1; // Decrement Stack Pointer +OptCategory[NN_ffree] = 1; // Free Register +OptCategory[NN_fnop] = 1; // No Operation +OptCategory[NN_feni] = 1; // (8087 only) +OptCategory[NN_fneni] = 1; // (no wait) (8087 only) +OptCategory[NN_fdisi] = 1; // (8087 only) +OptCategory[NN_fndisi] = 1; // (no wait) (8087 only) + +// +// 80387 instructions +// + +OptCategory[NN_fprem1] = 1; // Partial Remainder ( < half ) +OptCategory[NN_fsincos] = 1; // t<-cos(st); st<-sin(st); push t +OptCategory[NN_fsin] = 1; // Sine +OptCategory[NN_fcos] = 1; // Cosine +OptCategory[NN_fucom] = 1; // Compare Unordered Real +OptCategory[NN_fucomp] = 1; // Compare Unordered Real and Pop +OptCategory[NN_fucompp] = 1; // Compare Unordered Real and Pop Twice + +// +// Instructions added 28.02.96 +// + +OptCategory[NN_setalc] = 2; // Set AL to Carry Flag ** +OptCategory[NN_svdc] = 0; // Save Register and Descriptor +OptCategory[NN_rsdc] = 0; // Restore Register and Descriptor +OptCategory[NN_svldt] = 0; // Save LDTR and Descriptor +OptCategory[NN_rsldt] = 0; // Restore LDTR and Descriptor +OptCategory[NN_svts] = 1; // Save TR and Descriptor +OptCategory[NN_rsts] = 1; // Restore TR and Descriptor +OptCategory[NN_icebp] = 1; // ICE Break Point +OptCategory[NN_loadall] = 0; // Load the entire CPU state from ES:EDI + +// +// MMX instructions +// + +OptCategory[NN_emms] = 1; // Empty MMX state +OptCategory[NN_movd] = 9; // Move 32 bits +OptCategory[NN_movq] = 9; // Move 64 bits +OptCategory[NN_packsswb] = 1; // Pack with Signed Saturation (Word->Byte) +OptCategory[NN_packssdw] = 1; // Pack with Signed Saturation (Dword->Word) +OptCategory[NN_packuswb] = 1; // Pack with Unsigned Saturation (Word->Byte) +OptCategory[NN_paddb] = 1; // Packed Add Byte +OptCategory[NN_paddw] = 1; // Packed Add Word +OptCategory[NN_paddd] = 1; // Packed Add Dword +OptCategory[NN_paddsb] = 1; // Packed Add with Saturation (Byte) +OptCategory[NN_paddsw] = 1; // Packed Add with Saturation (Word) +OptCategory[NN_paddusb] = 1; // Packed Add Unsigned with Saturation (Byte) +OptCategory[NN_paddusw] = 1; // Packed Add Unsigned with Saturation (Word) +OptCategory[NN_pand] = 1; // Bitwise Logical And +OptCategory[NN_pandn] = 1; // Bitwise Logical And Not +OptCategory[NN_pcmpeqb] = 1; // Packed Compare for Equal (Byte) +OptCategory[NN_pcmpeqw] = 1; // Packed Compare for Equal (Word) +OptCategory[NN_pcmpeqd] = 1; // Packed Compare for Equal (Dword) +OptCategory[NN_pcmpgtb] = 1; // Packed Compare for Greater Than (Byte) +OptCategory[NN_pcmpgtw] = 1; // Packed Compare for Greater Than (Word) +OptCategory[NN_pcmpgtd] = 1; // Packed Compare for Greater Than (Dword) +OptCategory[NN_pmaddwd] = 1; // Packed Multiply and Add +OptCategory[NN_pmulhw] = 1; // Packed Multiply High +OptCategory[NN_pmullw] = 1; // Packed Multiply Low +OptCategory[NN_por] = 1; // Bitwise Logical Or +OptCategory[NN_psllw] = 1; // Packed Shift Left Logical (Word) +OptCategory[NN_pslld] = 1; // Packed Shift Left Logical (Dword) +OptCategory[NN_psllq] = 1; // Packed Shift Left Logical (Qword) +OptCategory[NN_psraw] = 1; // Packed Shift Right Arithmetic (Word) +OptCategory[NN_psrad] = 1; // Packed Shift Right Arithmetic (Dword) +OptCategory[NN_psrlw] = 1; // Packed Shift Right Logical (Word) +OptCategory[NN_psrld] = 1; // Packed Shift Right Logical (Dword) +OptCategory[NN_psrlq] = 1; // Packed Shift Right Logical (Qword) +OptCategory[NN_psubb] = 1; // Packed Subtract Byte +OptCategory[NN_psubw] = 1; // Packed Subtract Word +OptCategory[NN_psubd] = 1; // Packed Subtract Dword +OptCategory[NN_psubsb] = 1; // Packed Subtract with Saturation (Byte) +OptCategory[NN_psubsw] = 1; // Packed Subtract with Saturation (Word) +OptCategory[NN_psubusb] = 1; // Packed Subtract Unsigned with Saturation (Byte) +OptCategory[NN_psubusw] = 1; // Packed Subtract Unsigned with Saturation (Word) +OptCategory[NN_punpckhbw] = 1; // Unpack High Packed Data (Byte->Word) +OptCategory[NN_punpckhwd] = 1; // Unpack High Packed Data (Word->Dword) +OptCategory[NN_punpckhdq] = 1; // Unpack High Packed Data (Dword->Qword) +OptCategory[NN_punpcklbw] = 1; // Unpack Low Packed Data (Byte->Word) +OptCategory[NN_punpcklwd] = 1; // Unpack Low Packed Data (Word->Dword) +OptCategory[NN_punpckldq] = 1; // Unpack Low Packed Data (Dword->Qword) +OptCategory[NN_pxor] = 1; // Bitwise Logical Exclusive Or + +// +// Undocumented Deschutes processor instructions +// + +OptCategory[NN_fxsave] = 1; // Fast save FP context ** to where? +OptCategory[NN_fxrstor] = 1; // Fast restore FP context ** from where? + +// Pentium II instructions + +OptCategory[NN_sysenter] = 1; // Fast Transition to System Call Entry Point +OptCategory[NN_sysexit] = 1; // Fast Transition from System Call Entry Point + +// 3DNow! instructions + +OptCategory[NN_pavgusb] = 1; // Packed 8-bit Unsigned Integer Averaging +OptCategory[NN_pfadd] = 1; // Packed Floating-Point Addition +OptCategory[NN_pfsub] = 1; // Packed Floating-Point Subtraction +OptCategory[NN_pfsubr] = 1; // Packed Floating-Point Reverse Subtraction +OptCategory[NN_pfacc] = 1; // Packed Floating-Point Accumulate +OptCategory[NN_pfcmpge] = 1; // Packed Floating-Point Comparison, Greater or Equal +OptCategory[NN_pfcmpgt] = 1; // Packed Floating-Point Comparison, Greater +OptCategory[NN_pfcmpeq] = 1; // Packed Floating-Point Comparison, Equal +OptCategory[NN_pfmin] = 1; // Packed Floating-Point Minimum +OptCategory[NN_pfmax] = 1; // Packed Floating-Point Maximum +OptCategory[NN_pi2fd] = 1; // Packed 32-bit Integer to Floating-Point +OptCategory[NN_pf2id] = 1; // Packed Floating-Point to 32-bit Integer +OptCategory[NN_pfrcp] = 1; // Packed Floating-Point Reciprocal Approximation +OptCategory[NN_pfrsqrt] = 1; // Packed Floating-Point Reciprocal Square Root Approximation +OptCategory[NN_pfmul] = 1; // Packed Floating-Point Multiplication +OptCategory[NN_pfrcpit1] = 1; // Packed Floating-Point Reciprocal First Iteration Step +OptCategory[NN_pfrsqit1] = 1; // Packed Floating-Point Reciprocal Square Root First Iteration Step +OptCategory[NN_pfrcpit2] = 1; // Packed Floating-Point Reciprocal Second Iteration Step +OptCategory[NN_pmulhrw] = 1; // Packed Floating-Point 16-bit Integer Multiply with rounding +OptCategory[NN_femms] = 1; // Faster entry/exit of the MMX or floating-point state +OptCategory[NN_prefetch] = 1; // Prefetch at least a 32-byte line into L1 data cache +OptCategory[NN_prefetchw] = 1; // Prefetch processor cache line into L1 data cache (mark as modified) + + +// Pentium III instructions + +OptCategory[NN_addps] = 1; // Packed Single-FP Add +OptCategory[NN_addss] = 1; // Scalar Single-FP Add +OptCategory[NN_andnps] = 1; // Bitwise Logical And Not for Single-FP +OptCategory[NN_andps] = 1; // Bitwise Logical And for Single-FP +OptCategory[NN_cmpps] = 1; // Packed Single-FP Compare +OptCategory[NN_cmpss] = 1; // Scalar Single-FP Compare +OptCategory[NN_comiss] = 1; // Scalar Ordered Single-FP Compare and Set EFLAGS +OptCategory[NN_cvtpi2ps] = 1; // Packed signed INT32 to Packed Single-FP conversion +OptCategory[NN_cvtps2pi] = 1; // Packed Single-FP to Packed INT32 conversion +OptCategory[NN_cvtsi2ss] = 1; // Scalar signed INT32 to Single-FP conversion +OptCategory[NN_cvtss2si] = 2; // Scalar Single-FP to signed INT32 conversion +OptCategory[NN_cvttps2pi] = 1; // Packed Single-FP to Packed INT32 conversion (truncate) +OptCategory[NN_cvttss2si] = 2; // Scalar Single-FP to signed INT32 conversion (truncate) +OptCategory[NN_divps] = 1; // Packed Single-FP Divide +OptCategory[NN_divss] = 1; // Scalar Single-FP Divide +OptCategory[NN_ldmxcsr] = 1; // Load Streaming SIMD Extensions Technology Control/Status Register +OptCategory[NN_maxps] = 1; // Packed Single-FP Maximum +OptCategory[NN_maxss] = 1; // Scalar Single-FP Maximum +OptCategory[NN_minps] = 1; // Packed Single-FP Minimum +OptCategory[NN_minss] = 1; // Scalar Single-FP Minimum +OptCategory[NN_movaps] = 9; // Move Aligned Four Packed Single-FP ** infer memsrc 'n'? +OptCategory[NN_movhlps] = 1; // Move High to Low Packed Single-FP +OptCategory[NN_movhps] = 1; // Move High Packed Single-FP +OptCategory[NN_movlhps] = 1; // Move Low to High Packed Single-FP +OptCategory[NN_movlps] = 1; // Move Low Packed Single-FP +OptCategory[NN_movmskps] = 1; // Move Mask to Register +OptCategory[NN_movss] = 9; // Move Scalar Single-FP +OptCategory[NN_movups] = 9; // Move Unaligned Four Packed Single-FP +OptCategory[NN_mulps] = 1; // Packed Single-FP Multiply +OptCategory[NN_mulss] = 1; // Scalar Single-FP Multiply +OptCategory[NN_orps] = 1; // Bitwise Logical OR for Single-FP Data +OptCategory[NN_rcpps] = 1; // Packed Single-FP Reciprocal +OptCategory[NN_rcpss] = 1; // Scalar Single-FP Reciprocal +OptCategory[NN_rsqrtps] = 1; // Packed Single-FP Square Root Reciprocal +OptCategory[NN_rsqrtss] = 1; // Scalar Single-FP Square Root Reciprocal +OptCategory[NN_shufps] = 1; // Shuffle Single-FP +OptCategory[NN_sqrtps] = 1; // Packed Single-FP Square Root +OptCategory[NN_sqrtss] = 1; // Scalar Single-FP Square Root +OptCategory[NN_stmxcsr] = 0; // Store Streaming SIMD Extensions Technology Control/Status Register ** Infer dest is 'n' +OptCategory[NN_subps] = 1; // Packed Single-FP Subtract +OptCategory[NN_subss] = 1; // Scalar Single-FP Subtract +OptCategory[NN_ucomiss] = 1; // Scalar Unordered Single-FP Compare and Set EFLAGS +OptCategory[NN_unpckhps] = 1; // Unpack High Packed Single-FP Data +OptCategory[NN_unpcklps] = 1; // Unpack Low Packed Single-FP Data +OptCategory[NN_xorps] = 1; // Bitwise Logical XOR for Single-FP Data +OptCategory[NN_pavgb] = 1; // Packed Average (Byte) +OptCategory[NN_pavgw] = 1; // Packed Average (Word) +OptCategory[NN_pextrw] = 2; // Extract Word +OptCategory[NN_pinsrw] = 1; // Insert Word +OptCategory[NN_pmaxsw] = 1; // Packed Signed Integer Word Maximum +OptCategory[NN_pmaxub] = 1; // Packed Unsigned Integer Byte Maximum +OptCategory[NN_pminsw] = 1; // Packed Signed Integer Word Minimum +OptCategory[NN_pminub] = 1; // Packed Unsigned Integer Byte Minimum +OptCategory[NN_pmovmskb] = 1; // Move Byte Mask to Integer +OptCategory[NN_pmulhuw] = 1; // Packed Multiply High Unsigned +OptCategory[NN_psadbw] = 1; // Packed Sum of Absolute Differences +OptCategory[NN_pshufw] = 1; // Packed Shuffle Word +OptCategory[NN_maskmovq] = 0; // Byte Mask write ** Infer dest is 'n' +OptCategory[NN_movntps] = 0; // Move Aligned Four Packed Single-FP Non Temporal * infer dest is 'n' +OptCategory[NN_movntq] = 0; // Move 64 Bits Non Temporal ** Infer dest is 'n' +OptCategory[NN_prefetcht0] = 1; // Prefetch to all cache levels +OptCategory[NN_prefetcht1] = 1; // Prefetch to all cache levels +OptCategory[NN_prefetcht2] = 1; // Prefetch to L2 cache +OptCategory[NN_prefetchnta] = 1; // Prefetch to L1 cache +OptCategory[NN_sfence] = 1; // Store Fence + +// Pentium III Pseudo instructions + +OptCategory[NN_cmpeqps] = 1; // Packed Single-FP Compare EQ +OptCategory[NN_cmpltps] = 1; // Packed Single-FP Compare LT +OptCategory[NN_cmpleps] = 1; // Packed Single-FP Compare LE +OptCategory[NN_cmpunordps] = 1; // Packed Single-FP Compare UNORD +OptCategory[NN_cmpneqps] = 1; // Packed Single-FP Compare NOT EQ +OptCategory[NN_cmpnltps] = 1; // Packed Single-FP Compare NOT LT +OptCategory[NN_cmpnleps] = 1; // Packed Single-FP Compare NOT LE +OptCategory[NN_cmpordps] = 1; // Packed Single-FP Compare ORDERED +OptCategory[NN_cmpeqss] = 1; // Scalar Single-FP Compare EQ +OptCategory[NN_cmpltss] = 1; // Scalar Single-FP Compare LT +OptCategory[NN_cmpless] = 1; // Scalar Single-FP Compare LE +OptCategory[NN_cmpunordss] = 1; // Scalar Single-FP Compare UNORD +OptCategory[NN_cmpneqss] = 1; // Scalar Single-FP Compare NOT EQ +OptCategory[NN_cmpnltss] = 1; // Scalar Single-FP Compare NOT LT +OptCategory[NN_cmpnless] = 1; // Scalar Single-FP Compare NOT LE +OptCategory[NN_cmpordss] = 1; // Scalar Single-FP Compare ORDERED + +// AMD K7 instructions + +// Revisit AMD if we port to it. +OptCategory[NN_pf2iw] = 0; // Packed Floating-Point to Integer with Sign Extend +OptCategory[NN_pfnacc] = 0; // Packed Floating-Point Negative Accumulate +OptCategory[NN_pfpnacc] = 0; // Packed Floating-Point Mixed Positive-Negative Accumulate +OptCategory[NN_pi2fw] = 0; // Packed 16-bit Integer to Floating-Point +OptCategory[NN_pswapd] = 0; // Packed Swap Double Word + +// Undocumented FP instructions (thanks to norbert.juffa@adm.com) + +OptCategory[NN_fstp1] = 9; // Alias of Store Real and Pop +OptCategory[NN_fcom2] = 1; // Alias of Compare Real +OptCategory[NN_fcomp3] = 1; // Alias of Compare Real and Pop +OptCategory[NN_fxch4] = 1; // Alias of Exchange Registers +OptCategory[NN_fcomp5] = 1; // Alias of Compare Real and Pop +OptCategory[NN_ffreep] = 1; // Free Register and Pop +OptCategory[NN_fxch7] = 1; // Alias of Exchange Registers +OptCategory[NN_fstp8] = 9; // Alias of Store Real and Pop +OptCategory[NN_fstp9] = 9; // Alias of Store Real and Pop + +// Pentium 4 instructions + +OptCategory[NN_addpd] = 1; // Add Packed Double-Precision Floating-Point Values +OptCategory[NN_addsd] = 1; // Add Scalar Double-Precision Floating-Point Values +OptCategory[NN_andnpd] = 1; // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values +OptCategory[NN_andpd] = 1; // Bitwise Logical AND of Packed Double-Precision Floating-Point Values +OptCategory[NN_clflush] = 1; // Flush Cache Line +OptCategory[NN_cmppd] = 1; // Compare Packed Double-Precision Floating-Point Values +OptCategory[NN_cmpsd] = 1; // Compare Scalar Double-Precision Floating-Point Values +OptCategory[NN_comisd] = 1; // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS +OptCategory[NN_cvtdq2pd] = 1; // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values +OptCategory[NN_cvtdq2ps] = 1; // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values +OptCategory[NN_cvtpd2dq] = 1; // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers +OptCategory[NN_cvtpd2pi] = 1; // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers +OptCategory[NN_cvtpd2ps] = 1; // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values +OptCategory[NN_cvtpi2pd] = 1; // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values +OptCategory[NN_cvtps2dq] = 1; // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers +OptCategory[NN_cvtps2pd] = 1; // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values +OptCategory[NN_cvtsd2si] = 2; // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer +OptCategory[NN_cvtsd2ss] = 1; // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value +OptCategory[NN_cvtsi2sd] = 1; // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value +OptCategory[NN_cvtss2sd] = 1; // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value +OptCategory[NN_cvttpd2dq] = 1; // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers +OptCategory[NN_cvttpd2pi] = 1; // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers +OptCategory[NN_cvttps2dq] = 1; // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers +OptCategory[NN_cvttsd2si] = 2; // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer +OptCategory[NN_divpd] = 1; // Divide Packed Double-Precision Floating-Point Values +OptCategory[NN_divsd] = 1; // Divide Scalar Double-Precision Floating-Point Values +OptCategory[NN_lfence] = 1; // Load Fence +OptCategory[NN_maskmovdqu] = 0; // Store Selected Bytes of Double Quadword ** Infer dest is 'n' +OptCategory[NN_maxpd] = 1; // Return Maximum Packed Double-Precision Floating-Point Values +OptCategory[NN_maxsd] = 1; // Return Maximum Scalar Double-Precision Floating-Point Value +OptCategory[NN_mfence] = 1; // Memory Fence +OptCategory[NN_minpd] = 1; // Return Minimum Packed Double-Precision Floating-Point Values +OptCategory[NN_minsd] = 1; // Return Minimum Scalar Double-Precision Floating-Point Value +OptCategory[NN_movapd] = 9; // Move Aligned Packed Double-Precision Floating-Point Values ** Infer dest is 'n' +OptCategory[NN_movdq2q] = 1; // Move Quadword from XMM to MMX Register +OptCategory[NN_movdqa] = 9; // Move Aligned Double Quadword ** Infer dest is 'n' +OptCategory[NN_movdqu] = 9; // Move Unaligned Double Quadword ** Infer dest is 'n' +OptCategory[NN_movhpd] = 9; // Move High Packed Double-Precision Floating-Point Values ** Infer dest is 'n' +OptCategory[NN_movlpd] = 9; // Move Low Packed Double-Precision Floating-Point Values ** Infer dest is 'n' +OptCategory[NN_movmskpd] = 2; // Extract Packed Double-Precision Floating-Point Sign Mask +OptCategory[NN_movntdq] = 0; // Store Double Quadword Using Non-Temporal Hint +OptCategory[NN_movnti] = 0; // Store Doubleword Using Non-Temporal Hint +OptCategory[NN_movntpd] = 0; // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint +OptCategory[NN_movq2dq] = 1; // Move Quadword from MMX to XMM Register +OptCategory[NN_movsd] = 9; // Move Scalar Double-Precision Floating-Point Values +OptCategory[NN_movupd] = 9; // Move Unaligned Packed Double-Precision Floating-Point Values +OptCategory[NN_mulpd] = 1; // Multiply Packed Double-Precision Floating-Point Values +OptCategory[NN_mulsd] = 1; // Multiply Scalar Double-Precision Floating-Point Values +OptCategory[NN_orpd] = 1; // Bitwise Logical OR of Double-Precision Floating-Point Values +OptCategory[NN_paddq] = 1; // Add Packed Quadword Integers +OptCategory[NN_pause] = 1; // Spin Loop Hint +OptCategory[NN_pmuludq] = 1; // Multiply Packed Unsigned Doubleword Integers +OptCategory[NN_pshufd] = 1; // Shuffle Packed Doublewords +OptCategory[NN_pshufhw] = 1; // Shuffle Packed High Words +OptCategory[NN_pshuflw] = 1; // Shuffle Packed Low Words +OptCategory[NN_pslldq] = 1; // Shift Double Quadword Left Logical +OptCategory[NN_psrldq] = 1; // Shift Double Quadword Right Logical +OptCategory[NN_psubq] = 1; // Subtract Packed Quadword Integers +OptCategory[NN_punpckhqdq] = 1; // Unpack High Data +OptCategory[NN_punpcklqdq] = 1; // Unpack Low Data +OptCategory[NN_shufpd] = 1; // Shuffle Packed Double-Precision Floating-Point Values +OptCategory[NN_sqrtpd] = 1; // Compute Square Roots of Packed Double-Precision Floating-Point Values +OptCategory[NN_sqrtsd] = 1; // Compute Square Rootof Scalar Double-Precision Floating-Point Value +OptCategory[NN_subpd] = 1; // Subtract Packed Double-Precision Floating-Point Values +OptCategory[NN_subsd] = 1; // Subtract Scalar Double-Precision Floating-Point Values +OptCategory[NN_ucomisd] = 1; // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS +OptCategory[NN_unpckhpd] = 1; // Unpack and Interleave High Packed Double-Precision Floating-Point Values +OptCategory[NN_unpcklpd] = 1; // Unpack and Interleave Low Packed Double-Precision Floating-Point Values +OptCategory[NN_xorpd] = 1; // Bitwise Logical OR of Double-Precision Floating-Point Values + + +// AMD syscall/sysret instructions NOTE: not AMD, found in Intel manual + +OptCategory[NN_syscall] = 1; // Low latency system call +OptCategory[NN_sysret] = 1; // Return from system call + +// AMD64 instructions NOTE: not AMD, found in Intel manual + +OptCategory[NN_swapgs] = 1; // Exchange GS base with KernelGSBase MSR + +// New Pentium instructions (SSE3) + +OptCategory[NN_movddup] = 9; // Move One Double-FP and Duplicate +OptCategory[NN_movshdup] = 9; // Move Packed Single-FP High and Duplicate +OptCategory[NN_movsldup] = 9; // Move Packed Single-FP Low and Duplicate + +// Missing AMD64 instructions NOTE: also found in Intel manual + +OptCategory[NN_movsxd] = 2; // Move with Sign-Extend Doubleword +OptCategory[NN_cmpxchg16b] = 0; // Compare and Exchange 16 Bytes + +// SSE3 instructions + +OptCategory[NN_addsubpd] = 1; // Add /Sub packed DP FP numbers +OptCategory[NN_addsubps] = 1; // Add /Sub packed SP FP numbers +OptCategory[NN_haddpd] = 1; // Add horizontally packed DP FP numbers +OptCategory[NN_haddps] = 1; // Add horizontally packed SP FP numbers +OptCategory[NN_hsubpd] = 1; // Sub horizontally packed DP FP numbers +OptCategory[NN_hsubps] = 1; // Sub horizontally packed SP FP numbers +OptCategory[NN_monitor] = 1; // Set up a linear address range to be monitored by hardware +OptCategory[NN_mwait] = 1; // Wait until write-back store performed within the range specified by the MONITOR instruction +OptCategory[NN_fisttp] = 2; // Store ST in intXX (chop) and pop +OptCategory[NN_lddqu] = 0; // Load unaligned integer 128-bit + +// SSSE3 instructions + +OptCategory[NN_psignb] = 1; // Packed SIGN Byte +OptCategory[NN_psignw] = 1; // Packed SIGN Word +OptCategory[NN_psignd] = 1; // Packed SIGN Doubleword +OptCategory[NN_pshufb] = 1; // Packed Shuffle Bytes +OptCategory[NN_pmulhrsw] = 1; // Packed Multiply High with Round and Scale +OptCategory[NN_pmaddubsw] = 1; // Multiply and Add Packed Signed and Unsigned Bytes +OptCategory[NN_phsubsw] = 1; // Packed Horizontal Subtract and Saturate +OptCategory[NN_phaddsw] = 1; // Packed Horizontal Add and Saturate +OptCategory[NN_phaddw] = 1; // Packed Horizontal Add Word +OptCategory[NN_phaddd] = 1; // Packed Horizontal Add Doubleword +OptCategory[NN_phsubw] = 1; // Packed Horizontal Subtract Word +OptCategory[NN_phsubd] = 1; // Packed Horizontal Subtract Doubleword +OptCategory[NN_palignr] = 1; // Packed Align Right +OptCategory[NN_pabsb] = 1; // Packed Absolute Value Byte +OptCategory[NN_pabsw] = 1; // Packed Absolute Value Word +OptCategory[NN_pabsd] = 1; // Packed Absolute Value Doubleword + +// VMX instructions + +OptCategory[NN_vmcall] = 1; // Call to VM Monitor +OptCategory[NN_vmclear] = 0; // Clear Virtual Machine Control Structure +OptCategory[NN_vmlaunch] = 1; // Launch Virtual Machine +OptCategory[NN_vmresume] = 1; // Resume Virtual Machine +OptCategory[NN_vmptrld] = 6; // Load Pointer to Virtual Machine Control Structure +OptCategory[NN_vmptrst] = 0; // Store Pointer to Virtual Machine Control Structure +OptCategory[NN_vmread] = 0; // Read Field from Virtual Machine Control Structure +OptCategory[NN_vmwrite] = 0; // Write Field from Virtual Machine Control Structure +OptCategory[NN_vmxoff] = 1; // Leave VMX Operation +OptCategory[NN_vmxon] = 1; // Enter VMX Operation + +OptCategory[NN_last] = 1; + + return; + +} // end InitOptCategory() + + + +