// // SMPStaticAnalyzer.cpp // // This plugin performs the static analyses needed for the SMP project // (Software Memory Protection). // #include <list> #include <vector> #include <string> #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 <nalt.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 0 // 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 #define SMP_DEBUG_ORPHANS 1 // find code outside of functions #define SMP_DEBUG_CHUNKS 0 // restructuring tail chunks, shared chunks, etc. #define SMP_DEBUG_DATA_ONLY 0 // Find & fix data addresses in code segments // 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 SMP_FIXUP_IDB 1 // Try to fix the IDA database? #define SMP_DEBUG_FIXUP_IDB 0 // debugging output for FixupIDB chain // 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}; // Filename (not including path) of executable being analyzed. static char RootFileName[MAXSTR]; // Code addresses identified by a disassembler, such as objdump on // Linux. These can be used to improve the code vs. data identification // of IDA Pro. vector<ea_t> DisasmLocs; // Code addresses as identified by IDA Pro, to be compared to DisasmLocs. vector<ea_t> IDAProLocs; // Function start and end addresses (for function entry chunks only). // Kept here because IDA Pro 5.1 seems to have a memory overwriting // problem when iterating through all functions in the program. An existing // func_t *ChunkInfo data structure was getting overwritten by one of the // function func_t data structures, causing changes of startEA and endEA among // other things. struct SMP_bounds_t { ea_t startEA; ea_t endEA; }; vector<SMP_bounds_t> FuncBounds; // List of functions that need to be reanalyzed after all the code fixup // and code discovery is complete. Kept as a list of addresses; any address // within the function is good enough to designate it. list<ea_t> ReanalyzeList; void IDAP_run(int); // Functions for diagnosing and/or fixing problems in the IDA database. void FixupIDB(void); // Driver for all other fixing functions. void FindDataInCode(void); void AuditTailChunkOwnership(void); void FindOrphanedCode(segment_t *, FILE *); void FixCodeIdentification(void); void AuditCodeTargets(void); ea_t FindNewFuncLimit(ea_t); void SpecialDebugOutput(void); void RemoveIDACodeAddr(ea_t); 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; SMPFunction *CurrFunc = NULL; bool FuncsDumped = false; #if SMP_DEBUG2 char FuncName[MAXSTR]; #endif #if SMP_DEBUG msg("Beginning IDAP_run.\n"); #endif // Open the output file. ssize_t FileLen; FileLen = get_root_filename(RootFileName, sizeof(RootFileName) - 1); string SymsFileName(RootFileName); string FileSuffix(".annot"); SymsFileName += FileSuffix; SymsFile = qfopen(SymsFileName.c_str(), "w"); if (NULL == SymsFile) { error("FATAL: Cannot open output file %s\n", SymsFileName.c_str()); return; } (void) memset(OptCount, 0, sizeof(OptCount)); (void) memset(AnnotationCount, 0, sizeof(AnnotationCount)); // Record the start and end addresses for all function entry // chunks in the program. FuncBounds.reserve(10 + get_func_qty()); for (size_t FuncIndex = 0; FuncIndex < get_func_qty(); ++FuncIndex) { func_t *FuncInfo = getn_func(FuncIndex); SMP_bounds_t temp; temp.startEA = FuncInfo->startEA; temp.endEA = FuncInfo->endEA; FuncBounds.push_back(temp); } #if SMP_DEBUG_DATA_ONLY FindDataInCode(); FixCodeIdentification(); qfclose(SymsFile); return; #endif // Pre-audit the IDA database by seeing if the distinction // between code and data can be improved, and if all branches // and calls have proper code targets and code cross references. #if SMP_FIXUP_IDB FixupIDB(); #endif // 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) { char SegName[MAXSTR]; seg = getnseg(SegIndex); ssize_t SegNameSize = get_segm_name(seg, SegName, sizeof(SegName) - 1); // 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", seg->type); if (SegNameSize > 0) msg(" SegName: %s\n", SegName); else msg("\n"); 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"); if (SegNameSize > 0) msg(" SegName: %s\n", SegName); else msg("\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; ...) #if SMP_DEBUG_ORPHANS FindOrphanedCode(seg, SymsFile); #endif } // end else if (seg->type === SEG_CODE) else { #if SMP_DEBUG msg("Not processing segment of type %d SegName: %s\n", seg->type, SegName); #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 }; // Find all code addresses in the IDA database and enter them into // IDAProLocs. Find all code addresses identified by the external // disassembler (e.g. objdump) and enter them into DisasmLocs. void FindCodeAddresses(void) { // Read in code addresses as found by an external disassembler. ea_t CurrDisasmAddr; string DisasmFileName(RootFileName); string FileSuffix(".SMPobjdump"); DisasmFileName += FileSuffix; FILE *DisasmFile = qfopen(DisasmFileName.c_str(), "r"); if (NULL == DisasmFile) { error("FATAL: Cannot open input file %s\n", DisasmFileName.c_str()); return; } #define DISASM_RESERVE_SIZE 50000 DisasmLocs.reserve(DISASM_RESERVE_SIZE); int ScanReturn = qfscanf(DisasmFile, "%x", &CurrDisasmAddr); while (1 == ScanReturn) { int NextChar; DisasmLocs.push_back(CurrDisasmAddr); // Swallow the rest of the input line and get the next address. do { NextChar = qfgetc(DisasmFile); } while ((EOF != NextChar) && ('\n' != NextChar)); ScanReturn = qfscanf(DisasmFile, "%x", &CurrDisasmAddr); } // end while (1 == ScanReturn) if (0 >= DisasmLocs.size()) { msg("ERROR: No addresses read from %s\n", DisasmFileName.c_str()); qfclose(DisasmFile); return; } else { msg("%d Disasm addresses read from %s\n", DisasmLocs.size(), DisasmFileName.c_str()); qfclose(DisasmFile); } // Find all the code locs in the IDA Pro database. As we find // them, store them in IDAProLocs. for (int SegIndex = 0; SegIndex < get_segm_qty(); ++SegIndex) { segment_t *seg = getnseg(SegIndex); if (SEG_CODE != seg->type) continue; for (ea_t addr = seg->startEA; addr < seg->endEA; addr = get_item_end(addr)) { flags_t InstrFlags = getFlags(addr); if (isHead(InstrFlags) && isCode(InstrFlags)) { IDAProLocs.push_back(addr); if ((0x806cda4 <= addr) && (0x806cf99 >= addr)) msg("IDA code addr: %x\n", addr); } // end if (isHead(addr) && isCode(addr) #if SMP_DEBUG_FIXUP_IDB else if ((0x806cda4 <= addr) && (0x806cf99 >= addr)) { if (!isHead(InstrFlags)) msg("Weirdness: not isHead at %x\n", addr); if (isUnknown(InstrFlags)) { msg("Weirdness: isUnknown at %x\n", addr); } } #endif } // end for (ea_t addr = seg->startEA; ...) } // end for (int SegIndex = 0; ...) return; } // end FindCodeAddresses() // Return true if addr is not a proper beginning address for an instruction. // Return false otherwise. // Currently, we claim that an instruction is misaligned if DisasmLocs does // not contain it. This function is useful for dealing with errors in IDA // code identification, in which a large code section is identified as data, // but some instructions in the middle of the "data" are identified as // code but IDA often starts on the wrong boundary in these cases. bool IsCodeMisaligned(ea_t addr) { // Do a binary search for addr within DisasmLocs, which is sorted // in ascending address order because of the way in which it was // generated. size_t min = 0; size_t max = DisasmLocs.size(); // don't access DisasmLocs[max] size_t index = (min + max) / 2; while (addr != DisasmLocs[index]) { if (min >= (max - 1)) return true; #if 0 msg("min: %d max: %d index: %d\n", min, max, index); #endif if (addr < DisasmLocs[index]) max = index; else // must be addr > DisasmLocs[index]; min = index; index = (min + max) / 2; } return false; } // end of IsCodeMisaligned() void RemoveIDACodeAddr(ea_t addr) { // Do a binary search for addr within IDAProLocs, which is sorted // in ascending address order because of the way in which it was // generated. Delete the element of IDAProLocs if found. size_t min = 0; size_t max = IDAProLocs.size(); // don't access IDAProLocs[max] size_t index = (min + max) / 2; while (addr != IDAProLocs[index]) { if (min >= (max - 1)) return; #if 0 msg("min: %d max: %d index: %d\n", min, max, index); #endif if (addr < IDAProLocs[index]) max = index; else // must be addr > IDAProLocs[index]; min = index; index = (min + max) / 2; } // IDAProLocs[index] contains addr. vector<ea_t>::iterator RemovalIterator = IDAProLocs.begin(); RemovalIterator += index; RemovalIterator = IDAProLocs.erase(RemovalIterator); return; } // end of RemoveIDACodeAddr() // Driver for all other fixing functions. Upon its return, the IDA // database (IDB file) should be fixed up as much as we can fix it. void FixupIDB(void) { FindCodeAddresses(); #if SMP_DEBUG_FIXUP_IDB SpecialDebugOutput(); #endif AuditCodeTargets(); FindDataInCode(); AuditTailChunkOwnership(); FixCodeIdentification(); #if SMP_DEBUG_FIXUP_IDB SpecialDebugOutput(); #endif } // end of FixupIDB() // Find and print all data head addresses in code segments. // If an isolated code instruction is found in the midst of a run // of data bytes and has no code xrefs jumping to it, it is not // reachable as code and is undoubtedly a mixup by IDA. Possibly // the whole data region will be converted to code later, in which // case the isolated code is not necessarily properly aligned and // parsed at its present address, so we are glad to convert it into // data anyway so that FindDataToConvert() will succeed on it later. // Data to code conversion, and isolated code detection, are inhibited // by IDA identifying several consecutive instructions in the midst // of a data region, with the code addresses not agreeing with the // external disassembler's code addresses. We will convert these // misaligned instructions to data as we detect them. We will also // convert unexplored bytes (isUnknown(flags) == true) into data if // they are in the midst of a data sequence. #define MIN_DATARUN_LEN 24 // #bytes on either side of "isolated" code void FindDataInCode(void) { size_t DataRunLen = 0; // How many data bytes in a row have we seen? bool IsolatedCodeTrigger = false; // Have seen data, then isolated code // Now looking for data ea_t IsolatedCodeAddr; int IsolatedCodeLen; int InstrLen; for (int SegIndex = 0; SegIndex < get_segm_qty(); ++SegIndex) { char SegName[MAXSTR]; segment_t *seg = getnseg(SegIndex); ssize_t SegNameSize = get_segm_name(seg, SegName, sizeof(SegName) - 1); if (SEG_CODE != seg->type) continue; #if SMP_DEBUG_FIXUP_IDB msg("Non-code addresses for code segment %s from %x to %x\n", SegName, seg->startEA, seg->endEA); #endif for (ea_t addr = seg->startEA; addr < seg->endEA; addr = get_item_end(addr)) { flags_t AddrFlags = getFlags(addr); if (isHead(AddrFlags)) { if (isData(AddrFlags)) { DataRunLen += get_item_size(addr); #if SMP_DEBUG_FIXUP_IDB msg("Data: %x\n", addr); #endif if (MIN_DATARUN_LEN <= DataRunLen) { if (IsolatedCodeTrigger) { // Saw data, then one isolated code, then data do_unknown_range(IsolatedCodeAddr, IsolatedCodeLen, DOUNK_SIMPLE); RemoveIDACodeAddr(IsolatedCodeAddr); if (do_data_ex(IsolatedCodeAddr, byteflag(), IsolatedCodeLen, BADNODE)) { msg("Converted isolated code to data: %x\n", IsolatedCodeAddr); } else { msg("Failed to convert isolated code to data: %x len: %x\n", IsolatedCodeAddr, IsolatedCodeLen); } IsolatedCodeTrigger = false; } // end if (IsolatedCodeTrigger) } // end if (MIN_DATARUN_LEN <= DataRunLen) } // end if (isData(AddrFlags) else if (isUnknown(AddrFlags)) { // Just in case; unknown usually means not head or tail // If in a data run, convert to data. InstrLen = get_item_size(addr); msg("Unknown: %x len: %x\n", addr, InstrLen); if (0 < DataRunLen) { if (do_data_ex(addr, byteflag(), InstrLen, BADNODE)) { msg("Converted unknown to data at %x len: %x\n", addr, InstrLen); DataRunLen += InstrLen; } else { msg("Failed to convert unknown to data at %x len: %x\n", addr, InstrLen); DataRunLen = 0; IsolatedCodeTrigger = false; } } } else if (isCode(AddrFlags)) { // must be true if (MIN_DATARUN_LEN <= DataRunLen) { msg("DataRunLen: %d at %x\n", DataRunLen, addr); InstrLen = ua_ana0(addr); #if SMP_DEBUG_FIXUP_IDB msg("Calling IsCodeMisaligned: len %d\n", InstrLen); #endif if (IsCodeMisaligned(addr)) { #if SMP_DEBUG_FIXUP_IDB msg("Code was misaligned.\n"); #endif do_unknown_range(addr, InstrLen, DOUNK_SIMPLE); RemoveIDACodeAddr(addr); if (do_data_ex(addr, byteflag(), InstrLen, BADNODE)) { msg("Converted misaligned code to data at %x : len: %x\n", addr, InstrLen); // Step back so data gets processed. DataRunLen += get_item_size(addr); continue; // skip reset of DataRunLen } else { msg("Misaligned code left as unknown at %x : len: %x\n", addr, InstrLen); IsolatedCodeTrigger = false; } } // end if (IsCodeMisaligned() ...) else if (!hasRef(AddrFlags)) { // No references at all --> isolated code. IsolatedCodeTrigger = true; IsolatedCodeAddr = addr; IsolatedCodeLen = InstrLen; } else { xrefblk_t xb; bool ok = xb.first_to(IsolatedCodeAddr, XREF_ALL); if (!ok) { // No code xrefs to this target addr. IsolatedCodeTrigger = true; IsolatedCodeAddr = addr; IsolatedCodeLen = InstrLen; } } } // end if (MIN_DATARUN_LEN <= DataRunLen) else if (IsolatedCodeTrigger) { // Two instructions in a row does not fit the pattern. IsolatedCodeTrigger = false; } DataRunLen = 0; } // end if (isData) ... else if (isUnknown) ... else isCode } // end if (isHead) else if (isUnknown(AddrFlags)) { // If in a data run, convert to data. InstrLen = get_item_size(addr); msg("Unknown: %x len: %x\n", addr, InstrLen); if (0 < DataRunLen) { if (do_data_ex(addr, byteflag(), InstrLen, BADNODE)) { msg("Converted unknown to data at %x len: %x\n", addr, InstrLen); DataRunLen += InstrLen; } else { msg("Failed to convert unknown to data at %x len: %x\n", addr, InstrLen); DataRunLen = 0; IsolatedCodeTrigger = false; } } } } // end for (ea_t addr = seg->startEA; ...) } // end for (int SegIndex = 0; ...) return; } // end of FindDataInCode() // The choices that IDA makes for deciding which parent function of a // TAIL chunk is the primary owner of the tail can be counterintuitive. // A function entry can both fall into and jump to a tail chunk that // is contiguous with it, yet the "owner" might be a function that is // far below it in the executable address space. This function will // change the ownership to a more sensible arrangement. void AuditTailChunkOwnership(void) { char FuncName[MAXSTR]; // Iterate through all chunks in the program. for (size_t ChunkIndex = 0; ChunkIndex < get_fchunk_qty(); ++ChunkIndex) { func_t *ChunkInfo = getn_fchunk((int) ChunkIndex); if (is_func_tail(ChunkInfo)) { // For each TAIL chunk, find all the parent chunks. Find the last // parent chunk with an address less than the TAIL chunk address. ea_t BestCandidate = 0; func_parent_iterator_t FuncParent(ChunkInfo); #if SMP_DEBUG_CHUNKS msg("Tail chunk: %x ", ChunkInfo->startEA); #endif for (bool ok = FuncParent.first(); ok; ok = FuncParent.next()) { ea_t parent = FuncParent.parent(); #if SMP_DEBUG_CHUNKS msg(" parent: %x ", parent); #endif if ((parent > BestCandidate) && (parent < ChunkInfo->startEA)) BestCandidate = parent; } #if SMP_DEBUG_CHUNKS msg("\n"); #endif // Make the best parent chunk the owner of the TAIL chunk if it is // not already the owner. if (ChunkInfo->owner != BestCandidate) { if (0 < BestCandidate) { if (set_tail_owner(ChunkInfo, BestCandidate)) { func_t *FuncInfo = get_func(BestCandidate); msg("Set %x as new owner of tail %x\n", BestCandidate, ChunkInfo->startEA); // Reanalyze the parent function (and all its // tail chunks) now that the structure has changed. reanalyze_function(FuncInfo); } else { msg("set_tail_owner failed for tail %x and parent %x\n", ChunkInfo->startEA, BestCandidate); } } else { func_t *FuncInfo = get_func(ChunkInfo->owner); get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName) - 1); #if SMP_DEBUG_CHUNKS msg("No good parent candidate before tail at %x\n", ChunkInfo->startEA); msg("Current parent is %x: %s\n", FuncInfo->startEA, FuncName); #endif // Find out if a function entry chunk that comes before the // tail is a better candidate for the owner (i.e. it falls // through to the tail, or jumps to it). BestCandidate = 0; #if SMP_DEBUG_CHUNKS msg("Finding parent func candidates for %x:", ChunkInfo->startEA); #endif SMP_bounds_t CurrFunc; for (size_t FuncIndex = 0; FuncIndex < FuncBounds.size(); ++FuncIndex) { CurrFunc = FuncBounds[FuncIndex]; if ((CurrFunc.startEA < ChunkInfo->startEA) && (CurrFunc.startEA > BestCandidate)) { BestCandidate = CurrFunc.startEA; #if SMP_DEBUG_CHUNKS msg(" candidate: %x tail: %x", BestCandidate, ChunkInfo->startEA); #endif } else { #if SMP_DEBUG_CHUNKS msg(" not a candidate: %x tail: %x best: %x\n", CurrFunc.startEA, ChunkInfo->startEA, BestCandidate); #endif break; } } // end for (size_t FuncIndex = 0; ...) if (0 >= BestCandidate) { // highly unlikely msg("No good func entry parent candidate.\n"); } else { FuncInfo = get_func(BestCandidate); get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName) - 1); #if SMP_DEBUG_CHUNKS msg("Best func entry parent candidate: %s at %x", FuncName, BestCandidate); if (FuncInfo->endEA == ChunkInfo->startEA) msg(" Function endEA == tail chunk startEA"); msg("\n"); #endif } } } // end if (ChunkInfo->owner != BestCandidate) #if SMP_DEBUG_CHUNKS else { msg("Already best parent for %x is %x\n", ChunkInfo->startEA, ChunkInfo->owner); } #endif } // end if (is_func_tail(ChunkInfo)) } // end for (size_t ChunkIndex = 0; ...) return; } // end of AuditTailChunkOwnership() // If the addresses signified from DisasmIndex to IDAProIndex are // all considered data and do NOT follow a return instruction, // return false and update AreaSize to reflect the area to be // converted. // Return value: true -> skip to IDAProIndex; false -> convert AreaSize bytes. bool FindDataToConvert(size_t IDAProIndex, size_t DisasmIndex, int &AreaSize) { ea_t PrevIDAAddr; ea_t NextIDAAddr; size_t ShadowDisasmIndex = DisasmIndex - 1; ea_t DisasmAddr = DisasmLocs[ShadowDisasmIndex]; bool CannotConvert = false; // return value bool DebugAddress = false; #if SMP_DEBUG_FIXUP_IDB DebugAddress = (DisasmAddr == 0x806c19a); #endif if (DebugAddress) { msg("IDAProIndex: %d DisasmIndex: %d\n", IDAProIndex, DisasmIndex); msg("IDA locs size %d Disasm locs size %d\n", IDAProLocs.size(), DisasmLocs.size()); } if (IDAProIndex >= IDAProLocs.size()) { // Have already processed the last IDA address. if (DebugAddress) msg(" Already done with IDAProLocs.\n"); return true; } else if (DisasmIndex >= DisasmLocs.size()) { // Strange. Last Disasm address is only one to convert, and // IDA still has addresses after that? if (DebugAddress) msg(" Already done with DisasmLocs.\n"); return true; } else if (IDAProIndex < 2) { // We have Disasm addrs before the very first IDA addr. We // don't trust this boundary case. if (DebugAddress) msg(" Boundary case with IDAProLocs.\n"); return true; } NextIDAAddr = IDAProLocs[IDAProIndex - 1]; PrevIDAAddr = IDAProLocs[IDAProIndex - 2]; if (DebugAddress) msg(" PrevIDAAddr: %x NextIDAAddr: %x\n", PrevIDAAddr, NextIDAAddr); // See if previous IDA address was a return. flags_t PrevFlags = getFlags(PrevIDAAddr); if (!isCode(PrevFlags) || !isHead(PrevFlags)) { msg("PrevIDAAddr %x not isCode or not isHead.\n", PrevIDAAddr); return true; } SMPInstr PrevInstr(PrevIDAAddr); PrevInstr.Analyze(); if (DebugAddress) msg("Finished PrevInstr.Analyze()\n"); if (PrevInstr.MDIsReturnInstr()) { // Right after a return come no-ops and 2-byte no-ops // that are just for alignment. IDA does not seem to be // happy when we convert all those to code. if (DebugAddress) msg(" Data followed a return instruction.\n"); return true; } // Now, see if the area from DisasmAddr to NextIDAAddr is all data // according to IDA. while (DisasmAddr < NextIDAAddr) { flags_t DataFlags = getFlags(DisasmAddr); if (isTail(DataFlags)) { if (DebugAddress) msg(" tail byte: %x\n", DisasmAddr); DisasmAddr = get_item_end(DisasmAddr); } else if (isData(DataFlags)) { if (DebugAddress) msg(" data byte: %x\n", DisasmAddr); DisasmAddr = get_item_end(DisasmAddr); } else if (isCode(DataFlags)) { // How could this ever happen? if (DebugAddress) msg(" isCode: %x\n", DisasmAddr); return true; } else { // must be isUnknown() // Very conservative here; only want to convert when the whole // region is data, because that is a symptom of IDA missing // a piece of code within a function (usually a piece of code // that is only reachable via an indirect jump). if (DebugAddress) msg(" Not isData: %x\n", DisasmAddr); return true; } if (DebugAddress) msg(" new DisasmAddr: %x\n", DisasmAddr); } // end while (DisasmAddr < NextIDAAddr) if (DebugAddress) msg(" loop exit CannotConvert: %d\n", CannotConvert); if (!CannotConvert) { // Success. DisasmAddr = DisasmLocs[ShadowDisasmIndex]; AreaSize = NextIDAAddr - DisasmAddr; if (DebugAddress) { msg(" Success! AreaSize: %x Old index: %d new index: %d\n", AreaSize, ShadowDisasmIndex, DisasmIndex); msg(" exiting FindDataToConvert()\n"); msg("\n"); } } // end if (!CannotConvert) return CannotConvert; } // end of FindDataToConvert() // Does a converted code region look like a function prologue? If so, // we should not include it in the previous function. bool IsFunctionPrologue(ea_t StartAddr, ea_t EndAddr) { return false; // **!!** TODO } // end of IsFunctionPrologue() // Patch program bytes that could not be converted from // data to code, if it can be determined that the bytes represent code // that IDA has a hard time with. // Currently limited to finding "call near ptr 0" instructions, which // often are found in optimized glibc code because gcc was able to // determine that a function pointer was zero and did constant propagation, // but unfortunately was not able to determine that the code was unreachable. // IDA will not succeed in ua_code() for "call 0", but there is no danger // of a working program ever executing this code. Replacing the call with // no-ops permits us to continue converting a contiguous range of data to // code, and permits IDA to reanalyze the function later. // Returns true if program bytes were patched. bool MDPatchUnconvertedBytes(ea_t CurrDisasmAddr) { flags_t AddrFlags = getFlags(CurrDisasmAddr); if (isData(AddrFlags) || isTail(AddrFlags)) { // Bytes should have been converted to unknown already. msg("Cannot patch data bytes or tail bytes at %x\n", CurrDisasmAddr); return false; } SMPInstr PatchInstr(CurrDisasmAddr); PatchInstr.Analyze(); int InstrLen = PatchInstr.GetCmd().size; if (0 >= InstrLen) { msg("ua_ana0() failed on patch location %x\n", CurrDisasmAddr); return false; } else { if (PatchInstr.GetCmd().itype != NN_call) { msg("Cannot patch non-call instruction at %x\n", CurrDisasmAddr); return false; } PatchInstr.PrintOperands(); op_t CallDest = PatchInstr.GetUse(0); if ((o_near != CallDest.type) || (0 != CallDest.addr)) { msg("Cannot patch call unless it is call near ptr 0 at %x", CurrDisasmAddr); return false; } ea_t PatchAddr = CurrDisasmAddr; for (int i = 0; i < InstrLen; ++i) { bool ok = patch_byte(PatchAddr, 0x90); // x86 no-op if (!ok) { msg("patch_byte() failed at %x\n", PatchAddr); return false; } ++PatchAddr; } msg("Patched %d bytes successfully at %x\n", InstrLen, CurrDisasmAddr); InstrLen = ua_code(CurrDisasmAddr); if (0 >= InstrLen) { msg(" ... but ua_code() still failed!\n"); return false; } } // end if (0 >= InstrLen) ... else ... return true; } // end of MDPatchUnconvertedBytes() // Create lists of code addresses identified by IDA Pro (in IDAProLocs) // and an external disassembler (in DisasmLocs). Compare the lists and // try to convert addresses to code that are found in DisasmLocs but // not in IDAProLocs. Emit warnings when IDAProLocs has a code address // not found in DisasmLocs. void FixCodeIdentification(void) { size_t DisasmIndex = 0; ea_t CurrDisasmAddr = DisasmLocs[DisasmIndex++]; size_t IDAProIndex = 0; ea_t CurrAddr = IDAProLocs[IDAProIndex++]; while (DisasmIndex <= DisasmLocs.size()) { // If the current address is less than the current // external disasm address, we have the rare case in // which IDA Pro has identified an address as code // but the external disasm has not. Emit a warning // message and go on to the next IDA address. if (CurrAddr < CurrDisasmAddr) { SMPInstr TempInstr(CurrAddr); TempInstr.Analyze(); msg("Address %x is code in IDB but not in external disassembler: %s\n", CurrAddr, TempInstr.GetDisasm()); if (IDAProIndex < IDAProLocs.size()) CurrAddr = IDAProLocs[IDAProIndex++]; else { // Last IDA addr; might still process Disasm addrs // after loop exit. break; } } else if (CurrAddr == CurrDisasmAddr) { // If equal, no problem, we are moving through the // code addresses in lockstep. Grab the next address // from each source. if (DisasmIndex < DisasmLocs.size()) { CurrDisasmAddr = DisasmLocs[DisasmIndex++]; } else { ++DisasmIndex; // cause loop exit; skip cleanup loop } if (IDAProIndex < IDAProLocs.size()) CurrAddr = IDAProLocs[IDAProIndex++]; else { // Last IDA addr; might still process Disasm addrs // after loop exit in cleanup loop. break; } } else { // We must have CurrAddr > CurrDisasmAddr. That means // IDA has jumped over some code addresses in // DisasmLocs. We need to try to convert addresses // to code until we can reach the current addr. int InstrLen; // For now, we will address only the case in which IDA // has identified addresses as data bytes, and the // external disassembler(e.g. objdump) has identified // the same addresses as code. We only want to deal with // contiguous areas of data-to-code conversion that do NOT // follow a return statement. int AreaSize = 0; ea_t AreaStart = CurrDisasmAddr; ea_t AreaEnd; #if SMP_DEBUG_FIXUP_IDB msg("CurrDisasmAddr: %x CurrAddr: %x\n", CurrDisasmAddr, CurrAddr); #endif bool SkipArea = FindDataToConvert(IDAProIndex, DisasmIndex, AreaSize); bool DebugAddress = (CurrDisasmAddr == 0x806c19a); if (SkipArea) { // Skip over the extra external disasm addresses. while (CurrDisasmAddr < CurrAddr) CurrDisasmAddr = DisasmLocs[DisasmIndex++]; } else { // Convert the overlooked code region to unexplored. AreaEnd = CurrDisasmAddr + AreaSize; #if SMP_DEBUG_FIXUP_IDB msg("Found data to convert: %x to %x\n", AreaStart, AreaEnd); #endif do_unknown_range(AreaStart, AreaSize, DOUNK_SIMPLE); bool AllConverted = true; do { flags_t InstrFlags = getFlags(CurrDisasmAddr); if (!isUnknown(InstrFlags)) { msg("Sync problem in FixCodeID: %x\n", CurrDisasmAddr); } else { InstrLen = ua_code(CurrDisasmAddr); if (InstrLen > 0) { // Successfully converted to code SMPInstr NewInstr(CurrDisasmAddr); NewInstr.Analyze(); #if SMP_DEBUG_FIXUP_IDB #if 0 msg("FixCodeID success at %x: len: %d %s\n", CurrDisasmAddr, InstrLen, NewInstr.GetDisasm()); #endif #endif } else { if (MDPatchUnconvertedBytes(CurrDisasmAddr)) { msg(" Patched bytes at %x\n", CurrDisasmAddr); } else { AllConverted = false; msg("FixCodeID failure at %x\n", CurrDisasmAddr); } } } // end if (isCode(InstrFlags) ... else ... if (DisasmIndex < DisasmLocs.size()) { CurrDisasmAddr = DisasmLocs[DisasmIndex++]; } else { // cause loops to exit CurrDisasmAddr = CurrAddr; ++DisasmIndex; // skip cleanup loop } } while (CurrDisasmAddr < CurrAddr); if (AllConverted) { if (IsFunctionPrologue(AreaStart, AreaEnd)) { // Create a new function entry chunk here. // **!!** TODO ; } else { // Extend the previous chunk to include the // converted code. ea_t PrevIDAAddr = IDAProLocs[IDAProIndex - 2]; func_t *PrevChunk = get_fchunk(PrevIDAAddr); #if SMP_DEBUG_FIXUP_IDB msg(" addr in chunk to extend: %x\n", PrevIDAAddr); msg(" func_t pointer for chunk: %x\n", PrevChunk); #endif #if 0 // temporary for debugging if (is_func_entry(PrevChunk)) { // Extend the func entry to contain the new code. if (func_setend(PrevIDAAddr, AreaEnd)) { msg("Func extended to include code from %x to %x\n", AreaStart, AreaEnd); ReanalyzeList.push_back(PrevIDAAddr); } else { msg("Failed to extend func from %x to %x\n", AreaStart, AreaEnd); } } else { // tail // See if this works for function tails, also. // Extend the func entry to contain the new code. if (func_setend(PrevIDAAddr, AreaEnd)) { msg("Tail extended to include code from %x to %x\n", AreaStart, AreaEnd); func_t *TailOwner = get_func(PrevChunk->owner); ReanalyzeList.push_back(PrevIDAAddr); } else { msg("Failed to extend tail from %x to %x\n", AreaStart, AreaEnd); } } // end if (is_func_entry()) ... else ... #endif } // end if (IsFunctionPrologue()) ... else ... } // end if (AllConverted) else { msg("not AllConverted; cannot include new code in previous chunk.\n"); } } // end if (SkipArea) ... else ... } // end if (addr < CurrDisasmAddr) .. else if ... else ... } // end while (DisasmIndex <= DisasmLocs.size() #if 0 // Make this code use FindDataToConvert() **!!** // Cleanup loop: // If there are still Disasm addrs to process, try to turn them // into code in the IDB. while (DisasmIndex <= DisasmLocs.size()) { flags_t InstrFlags = getFlags(CurrDisasmAddr); if (isCode(InstrFlags)) { msg("Sync problem in FixCodeID: %x\n", CurrDisasmAddr); } else { // Clear bytes to unexplored. segment_t *seg = getseg(CurrDisasmAddr); if (SEG_CODE == seg->type) { do_unknown_range(CurrDisasmAddr, seg->endEA - CurrDisasmAddr, DOUNK_SIMPLE); } else { // Might be safest to just discontinue processing // if we wander into a non-code segment. // DisasmLocs should not have an entire code segment // that IDA Pro missed. break; } int InstrLen = ua_code(CurrDisasmAddr); if (InstrLen > 0) { // Successfully converted to code SMPInstr NewInstr(CurrDisasmAddr); NewInstr.Analyze(); msg("FixCodeID success at %x: %s\n", CurrDisasmAddr, NewInstr.GetDisasm()); } else { msg("FixCodeID failure at %x\n", CurrDisasmAddr); } } // end if (isCode(InstrFlags) ... else ... if (DisasmIndex < DisasmLocs.size()) { CurrDisasmAddr = DisasmLocs[DisasmIndex++]; } else { ++DisasmIndex; // cause loop to exit } } // end while (DisasmIndex <= DisasmLocs.size() #endif return; } // end of FixCodeIdentification() // Audit the IDA code database by looking at all instructions in the // code segment and printing all those that are not contained in a // function. Emit the context-free annotations that we are able to // emit ona per-instruction basis. void FindOrphanedCode(segment_t *CurrSeg, FILE *AnnotFile) { char disasm[MAXSTR]; for (ea_t addr = CurrSeg->startEA; addr < CurrSeg->endEA; addr = get_item_end(addr)) { flags_t InstrFlags = getFlags(addr); if (isTail(InstrFlags)) continue; if (isHead(InstrFlags) && isCode(InstrFlags)) { func_t *CurrFunc = get_func(addr); if (NULL == CurrFunc) { SMPInstr CurrInst(addr); CurrInst.Analyze(); msg("Orphan code at %x : %s\n", addr, CurrInst.GetDisasm()); // TODO: If there are code xrefs to the orphan code, // see what kind. If a CALL, and orphan code looks // like a prologue, make a function. If a JUMP of // some kind, then make a function chunk and make // it a tail of all functions that jump to it. **!!** // If instruction is still not included in a code chunk, // emit annotations for it in isolation. CurrInst.EmitAnnotations(true, false, AnnotFile); } } else if (isUnknown(InstrFlags)) { msg("Unanalyzed byte at %x\n", addr); // Can IDA analyze this to be code? int InstrLen = ua_code(addr); if (InstrLen > 0) { (void) generate_disasm_line(addr, disasm, sizeof(disasm) - 1); // Remove interactive color-coding tags. tag_remove(disasm, disasm, 0); msg("Successfully analyzed! %s\n", disasm); SMPInstr UnknownInstr(addr); UnknownInstr.Analyze(); // TODO: Get new code into a chunk. **!!** // If instruction is still not included in a code chunk, // emit annotations for it in isolation. UnknownInstr.EmitAnnotations(true, false, AnnotFile); } } } // end for (ea_t addr = CurrSeg->startEA; ...) } // end of FindOrphanedCode() // Audit the IDA database with respect to branches and calls. They should // each have valid code targets (not data or unknown bytes) and the code // cross references should reflect the linkage. void AuditCodeTargets(void) { // Cover all the code that IDA has grouped into functions by iterating // through all function chunks in the program. for (size_t ChunkIndex = 0; ChunkIndex < get_fchunk_qty(); ++ChunkIndex) { func_t *ChunkInfo = getn_fchunk((int) ChunkIndex); char FuncName[MAXSTR]; get_func_name(ChunkInfo->startEA, FuncName, sizeof(FuncName) - 1); // First, see if any calls to this function (if this chunk is // an entry point) are not coming from within functions. if (is_func_entry(ChunkInfo)) { xrefblk_t xb; ea_t addr = ChunkInfo->startEA; for (bool ok = xb.first_to(addr, XREF_ALL); ok; ok = xb.next_to()) { uchar XrefType = xb.type & XREF_MASK; if (xb.iscode) { if ((XrefType == fl_U) || (XrefType == fl_USobsolete)) { msg("Bad xref type: %x %s\n", addr, FuncName); } #if SMP_DEBUG_FIXUP_IDB else if ((XrefType == fl_JF) || (XrefType == fl_JN)) { msg("Jump to func: %x %s from: %x\n", addr, FuncName, xb.from); } #endif else if (XrefType == fl_F) { msg("Fall through to func: %x %s from: %x\n", addr, FuncName, xb.from); } else if ((XrefType == fl_CF) || (XrefType == fl_CN)) { // Far call or Near call func_t *CallingFunc = get_func(xb.from); if (NULL == CallingFunc) { msg("Call to %x Func %s from %x not in function.\n", addr, FuncName, xb.from); } } } // end if (xb.iscode) else { // DATA xref if (XrefType == dr_O) { msg("Data xref to %x Func %s from %x\n", addr, FuncName, xb.from); } else { msg("Strange data xref %d to %x Func %s from %x\n", XrefType, addr, FuncName, xb.from); } } } // end for (bool ok = xb.first_to(); ...) } // end if (is_func_entry(ChunkInfo)) // Next, see if any call or branch in this chunk references // a target address that is not in a function. If so, and the // callee address code looks like a function prologue, then // create a function for the contiguous code starting at that // address and ask IDA to analyze it and store it in the // IDA database. If it is a branch target, not a call target, // create a new TAIL chunk for the current parent functions. for (ea_t addr = ChunkInfo->startEA; addr < ChunkInfo->endEA; addr = get_item_end(addr)) { flags_t InstrFlags = getFlags(addr); if (isCode(InstrFlags) && isHead(InstrFlags)) { SMPInstr CurrInst(addr); CurrInst.Analyze(); if ((CALL|JUMP|COND_BRANCH) & CurrInst.GetDataFlowType()) { xrefblk_t xb; for (bool ok = xb.first_from(addr, XREF_FAR); ok; ok = xb.next_from()) { if (xb.iscode) { func_t *FuncInfo = get_func(xb.to); if (NULL == FuncInfo) { // Found call to addr that is not in a func. ea_t FirstAddr = xb.to; // Find limits of contiguous code starting at FirstAddr. ea_t LastAddr = FindNewFuncLimit(xb.to); if (CALL == CurrInst.GetDataFlowType()) msg("Found new func from %x to %x\n", FirstAddr, LastAddr); else msg("Found new chunk from %x to %x\n", FirstAddr, LastAddr); } } } } } } } // end for (size_t ChunkIndex = 0; ... ) return; } // end of AuditCodeTargets() // Find the span of contiguous code that is not contained within any // function, starting at StartAddr, which should already be an example // of an instruction address that is outside of a function. ea_t FindNewFuncLimit(ea_t StartAddr) { ea_t LimitAddr = StartAddr; segment_t *seg = getseg(StartAddr); if (NULL == seg) return LimitAddr; ea_t SegLimit = seg->endEA; for (ea_t addr = get_item_end(StartAddr); addr < SegLimit; addr = get_item_end(addr)) { flags_t InstrFlags = getFlags(addr); if (isCode(InstrFlags) && isHead(InstrFlags)) { LimitAddr = addr; func_t *FuncInfo = get_func(addr); if (NULL != FuncInfo) break; // ran into an existing function } else // Not a code head; time to stop. break; } return LimitAddr; } // end of FindNewFuncLimit() void SpecialDebugOutput(void) { char disasm[MAXSTR]; vector<ea_t> ProblemAddrs; ProblemAddrs.push_back(0x8066d08); for (size_t index = 0; index < ProblemAddrs.size(); ++index) { ea_t addr = ProblemAddrs[index]; flags_t InstrFlags = getFlags(addr); if (isCode(InstrFlags) && isHead(InstrFlags)) { ua_ana0(addr); generate_disasm_line(addr, disasm, sizeof(disasm) - 1); tag_remove(disasm, disasm, 0); msg("Problem addr %x : %s\n", addr, disasm); } } return; } // end of SpecialDebugOutput() // 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()