/* SMPInstr.cpp - <see below>. * * Copyright (c) 2000, 2001, 2010 - University of Virginia * * This file is part of the Memory Error Detection System (MEDS) infrastructure. * This file may be used and modified for non-commercial purposes as long as * all copyright, permission, and nonwarranty notices are preserved. * Redistribution is prohibited without prior written consent from the University * of Virginia. * * Please contact the authors for restrictions applying to commercial use. * * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Author: University of Virginia * e-mail: jwd@virginia.com * URL : http://www.cs.virginia.edu/ * * Additional copyrights 2010, 2011, 2012, 2013, 2014, 2015 by Zephyr Software LLC * e-mail: {clc,jwd}@zephyr-software.com * URL : http://www.zephyr-software.com/ * */ // // SMPInstr.cpp // // This module performs the instruction level analyses needed for the // SMP project (Software Memory Protection). // using namespace std; #include <memory> #include <string> #include <iostream> #include <sstream> #include <iomanip> #include <cstring> #include <cstddef> #include <cassert> #include "interfaces/STARSTypes.h" #include "interfaces/SMPDBInterface.h" #include "base/SMPDataFlowAnalysis.h" #include "base/SMPInstr.h" #include "base/SMPProgram.h" #include "base/ProfilerInformation.h" #include "interfaces/abstract/STARSInstruction.h" #include "interfaces/abstract/STARSOp.h" // Set to 1 for debugging output #define SMP_DEBUG 1 #define SMP_DEBUG2 0 // verbose #define SMP_DEBUG_XOR 0 #define SMP_DEBUG_BUILD_RTL 1 // should be left on, serious errors! #define SMP_VERBOSE_DEBUG_BUILD_RTL 0 #define SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE 0 #define SMP_VERBOSE_DEBUG_INFER_TYPES 0 #define SMP_VERBOSE_DUMP 0 #define SMP_VERBOSE_FIND_POINTERS 0 #define STARS_DUMP_FG_INFO 1 // show signedness of DEFs and USEs in dump #define STARS_DEBUG_STATIC_MEM_OPS 0 #define SMP_BASEREG_POINTER_TYPE 1 // Initialize Base Register USEs to type POINTER? #define SMP_OPTIMIZE_ADD_TO_NUMERIC 0 // optimizing annotation type -5 #define SMP_IDENTIFY_POINTER_ADDRESS_REG 0 // optimizing annotation POINTER #define SMP_CHILDACCESS_ALL_CODE 0 // CHILDACCESS annotations for all funcs, or just analyzed funcs? #define SPECIAL_CASE_CARRY_BORROW 0 // Treat sbb/adc different from sub/add annotations? #define SMP_BUILD_SPECIAL_ADC_SBB_RTL 0 // Explicit RTL subtree for carry flag? #define SMP_AGGRESSIVE_TYPE_INFERENCE 1 // Shorten iterations by quick propagation in InferOperatorType() #define SMP_ANNOTATE_ALL_MEMORY_OPERANDS 0 // Info annotation for all memory read and write operands? #define SMP_AGGRESSIVE_SIGN_TRANSFER 1 // More transfer of signedness across instructions #define STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR 1 // unsigned left shift for scale factors is really unknownsign multiply #define STARS_USE_NUMERIC_ERROR_BLACKLISTING 1 // Only instrument for numeric errors if DEF leads to a blacklisted (important) sink #define STARS_CONSERVATIVE_DEADREGS 1 // debug DEADREGS annotations by being ultra-conservative at call sites #define STARS_EXPR_CALL_DEPTH_LIMIT 50 // Limit on number of invocations of ExpandExpr(), ExpandOperand(), and ExpandOperandHelper() // Text to be printed in each optimizing annotation explaining why // the annotation was emitted. #define LAST_TYPE_CATEGORY 15 static const char *OptExplanation[LAST_TYPE_CATEGORY + 1] = { "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM", "Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr", "AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest", "NumericSources", "StackMemoryTracking", "NumericSources", "NumericMemDest", "NeverMemDest", "SafeIfNoIndexing" }; const char *OperatorText[LAST_SMP_OPERATOR + 1] = { "SMP_NULL_OPERATOR", "SMP_CALL", "SMP_INPUT", "SMP_OUTPUT", "SMP_ADDRESS_OF", "SMP_U_LEFT_SHIFT", "SMP_S_LEFT_SHIFT", "SMP_U_RIGHT_SHIFT", "SMP_S_RIGHT_SHIFT", "SMP_ROTATE_LEFT", "SMP_ROTATE_LEFT_CARRY", "SMP_ROTATE_RIGHT", "SMP_ROTATE_RIGHT_CARRY", "SMP_DECREMENT", "SMP_INCREMENT", "SMP_ADD", "SMP_ADD_CARRY", "SMP_SUBTRACT", "SMP_SUBTRACT_BORROW", "SMP_U_MULTIPLY", "SMP_S_MULTIPLY", "SMP_U_DIVIDE", "SMP_S_DIVIDE", "SMP_U_REMAINDER", "SMP_SIGN_EXTEND", "SMP_ZERO_EXTEND", "SMP_ASSIGN", "SMP_BITWISE_AND", "SMP_BITWISE_OR", "SMP_BITWISE_NOT", "SMP_BITWISE_XOR", "SMP_BITWISE_AND_NOT", "SMP_NEGATE", "SMP_S_COMPARE", "SMP_U_COMPARE", "SMP_GENERAL_COMPARE", "SMP_LESS_THAN", "SMP_GREATER_THAN", "SMP_LESS_EQUAL", "SMP_GREATER_EQUAL", "SMP_EQUAL", "SMP_NOT_EQUAL", "SMP_BELOW", "SMP_BELOW_EQUAL", "SMP_ABOVE", "SMP_ABOVE_EQUAL", "SMP_CARRY", "SMP_NOT_CARRY", "SMP_PARITY", "SMP_NOT_PARITY", "SMP_OVERFLOW", "SMP_NOT_OVERFLOW", "SMP_SIGN_BIT_SET", "SMP_NOT_SIGN_BIT_SET", "SMP_LOGICAL_AND", "SMP_LOGICAL_OR", "SMP_UNARY_NUMERIC_OPERATION", "SMP_BINARY_NUMERIC_OPERATION", "SMP_SYSTEM_OPERATION", "SMP_UNARY_FLOATING_ARITHMETIC", "SMP_BINARY_FLOATING_ARITHMETIC", "SMP_FLOATING_ADD", "SMP_FLOATING_SUBTRACT", "SMP_FLOATING_MULTIPLY", "SMP_FLOATING_DIVIDE", "SMP_FLOATING_NEGATE_AND_ADD", "SMP_REVERSE_SHIFT_U", "SMP_SHUFFLE", "SMP_COMPARE_EQ_AND_SET", "SMP_COMPARE_NE_AND_SET", "SMP_COMPARE_GT_AND_SET", "SMP_COMPARE_GE_AND_SET", "SMP_COMPARE_LT_AND_SET", "SMP_COMPARE_LE_AND_SET", "SMP_PACK_SIGNED", "SMP_PACK_UNSIGNED", "SMP_AVERAGE_UNSIGNED", "SMP_MULTIPLY_AND_ADD", "SMP_SUM_OF_DIFFS", "SMP_MAX_S", "SMP_MAX_U", "SMP_MIN_S", "SMP_MIN_U", "SMP_ABS_VALUE", "SMP_CONVERT_INT_TO_FP", "SMP_CONVERT_FP_TO_INT", "SMP_CREATE_MASK", "SMP_INTERLEAVE", "SMP_CONCATENATE", "SMP_EXTRACT_ZERO_EXTEND", "SMP_ENCRYPTION_OPERATION", "SMP_UNARY_POINTER_OPERATION", "X86.ReadMem64", "SMP_SIGNAL" }; // Take RelationalOperator from a comparison instruction, as determined by its matching jump, // and convert it to the operator needed if the comparison operands are swapped. // E.g.: cmp rax,rbx followed by ja label1 produces SMP_GREATER_THAN operator. // If we did cmp rbx,rax then the operator would logically be SMP_LESS_THAN. // Used in STARSExpression tree flips. SMPoperator InvertRelationalOperator(SMPoperator RelationalOperator) { switch (RelationalOperator) { case SMP_LESS_THAN: RelationalOperator = SMP_GREATER_THAN; break; case SMP_GREATER_THAN: RelationalOperator = SMP_LESS_THAN; break; case SMP_LESS_EQUAL: RelationalOperator = SMP_GREATER_EQUAL; break; case SMP_GREATER_EQUAL: RelationalOperator = SMP_LESS_EQUAL; break; case SMP_EQUAL: RelationalOperator = SMP_EQUAL; break; case SMP_NOT_EQUAL: RelationalOperator = SMP_NOT_EQUAL; break; case SMP_BELOW: // unsigned comparison operators BELOW, BELOW_EQUAL, ABOVE, ABOVE_EQUAL RelationalOperator = SMP_ABOVE; break; case SMP_BELOW_EQUAL: RelationalOperator = SMP_ABOVE_EQUAL; break; case SMP_ABOVE: RelationalOperator = SMP_BELOW; break; case SMP_ABOVE_EQUAL: RelationalOperator = SMP_BELOW_EQUAL; break; case SMP_CARRY: // should only be used in Guard RTLs RelationalOperator = SMP_NOT_CARRY; break; case SMP_NOT_CARRY: // should only be used in Guard RTLs RelationalOperator = SMP_CARRY; break; case SMP_PARITY: // should only be used in Guard RTLs RelationalOperator = SMP_NOT_PARITY; break; case SMP_NOT_PARITY: // should only be used in Guard RTLs RelationalOperator = SMP_PARITY; break; case SMP_OVERFLOW: // should only be used in Guard RTLs RelationalOperator = SMP_NOT_OVERFLOW; break; case SMP_NOT_OVERFLOW: // should only be used in Guard RTLs RelationalOperator = SMP_OVERFLOW; break; case SMP_SIGN_BIT_SET: // should only be used in Guard RTLs RelationalOperator = SMP_NOT_SIGN_BIT_SET; break; case SMP_NOT_SIGN_BIT_SET: // should only be used in Guard RTLs RelationalOperator = SMP_SIGN_BIT_SET; break; default: SMP_msg("ERROR: Non-relational operator %d in call to InvertRelationalOperator()\n", RelationalOperator); break; } return RelationalOperator; } // end of InvertRelationalOperator() // Is the given memory range just a local frame write? bool IsLocalStackFrameExprPair(const STARSExpression *LowerExpr, const STARSExpression *UpperExpr) { bool StackFrameAccess = false; if ((nullptr != LowerExpr) && (nullptr != UpperExpr)) { STARS_sval_t CurrentStackOffset = LowerExpr->GetOriginalParentInst()->GetStackPtrOffset(); STARS_sval_t FinalStackOffset; if (UpperExpr->IsStackPtrOffset(CurrentStackOffset, FinalStackOffset)) { StackFrameAccess = (0 > FinalStackOffset); } } return StackFrameAccess; } // end of IsLocalStackFrameExprPair() #if 0 // Does the CurrOperator definitely indicate a signed or unsigned operation? bool OperatorHasSignedness(SMPoperator CurrOperator) { bool DetectedSignedness; switch (CurrOperator) { case SMP_NULL_OPERATOR: DetectedSignedness = false; break; case SMP_CALL: // CALL instruction DetectedSignedness = true; break; case SMP_INPUT: // input from port case SMP_OUTPUT: // output to port case SMP_ADDRESS_OF: // take effective address case SMP_GENERAL_COMPARE: DetectedSignedness = false; break; case SMP_U_LEFT_SHIFT: // unsigned left shift case SMP_U_RIGHT_SHIFT: // unsigned right shift case SMP_ROTATE_LEFT: case SMP_ROTATE_LEFT_CARRY: // rotate left through carry case SMP_ROTATE_RIGHT: case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry case SMP_U_MULTIPLY: case SMP_U_DIVIDE: case SMP_U_REMAINDER: case SMP_ZERO_EXTEND: case SMP_BITWISE_NOT: // unary operator case SMP_BITWISE_XOR: case SMP_BITWISE_AND_NOT: case SMP_U_COMPARE: // unsigned compare (AND-based) case SMP_UNARY_POINTER_OPERATION: DetectedSignedness = true; break; case SMP_S_LEFT_SHIFT: // signed left shift case SMP_S_RIGHT_SHIFT: // signed right shift case SMP_S_MULTIPLY: case SMP_S_DIVIDE: case SMP_SIGN_EXTEND: case SMP_NEGATE: // unary negation case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_LESS_THAN: // boolean test operators case SMP_GREATER_THAN: case SMP_LESS_EQUAL: case SMP_GREATER_EQUAL: case SMP_BELOW: case SMP_BELOW_EQUAL: case SMP_ABOVE: case SMP_ABOVE_EQUAL: DetectedSignedness = true; break; case SMP_DECREMENT: case SMP_INCREMENT: case SMP_ADD: case SMP_ADD_CARRY: // add with carry case SMP_SUBTRACT: case SMP_SUBTRACT_BORROW: // subtract with borrow case SMP_ASSIGN: case SMP_BITWISE_AND: case SMP_BITWISE_OR: case SMP_EQUAL: case SMP_NOT_EQUAL: case SMP_LOGICAL_AND: case SMP_LOGICAL_OR: case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask case SMP_SIGNAL: // signal or raise exception DetectedSignedness = false; break; case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_FLOATING_ADD: case SMP_FLOATING_SUBTRACT: case SMP_FLOATING_MULTIPLY: // floating-point multiplication of any precision; all NUMERIC case SMP_FLOATING_DIVIDE: // floating-point division of any precision; all NUMERIC case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC DetectedSignedness = true; break; case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's case SMP_COMPARE_NE_AND_SET: // Compare for inequality and set fields to all 1's or all 0's case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision case SMP_AVERAGE_U: // Average of unsigned operands case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate) case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements case SMP_MAX_S: // dest := signed_max(dest, src) case SMP_MAX_U: // dest := unsigned_max(dest, src) case SMP_MIN_S: // dest := signed_min(dest, src) case SMP_MIN_U: // dest := unsigned_min(dest, src) case SMP_ABSOLUTE_VALUE: // take absolute value case SMP_CONVERT_INT_TO_FP: // convert integer to floating point case SMP_CONVERT_FP_TO_INT: // convert floating point to integer case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC DetectedSignedness = true; break; default: DetectedSignedness = false; SMP_msg("ERROR: Unknown operator in OperatorHasSignedness: %d\n", CurrOperator); break; } // end switch on operator return DetectedSignedness; } // end of OperatorHasSignedness() #endif // Print the SPARK Ada procedure suffix for the operand, e.g. reg32 or mem16 or const32 void PrintOperandSPARKAdaSuffix(const STARSOpndTypePtr &Opnd, FILE *OutFile) { bool ErrorFlag = false; if (Opnd->IsRegOp()) { SMP_fprintf(OutFile, "_reg"); } else if (IsMemOperand(Opnd)) { SMP_fprintf(OutFile, "_mem"); } else if (Opnd->IsImmedOp()) { SMP_fprintf(OutFile, "_const"); } else { ErrorFlag = true; SMP_fprintf(OutFile, "_ERROR"); } // Append the bit width. if (!ErrorFlag) { std::size_t ByteWidth = Opnd->GetByteWidth(); std::size_t BitWidth = ByteWidth * 8; char WidthStr[12]; SMP_snprintf(WidthStr, 5, "%z", BitWidth); SMP_fprintf(OutFile, "%s", WidthStr); } return; } // end of PrintOperandSPARKAdaSuffix() // Construct SPARK memory write procedure call, including open parenthesis for arg list. void GetSPARKMemWriteProcString(std::size_t OpndByteWidth, char *MemWriteString) { if (OpndByteWidth == 8) { SMP_snprintf(MemWriteString, 30, "X86.WriteMem64(("); } else if (OpndByteWidth == 4) { SMP_snprintf(MemWriteString, 30, "X86.WriteMem32(Unsigned64("); } else if (OpndByteWidth == 2) { SMP_snprintf(MemWriteString, 30, "X86.WriteMem16(Unsigned64("); } else if (OpndByteWidth == 1) { SMP_snprintf(MemWriteString, 30, "X86.WriteMem8(Unsigned64("); } else if (OpndByteWidth == 10) { SMP_snprintf(MemWriteString, 30, "X86.WriteMem80(Unsigned64("); } return; } // end of GetSPARKMemWriteProcString() // Construct SPARK memory read procedure call, including open parenthesis for arg list. void GetSPARKMemReadProcString(std::size_t OpndByteWidth, char *MemReadString) { if (OpndByteWidth == 8) { SMP_snprintf(MemReadString, 30, "X86.ReadMem64(("); } else if (OpndByteWidth == 4) { SMP_snprintf(MemReadString, 30, "X86.ReadMem32(Unsigned64("); } else if (OpndByteWidth == 2) { SMP_snprintf(MemReadString, 30, "X86.ReadMem16(Unsigned64("); } else if (OpndByteWidth == 1) { SMP_snprintf(MemReadString, 30, "X86.ReadMem8(Unsigned64("); } else if (OpndByteWidth == 10) { SMP_snprintf(MemReadString, 30, "X86.ReadMem80(Unsigned64("); } return; } // end of GetSPARKMemReadProcString() // Construct SPARK bitwidth cast string. e.g. Unsigned32. void GetSPARKWidthCastString(std::size_t OpndByteWidth, char *CastString) { if (OpndByteWidth == 8) { SMP_snprintf(CastString, 15, "Unsigned64"); } else if (OpndByteWidth == 4) { SMP_snprintf(CastString, 15, "Unsigned32"); } else if (OpndByteWidth == 2) { SMP_snprintf(CastString, 15, "Unsigned16"); } else if (OpndByteWidth == 1) { SMP_snprintf(CastString, 15, "Unsigned8"); } else if (OpndByteWidth == 10) { SMP_snprintf(CastString, 15, "Unsigned80"); } return; } // end of GetSPARKWidthCastString() void PrintSPARKIndentTabs(FILE *OutFile) { #define DEBUG_STARS_TABS 1 #if DEBUG_STARS_TABS if (STARS_SPARK_IndentCount > 8) { SMP_msg("ERROR: Indentation level out of range: %u\n", STARS_SPARK_IndentCount); STARS_SPARK_IndentCount = 8; } #endif for (std::size_t Counter = 0; Counter < STARS_SPARK_IndentCount; ++Counter) { SMP_fprintf(OutFile, "\t"); } return; } // Print an operand in SPARK-Ada form. void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace, bool UseSavedStackPtr) { #if 1 std::string OutString; this->SPARKAdaOperandToString(Opnd, OutString, LeftHandSide, UseFP, UseMachinePrefix, OmitTrailingSpace, UseSavedStackPtr); SMP_fprintf(OutFile, "%s", OutString.c_str()); #else std::size_t OpndByteWidth = Opnd->GetByteWidth(); bool MemOpnd = IsMemOperand(Opnd); bool SubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > OpndByteWidth); bool MemWrite = LeftHandSide && MemOpnd; bool MemRead = MemOpnd && (!LeftHandSide); char MemWriteString[40] = { '\0' }; ++SPARKOperandCount; if (MemWrite) { GetSPARKMemWriteProcString(OpndByteWidth, MemWriteString); } else if (MemRead) { GetSPARKMemReadProcString(OpndByteWidth, MemWriteString); } if (Opnd->IsStaticMemOp()) { if (Opnd->HasSIBByte()) { SMP_fprintf(OutFile, " %s ", MemWriteString); SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); SMP_fprintf(OutFile, " + 16#%llx# )", (uint64_t) Opnd->GetAddr()); } else { SMP_fprintf(OutFile, " %s 16#%llx# ", MemWriteString, (uint64_t) Opnd->GetAddr()); } if (SubwordWidth) { ++SubwordMemCount; } } else if (Opnd->IsMemNoDisplacementOp()) { if (Opnd->HasSIBByte()) { // has SIB info SMP_fprintf(OutFile, " %s ", MemWriteString); SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); } else { // no SIB info STARS_regnum_t BaseReg = Opnd->GetReg(); STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg); if (this->MDIsAddressing64bit()) { BaseOp->SetByteWidth(8); } #if STARS_SPARK_EMIT_SEGMENT_REGS if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) { // We have a segment selector that is not just a redundant SS: selector for an RSP-relative access. STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg()); SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp)); } else { #endif if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) { SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp)); } else { SMP_fprintf(OutFile, " %s SaveStackPtr ", MemWriteString); } #if STARS_SPARK_EMIT_SEGMENT_REGS } #endif if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) { ++SubwordAddressRegCount; } } if (Opnd->GetAddr() != 0) { SMP_msg(" \n WARNING: addr for o_phrase type: %llx\n", (unsigned long long) Opnd->GetAddr()); } if (SubwordWidth) { ++SubwordMemCount; } } else if (Opnd->IsMemDisplacementOp()) { STARS_ea_t offset = Opnd->GetAddr(); int SignedOffset = (int) offset; if (Opnd->HasSIBByte()) { SMP_fprintf(OutFile, " %s ", MemWriteString); SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), false); if (SignedOffset > 0) // print plus sign SMP_fprintf(OutFile, "+ 16#%x# )", (unsigned int) SignedOffset); else if (SignedOffset < 0) { SMP_fprintf(OutFile, "- 16#%x# )", (unsigned int) (0 - SignedOffset)); } } else { STARS_regnum_t BaseReg = Opnd->GetReg(); STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg); if (this->MDIsAddressing64bit()) { BaseOp->SetByteWidth(8); } #if STARS_SPARK_EMIT_SEGMENT_REGS if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) { // We have a segment selector that is not just a redundant SS: selector for an RSP-relative access. STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg()); SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp)); } else { #endif if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) { SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp)); } else { SMP_fprintf(OutFile, " %s SaveStackPtr ", MemWriteString); } #if STARS_SPARK_EMIT_SEGMENT_REGS } #endif if (SignedOffset >= 0) // print plus sign SMP_fprintf(OutFile, "+ 16#%x# ", (unsigned int) SignedOffset); else { SMP_fprintf(OutFile, "- 16#%x# ", (unsigned int) (0 - SignedOffset)); } if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) { ++SubwordAddressRegCount; } } if (SubwordWidth) { ++SubwordMemCount; } } else if (Opnd->IsRegOp()) { if (UseSavedStackPtr && Opnd->MatchesReg(MD_STACK_POINTER_REG)) { assert(!LeftHandSide); SMP_fprintf(OutFile, " SaveStackPtr"); } else if (SubwordWidth && LeftHandSide) { // Subword reg writes are procedure calls, e.g. Write_EDI(... SMP_fprintf(OutFile, " X86.Write_%s(", MDGetRegName(Opnd)); } else if (UseMachinePrefix) { SMP_fprintf(OutFile, " X86.%s", MDGetRegName(Opnd)); } else { SMP_fprintf(OutFile, " %s", MDGetRegName(Opnd)); } if (!OmitTrailingSpace) { // parameters to loop functions will get a suffix; all others need a space now SMP_fprintf(OutFile, " "); } if (SubwordWidth) { ++SubwordRegCount; } } else if (Opnd->IsFloatingPointRegOp()) { bool FPStackTop = (STARS_x86_R_st0 == Opnd->GetReg()); if (UseMachinePrefix) { if (FPStackTop) SMP_fprintf(OutFile, " X86.FloatingPointStackDummy "); else SMP_fprintf(OutFile, " X86.FloatingPointStackDummy1 "); } else { if (FPStackTop) SMP_fprintf(OutFile, " FloatingPointStackDummy "); else SMP_fprintf(OutFile, " FloatingPointStackDummy1 "); } } else if (Opnd->IsImmedOp()) { STARS_sval_t SignedImmedValue = (STARS_sval_t) Opnd->GetImmedValue(); if (0 > SignedImmedValue) { // enclose unary minus in parentheses for Ada SMP_fprintf(OutFile, " (%lld) ", (long long) SignedImmedValue); } else { SMP_fprintf(OutFile, " 16#%llx# ", (unsigned long long) SignedImmedValue); } } else if (Opnd->IsFarPointer() || Opnd->IsNearPointer()) { SMP_fprintf(OutFile, " 16#%llx# ", (unsigned long long) Opnd->GetAddr()); } else if (Opnd->IsVoidOp()) { ; // nothing to print } else { SMP_fprintf(OutFile, " ERROROP"); } if (MemWrite) { // close the procedure call address arg cast parentheses SMP_fprintf(OutFile, "), "); // e.g. MemWrite32(Unsigned64(Opnd), } else if (MemRead) { SMP_fprintf(OutFile, ")) "); // e.g. MemRead8(Unsigned64(Opnd)) } #endif return; } // end of PrintSPARKAdaOperand() void SMPInstr::SPARKAdaOperandToString(const STARSOpndTypePtr &Opnd, std::string &OutString, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace, bool UseSavedStackPtr) { std::size_t OpndByteWidth = Opnd->GetByteWidth(); bool MemOpnd = IsMemOperand(Opnd); bool SubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > OpndByteWidth); bool MemWrite = LeftHandSide && MemOpnd; bool MemRead = MemOpnd && (!LeftHandSide); char MemWriteString[40] = { '\0' }; char TempString[40] = { '\0' }; string SIBString; ++SPARKOperandCount; if (MemWrite) { GetSPARKMemWriteProcString(OpndByteWidth, MemWriteString); } else if (MemRead) { GetSPARKMemReadProcString(OpndByteWidth, MemWriteString); } if (Opnd->IsStaticMemOp()) { OutString.append(" "); OutString.append(MemWriteString); if (Opnd->HasSIBByte()) { SPARKAnnotSIBToString(Opnd, true, SIBString, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); OutString.append(" "); OutString.append(SIBString); (void) SMP_snprintf(TempString, 20, " + 16#%llx# )", (unsigned long long) Opnd->GetAddr()); } else { (void) SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) Opnd->GetAddr()); } OutString.append(" "); OutString.append(TempString); if (SubwordWidth) { ++SubwordMemCount; // OutString.append(")"); // close cast parenthesis } } else if (Opnd->IsMemNoDisplacementOp()) { OutString.append(" "); OutString.append(MemWriteString); if (Opnd->HasSIBByte()) { SPARKAnnotSIBToString(Opnd, false, SIBString, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); OutString.append(" "); OutString.append(SIBString); } else { // no SIB info STARS_regnum_t BaseReg = Opnd->GetReg(); STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg); if (this->MDIsAddressing64bit()) { BaseOp->SetByteWidth(8); } #if STARS_SPARK_EMIT_SEGMENT_REGS if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) { // We have a segment selector that is not just a redundant SS: selector for an RSP-relative access. STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg()); SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp)); } else { #endif if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) { OutString.append(" X86."); OutString.append(MDGetRegName(BaseOp)); OutString.append(" "); } else { OutString.append(" SaveStackPtr "); } #if STARS_SPARK_EMIT_SEGMENT_REGS } #endif if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) { ++SubwordAddressRegCount; } } if (Opnd->GetAddr() != 0) { SMP_msg(" \n WARNING: addr for o_phrase type: %llx\n", (unsigned long long) Opnd->GetAddr()); } if (SubwordWidth) { ++SubwordMemCount; // OutString.append(")"); // close cast parenthesis } } else if (Opnd->IsMemDisplacementOp()) { STARS_ea_t offset = Opnd->GetAddr(); int SignedOffset = (int) offset; OutString.append(" "); OutString.append(MemWriteString); if (Opnd->HasSIBByte()) { SPARKAnnotSIBToString(Opnd, true, SIBString, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), false); OutString.append(" "); OutString.append(SIBString); if (SignedOffset > 0) // print plus sign SMP_snprintf(TempString, 20, "+ 16#%x# )", (unsigned int) SignedOffset); else if (SignedOffset < 0) SMP_snprintf(TempString, 20, "- 16#%x# )", (unsigned int) (0 - SignedOffset)); OutString.append(TempString); } else { STARS_regnum_t BaseReg = Opnd->GetReg(); STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg); if (this->MDIsAddressing64bit()) { BaseOp->SetByteWidth(8); } #if STARS_SPARK_EMIT_SEGMENT_REGS if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) { // We have a segment selector that is not just a redundant SS: selector for an RSP-relative access. STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg()); SMP_fprintf(OutFile, " %s X86.%s + X86.%s ", MemWriteString, MDGetRegName(SegRegOp), MDGetRegName(BaseOp)); } else { #endif if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) { OutString.append(" X86."); OutString.append(MDGetRegName(BaseOp)); OutString.append(" "); } else { OutString.append(" SaveStackPtr "); } #if STARS_SPARK_EMIT_SEGMENT_REGS } #endif if (SignedOffset > 0) // print plus sign SMP_snprintf(TempString, 20, "+ 16#%x# ", (unsigned int) SignedOffset); else if (SignedOffset < 0) SMP_snprintf(TempString, 20, "- 16#%x# ", (unsigned int) (0 - SignedOffset)); OutString.append(TempString); if (global_STARS_program->GetSTARS_ISA_Bytewidth() > BaseOp->GetByteWidth()) { ++SubwordAddressRegCount; } } if (SubwordWidth) { ++SubwordMemCount; // OutString.append(")"); // close cast parenthesis } } else if (Opnd->IsRegOp()) { if (UseSavedStackPtr && Opnd->MatchesReg(MD_STACK_POINTER_REG)) { assert(!LeftHandSide); SMP_snprintf(TempString, 20, " SaveStackPtr"); } else if (SubwordWidth && LeftHandSide) { // Subword reg writes are procedure calls, e.g. Write_EDI(... SMP_snprintf(TempString, 20, " X86.Write_%s(", MDGetRegName(Opnd)); } else if (UseMachinePrefix) { SMP_snprintf(TempString, 20, " X86.%s", MDGetRegName(Opnd)); } else { SMP_snprintf(TempString, 20, " %s", MDGetRegName(Opnd)); } OutString.append(TempString); if (!OmitTrailingSpace) { // parameters to loop functions will get a suffix; all others need a space now OutString.append(" "); } if (SubwordWidth) { ++SubwordRegCount; } } else if (Opnd->IsFloatingPointRegOp()) { bool FPStackTop = (STARS_x86_R_st0 == Opnd->GetReg()); if (UseMachinePrefix) { if (FPStackTop) OutString.append(" X86.FloatingPointStackDummy "); else OutString.append(" X86.FloatingPointStackDummy1 "); } else { if (FPStackTop) OutString.append(" X86.FloatingPointStackDummy "); else OutString.append(" X86.FloatingPointStackDummy1 "); } } else if (Opnd->IsImmedOp()) { STARS_sval_t SignedImmedValue = (STARS_sval_t)Opnd->GetImmedValue(); if (0 > SignedImmedValue) { // enclose unary minus in parentheses for Ada SMP_snprintf(TempString, 20, " (%lld) ", (long long) SignedImmedValue); } else { SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) SignedImmedValue); } OutString.append(TempString); } else if (Opnd->IsFarPointer() || Opnd->IsNearPointer()) { SMP_snprintf(TempString, 20, " 16#%llx# ", (unsigned long long) Opnd->GetAddr()); OutString.append(TempString); } else if (Opnd->IsVoidOp()) { ; // nothing to print } else { OutString.append(" ERROROP"); } if (MemWrite) { // close the procedure call address arg cast parentheses OutString.append("), "); // e.g. MemWrite32(Unsigned64(Opnd), } else if (MemRead) { OutString.append(")) "); // e.g. MemRead8(Unsigned64(Opnd)) } return; } // end of SMPInstr::SPARKAdaOperandToString() // Print just the addressing expression for a memory operand in SPARK-Ada form. void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool UseFP, bool UseSavedStackPtr) { bool MemOpnd = IsMemOperand(Opnd); assert(MemOpnd); if (Opnd->IsStaticMemOp()) { if (Opnd->HasSIBByte()) { SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); SMP_fprintf(OutFile, " + 16#%llx# )", (uint64_t) Opnd->GetAddr()); } else { SMP_fprintf(OutFile, " 16#%llx# ", (uint64_t) Opnd->GetAddr()); } } else if (Opnd->IsMemNoDisplacementOp()) { if (Opnd->HasSIBByte()) { // has SIB info SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); } else { // no SIB info STARS_regnum_t BaseReg = Opnd->GetReg(); STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg); if (this->MDIsAddressing64bit()) { BaseOp->SetByteWidth(8); } #if STARS_SPARK_EMIT_SEGMENT_REGS if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) { // We have a segment selector that is not just a redundant SS: selector for an RSP-relative access. STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg()); SMP_fprintf(OutFile, " X86.%s + X86.%s ", MDGetRegName(SegRegOp), MDGetRegName(BaseOp)); } else { #endif if (!(UseSavedStackPtr && BaseOp->MatchesReg(MD_STACK_POINTER_REG))) { SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp)); } else { SMP_fprintf(OutFile, " SaveStackPtr "); } #if STARS_SPARK_EMIT_SEGMENT_REGS } #endif } if (Opnd->GetAddr() != 0) { SMP_msg(" \n WARNING: addr for o_phrase type: %llx\n", (uint64_t) Opnd->GetAddr()); } } else if (Opnd->IsMemDisplacementOp()) { STARS_ea_t offset = Opnd->GetAddr(); int SignedOffset = (int) offset; if (Opnd->HasSIBByte()) { SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDIsAddressing64bit(), UseSavedStackPtr); if (SignedOffset > 0) // print plus sign SMP_fprintf(OutFile, "+ 16#%x# )", (unsigned int) SignedOffset); else if (SignedOffset < 0) // minus sign will print automatically SMP_fprintf(OutFile, "%d )", SignedOffset); } else { STARS_regnum_t BaseReg = Opnd->GetReg(); STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd(BaseReg); if (this->MDIsAddressing64bit()) { BaseOp->SetByteWidth(8); } #if STARS_SPARK_EMIT_SEGMENT_REGS if (Opnd->HasSegReg() && (!((STARS_x86_R_ss == Opnd->GetSegReg()) && MDIsStackAccessOpnd(Opnd, UseFP)))) { // We have a segment selector that is not just a redundant SS: selector for an RSP-relative access. STARSOpndTypePtr SegRegOp = this->STARSInstPtr->MakeRegOpnd(Opnd->GetSegReg()); SMP_fprintf(OutFile, " X86.%s + X86.%s ", MDGetRegName(SegRegOp), MDGetRegName(BaseOp)); } else { #endif if (!(UseSavedStackPtr && BaseOp->MatchesReg(MD_STACK_POINTER_REG))) { SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp)); } else { SMP_fprintf(OutFile, " SaveStackPtr "); } #if STARS_SPARK_EMIT_SEGMENT_REGS } #endif if (SignedOffset >= 0) // print plus sign SMP_fprintf(OutFile, "+ 16#%x# ", (unsigned int) SignedOffset); else // minus sign will print automatically SMP_fprintf(OutFile, "%d ", SignedOffset); } } else { SMP_fprintf(OutFile, " ERROROP"); } return; } // end of PrintSPARKAdaAddressExpr() // Print an operator in SPARK-Ada form. void PrintSPARKAdaOperator(SMPoperator Oper, string &OutString, bool &PrefixProcCall, bool &PrefixUnary, bool ConstFollows) { PrefixProcCall = false; PrefixUnary = false; switch (Oper) { case SMP_NULL_OPERATOR: case SMP_INPUT: // input from port case SMP_OUTPUT: // output to port case SMP_ADDRESS_OF: // take effective address case SMP_S_LEFT_SHIFT: // signed left shift case SMP_ROTATE_LEFT_CARRY: // rotate left through carry case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry SMP_msg("ERROR: SPARK: Cannot translate operator: "); SMP_msg(" %s \n", OperatorText[Oper]); OutString = "ERROR"; break; case SMP_ADD_CARRY: // add with carry OutString = " X86.adc"; PrefixProcCall = true; break; case SMP_SUBTRACT_BORROW: // subtract with borrow OutString = " X86.sbb"; PrefixProcCall = true; break; case SMP_CALL: // CALL instruction break; case SMP_U_LEFT_SHIFT: // unsigned left shift case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand OutString = " Interfaces.Shift_Left"; PrefixProcCall = true; break; case SMP_U_RIGHT_SHIFT: // unsigned right shift OutString = " Interfaces.Shift_Right"; PrefixProcCall = true; break; case SMP_S_RIGHT_SHIFT: // signed right shift OutString = " Interfaces.Shift_Right_Arithmetic"; PrefixProcCall = true; break; case SMP_ROTATE_LEFT: OutString = " Interfaces.Rotate_Left"; PrefixProcCall = true; break; case SMP_ROTATE_RIGHT: OutString = " Interfaces.Rotate_Right"; PrefixProcCall = true; break; case SMP_DECREMENT: OutString = " - 1"; // we print LeftOp first, then - 1, then RightOp will be void break; case SMP_INCREMENT: OutString = " + 1"; // we print LeftOp first, then + 1, then RightOp will be void break; case SMP_ADD: case SMP_FLOATING_ADD: OutString = " + "; break; case SMP_SUBTRACT: case SMP_FLOATING_SUBTRACT: OutString = " - "; break; case SMP_U_MULTIPLY: case SMP_S_MULTIPLY: case SMP_FLOATING_MULTIPLY: // floating-point multiplication of any precision; all NUMERIC OutString = " * "; break; case SMP_U_DIVIDE: case SMP_S_DIVIDE: if (ConstFollows) { OutString = " / "; } else { OutString = " X86.SafeDivision64"; PrefixProcCall = true; } break; case SMP_FLOATING_DIVIDE: // floating-point division of any precision; all NUMERIC if (ConstFollows) { OutString = " / "; } else { OutString = " X86.SafeDivision64"; PrefixProcCall = true; } break; case SMP_U_REMAINDER: OutString = " rem "; break; case SMP_SIGN_EXTEND: OutString = ""; PrefixUnary = true; break; case SMP_ZERO_EXTEND: OutString = ""; PrefixUnary = true; break; case SMP_ASSIGN: OutString = ":= "; break; case SMP_BITWISE_AND: OutString = " and "; break; case SMP_BITWISE_OR: OutString = " or "; break; case SMP_BITWISE_NOT: // unary operator OutString = " not "; PrefixUnary = true; break; case SMP_BITWISE_XOR: OutString = " xor "; break; case SMP_BITWISE_AND_NOT: OutString = " andnot "; break; case SMP_NEGATE: // unary negation OutString = "-"; PrefixUnary = true; break; case SMP_LESS_THAN: // boolean test operators case SMP_BELOW: OutString = " < "; break; case SMP_GREATER_THAN: case SMP_ABOVE: OutString = " > "; break; case SMP_LESS_EQUAL: case SMP_BELOW_EQUAL: OutString = " <= "; break; case SMP_GREATER_EQUAL: case SMP_ABOVE_EQUAL: OutString = " >= "; break; case SMP_EQUAL: OutString = " = "; break; case SMP_NOT_EQUAL: OutString = " /= "; break; case SMP_LOGICAL_AND: #if ZST_EMIT_SPARK_ADA_SHORT_CIRCUIT_OPERATORS OutString = " and then "; // short circuit operator is accurate representation #else OutString = " and "; // faster proofs without short circuit operator #endif break; case SMP_LOGICAL_OR: #if ZST_EMIT_SPARK_ADA_SHORT_CIRCUIT_OPERATORS OutString = " or else "; // short circuit operator is accurate representation #else OutString = " or "; // faster proofs without short circuit operator #endif break; case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_U_COMPARE: // unsigned compare (AND-based) SMP_msg("WARNING: SPARK: Translating comparison operator: "); SMP_msg(" %s \n", OperatorText[Oper]); OutString = ", "; // assume this is part of Write_EFLAGS(opnd1, opnd2); break; case SMP_CONVERT_INT_TO_FP: // convert integer to floating point case SMP_CONVERT_FP_TO_INT: // convert floating point to integer SMP_msg("WARNING: SPARK: Translating conversion operator: "); SMP_msg(" %s \n", OperatorText[Oper]); OutString = " + "; // just move between int and FP regs, as they are all treated as ints in SPARK X86 package break; case SMP_SYMBOLIC_READ_MEMORY: OutString = " X86.ReadMem64"; PrefixUnary = true; break; case SMP_GENERAL_COMPARE: // comparisons of packed data, strings, signed, unsigned depending on control words case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's case SMP_COMPARE_NE_AND_SET: // Compare for not-equal and set fields to all 1's or all 0's case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision case SMP_AVERAGE_U: // Average of unsigned operands case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate) case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements case SMP_MAX_S: // dest := signed_max(dest, src) case SMP_MAX_U: // dest := unsigned_max(dest, src) case SMP_MIN_S: // dest := signed_min(dest, src) case SMP_MIN_U: // dest := unsigned_min(dest, src) case SMP_ABSOLUTE_VALUE: // take absolute value case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation case SMP_UNARY_POINTER_OPERATION: case SMP_SIGNAL: // signal or raise exception default: SMP_msg("ERROR: SPARK: Cannot translate unknown operator: "); SMP_msg(" %s \n", OperatorText[Oper]); OutString = "ERROR"; break; } return; } // end of PrintSPARKAdaOperator() // ***************************************************************** // Class SMPGuard // ***************************************************************** // Constructor SMPGuard::SMPGuard(void) { this->LeftOperand = nullptr; this->RightOperand = nullptr; this->GuardOp = SMP_NULL_OPERATOR; return; } // Debug print void SMPGuard::Dump(void) const { SMP_msg("GUARD: "); PrintOperand(this->LeftOperand); SMP_msg(" %s ", OperatorText[this->GuardOp]); PrintOperand(this->RightOperand); SMP_msg(":"); return; } // end of SMPGuard::Dump() // ***************************************************************** // Class SMPRegTransfer // ***************************************************************** // Constructors SMPRegTransfer::SMPRegTransfer(void) { this->Guard = NULL; this->LeftOperand = nullptr; this->RightOperand = nullptr; this->RTop.oper = SMP_NULL_OPERATOR; this->RTop.type = UNINIT; #if SMP_TRACK_NONSPEC_OPER_TYPE this->RTop.NonSpeculativeType = UNINIT; #endif this->RightRT = NULL; this->ParentInst = NULL; this->booleans1 = 0; return; } // Destructor SMPRegTransfer::~SMPRegTransfer() { #if 0 SMP_msg("Destroying SMPRegTransfer.\n"); #endif if (NULL != this->RightRT) delete this->RightRT; if (NULL != this->Guard) delete this->Guard; return; } // Get the left operand, and normalize it if it is a stack operand. STARSOpndTypePtr SMPRegTransfer::GetLeftOperand(void) const { STARSOpndTypePtr TempOp = this->LeftOperand; #if 0 if (this->ParentInst->AreDefsNormalized() && (0 != this->ParentInst->GetStackPtrOffset())) { #else if (this->ParentInst->AreDefsNormalized()) { #endif STARS_ea_t InstAddr = this->ParentInst->GetAddr(); TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp); } return TempOp; } // end of SMPRegTransfer::GetLeftOperand() // Get the right operand, and normalize it if it is a stack operand. STARSOpndTypePtr SMPRegTransfer::GetRightOperand(void) const { STARSOpndTypePtr TempOp = this->RightOperand; #if 0 if (this->ParentInst->AreDefsNormalized() && (0 != this->ParentInst->GetStackPtrOffset())) { #else if (this->ParentInst->AreDefsNormalized()) { #endif STARS_ea_t InstAddr = this->ParentInst->GetAddr(); TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp); } return TempOp; } // end of SMPRegTransfer::GetRightOperand() // Does RTL subtract a non-immediate value from the stack pointer? bool SMPRegTransfer::IsAllocaRTL(void) { bool AllocaFound = false; // Search for the pattern: stack_pointer := stack_pointer minus non-immediate if ((SMP_ASSIGN == this->GetOperator()) && (this->HasRightSubTree())) { STARSOpndTypePtr DefOp = this->GetLeftOperand(); if (DefOp->MatchesReg(MD_STACK_POINTER_REG)) { // We have the code pattern stack_pointer := ... SMPRegTransfer *RightRT = this->GetRightTree(); SMPoperator RightOperator = RightRT->GetOperator(); STARSOpndTypePtr RightDefOp = RightRT->GetLeftOperand(); if ((RightDefOp->MatchesReg(MD_STACK_POINTER_REG)) && (SMP_SUBTRACT == RightOperator)) { // We have the code pattern stack_pointer := stack_pointer minus ... if (RightRT->HasRightSubTree()) { AllocaFound = true; // not an immediate rightop, whatever it is } else { STARSOpndTypePtr RightUseOp = RightRT->GetRightOperand(); if (! RightUseOp->IsImmedOp()) { AllocaFound = true; } } } } } return AllocaFound; } // end of SMPRegTransfer::IsAllocaRTL() // SetOperatorType - set the type of the operator, take into account the speculative (profiler) status void SMPRegTransfer::SetOperatorType(SMPOperandType OpType, const SMPInstr* Instr) { SMPOperandType NewType = OpType; if (Instr->GetBlock()->GetFunc()->GetIsSpeculative()) { NewType = (SMPOperandType) (((int)NewType) | PROF_BASE); #if SMP_TRACK_NONSPEC_OPER_TYPE SMPOperandType OldType = RTop.type; if (!IsProfDerived(OldType)) RTop.NonSpeculativeType = OldType; #endif } RTop.type = NewType; } // end of SMPRegTransfer::SetOperatorType // Does UseOp arithmetically affect the value of the NonFlagsDef for this RTL? bool SMPRegTransfer::OperandTransfersValueToDef(const STARSOpndTypePtr &UseOp) const { bool FoundTransfer = false; STARSOpndTypePtr DefOp = this->GetLeftOperand(); SMPoperator CurrOp = this->GetOperator(); if ((SMP_ASSIGN == CurrOp) && (! DefOp->IsVoidOp()) && (! DefOp->MatchesReg(MD_FLAGS_REG))) { // We have an assignment to a non-flag DefOp. The only remaining question is whether // UseOp appears in the right hand side of the RT as something besides an address register // inside a memory operand. if (this->HasRightSubTree()) { FoundTransfer = this->GetRightTree()->OperandTransfersHelper(UseOp); } else { STARSOpndTypePtr RightOp = this->GetRightOperand(); if (IsEqOpIgnoreBitwidth(UseOp, RightOp)) { // Found UseOp. FoundTransfer = true; } } } return FoundTransfer; } // end of SMPRegTransfer::OperandTransfersValueToDef() // Does UseOp arithmetically affect the value of the NonFlagsDef for this RT? // Recursive helper for OperandTransfersValueToDef(). bool SMPRegTransfer::OperandTransfersHelper(const STARSOpndTypePtr &UseOp) const { bool FoundTransfer = false; STARSOpndTypePtr LeftOp = this->GetLeftOperand(); // Have to check left and right operands to see if they are UseOp. if (IsEqOpIgnoreBitwidth(UseOp, LeftOp)) { FoundTransfer = true; // Found UseOp. } else if (this->HasRightSubTree()) { // recurse FoundTransfer = this->GetRightTree()->OperandTransfersHelper(UseOp); } else { STARSOpndTypePtr RightOp = this->GetRightOperand(); if (IsEqOpIgnoreBitwidth(UseOp, RightOp)) { // Found UseOp. FoundTransfer = true; } } return FoundTransfer; } // end of SMPRegTransfer::OperandTransfersHelper() // Does RTL show LeftOp has smaller bitwidth than the right hand side operands? bool SMPRegTransfer::IsTruncatedWidthRTL(std::size_t &LeftBitWidth, std::size_t &RightBitWidth) const { bool TruncatedWidth = false; const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm(); std::size_t LeftOpByteWidth = (std::size_t) LeftOp->GetByteWidth(); std::size_t RightOpByteWidth = 0; const STARSOpndTypePtr RightOp = (this->HasRightSubTree()) ? this->GetRightTree()->GetConstLeftOperandNoNorm() : this->GetConstRightOperandNoNorm(); if (nullptr != RightOp) { RightOpByteWidth = RightOp->GetByteWidth(); } size_t DefaultByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); if ((LeftOpByteWidth < DefaultByteWidth) || (RightOpByteWidth > DefaultByteWidth)) { // Forget it unless LeftOp is reduced width. // Search right hand side for wider operands. LeftBitWidth = 8 * LeftOpByteWidth; RightBitWidth = 8 * RightOpByteWidth; TruncatedWidth = ((RightOpByteWidth > LeftOpByteWidth) && (RightOp->IsRegOp() || RightOp->IsMemOp() || RightOp->IsFloatingPointRegOp())); } return TruncatedWidth; } // end of SMPRegTransfer::IsTruncatedWidthRTL() // Does RTL show LeftOp has larger bitwidth than the right hand side operands? bool SMPRegTransfer::IsExpandedWidthRTL(std::size_t &LeftBitWidth, std::size_t &RightBitWidth) const { bool ExpandedWidth = false; const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm(); std::size_t LeftOpByteWidth = (std::size_t) LeftOp->GetByteWidth(); if (LeftOpByteWidth > global_STARS_program->GetSTARS_ISA_Bytewidth()) { // Forget it unless LeftOp is wide, e.g. FP stack. // Search right hand side for narrower operands. const STARSOpndTypePtr RightOp = (this->HasRightSubTree()) ? this->GetRightTree()->GetConstLeftOperandNoNorm() : this->GetConstRightOperandNoNorm(); size_t RightOpByteWidth = RightOp->GetByteWidth(); if (nullptr != RightOp) { ExpandedWidth = ((RightOpByteWidth < LeftOpByteWidth) && (RightOp->IsRegOp() || RightOp->IsMemOp() || RightOp->IsFloatingPointRegOp())); LeftBitWidth = 8 * LeftOpByteWidth; RightBitWidth = 8 * RightOpByteWidth; } } return ExpandedWidth; } // end of SMPRegTransfer::IsExpandedWidthRTL() // fix machine-specific FP reg encodings void SMPRegTransfer::MDFixFloatingPointRTL(void) { const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm(); if ((nullptr != LeftOp) && LeftOp->IsFloatingPointRegOp()) { STARS_regnum_t FPRegNum = LeftOp->GetReg(); if (FPRegNum < STARS_x86_R_st0) { // X86 encodes STARS_x86_R_st0 as register 0, STARS_x86_R_st1 as register 1, with o_fpreg flag indicating adjustment. // We want to encode using the STARS_regnum_t enumeration alone. STARSOpndTypePtr NewLeftOp = this->GetParentInst()->MakeFloatingPointRegOpnd(FPRegNum); this->SetLeftOperand(NewLeftOp); } } if (this->HasRightSubTree()) { this->GetRightTree()->MDFixFloatingPointRTL(); // recurse into right tree } else { const STARSOpndTypePtr RightOp = this->GetConstRightOperandNoNorm(); if ((nullptr != RightOp) && RightOp->IsFloatingPointRegOp()) { STARS_regnum_t FPRegNum = RightOp->GetReg(); if (FPRegNum < STARS_x86_R_st0) { // X86 encodes STARS_x86_R_st0 as register 0, STARS_x86_R_st1 as register 1, with o_fpreg flag indicating adjustment. // We want to encode using the STARS_regnum_t enumeration alone. STARSOpndTypePtr NewRightOp = this->GetParentInst()->MakeFloatingPointRegOpnd(FPRegNum); this->SetRightOperand(NewRightOp); } } } return; } // end of SMPRegTransfer::MDFixFloatingPointRTL() // If we see add esp,immediate and the immediate value is large, then // some stupid hand-coded ASM is probably counting on an overflow, and // this is actually a subtraction from the stack pointer (i.e. it is an // addition of a negative number). We have to detect the signedness error // because IDA Pro treats the immediate operands as unsigned at all times. #define STARS_ESP_ADDITION_OVERFLOW_THRESHOLD 0xf0000000 // Compute operand-dependent change in stack pointer value. STARS_sval_t SMPRegTransfer::ComputeStackPointerAlteration(bool IsLeaveInstr, STARS_sval_t IncomingDelta, STARS_sval_t FramePtrDelta) { STARS_sval_t delta = 0; // Search for the pattern: stack_pointer := ... if (SMP_ASSIGN == this->GetOperator()) { STARSOpndTypePtr DefOp = this->GetLeftOperand(); if (DefOp->MatchesReg(MD_STACK_POINTER_REG)) { // We have the code pattern stack_pointer := ... // We expect to find an overall RT structure of: // stack_pointer := stack_pointer binaryoperator constant // If the binaryoperator is addition or subtraction, then // we use the constant to determine our return value. // If the binaryoperator is a bitwise AND, then we return // a special code. Delta is unknown but can probably be treated // as zero, assuming that no stack-pointer-relative accesses to // the stack region above the current stack pointer occur later. // If we have a non-constant operand, we return an error code // to indicate that we cannot compute the delta. // If we don't have a binary operator, we return an error code, // unless we find a stack frame deallocation: esp := ebp if (!this->HasRightSubTree()) { STARSOpndTypePtr UseOp = this->GetRightOperand(); if (UseOp->MatchesReg(MD_FRAME_POINTER_REG)) { // !!!!****!!!! Should validate that frame pointer reg is used as frame pointer // Found esp := ebp (deallocation of stack frame) delta = FramePtrDelta - IncomingDelta; assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame } else { // !!!!****!!!!**** Need to look up deltas for registers that // were used to hold a copy of the stack pointer. // For now, just consider it an error. delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE; } } else { SMPRegTransfer *RightRT = this->GetRightTree(); SMPoperator RightOperator = RightRT->GetOperator(); STARSOpndTypePtr RightDefOp = RightRT->GetLeftOperand(); if (IsLeaveInstr) { // Found the RT esp := ebp + wordsize that adjusts the stack pointer // for an x86 LEAVE instruction. esp := ebp is equivalent // to esp := <esp when frame ptr was set up>, so delta becomes // <esp delta when frame ptr was set up> - IncomingDelta + wordsize. assert(SMP_ADD == RightOperator); assert(!RightRT->HasRightSubTree()); assert(RightDefOp->MatchesReg(X86_FRAME_POINTER_REG)); delta = global_STARS_program->GetSTARS_ISA_Bytewidth() + FramePtrDelta - IncomingDelta; } else if (RightRT->HasRightSubTree()) { // Not the right code pattern; unknown effect on stack pointer. delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE; } else if (!RightDefOp->MatchesReg(MD_STACK_POINTER_REG)) { // We have stack_pointer := something1 operator something2 // where something1 is not the stack_pointer. It might be // the frame pointer, e.g. SP := FP-12. We can compute this // stack delta because we know the delta when the FP was set up. STARSOpndTypePtr RightUseOp = RightRT->GetRightOperand(); if (RightDefOp->MatchesReg(MD_FRAME_POINTER_REG) && RightUseOp->IsImmedOp()) { // We have SP := FP operator immediate delta = FramePtrDelta - IncomingDelta; // partial computation: SP := BP assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame if (SMP_ADD == RightOperator) { delta += RightUseOp->GetImmedValue(); } else if (SMP_SUBTRACT == RightOperator) { delta -= RightUseOp->GetImmedValue(); } else { // Not the right code pattern; unknown effect on stack pointer. delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE; } } else { // !!!!****!!!!**** Need to look up deltas for registers that // were used to hold a copy of the stack pointer. // For now, just consider it an error. delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE; } } else { // We have stack_pointer := stack_pointer operator ... STARSOpndTypePtr RightUseOp = RightRT->GetRightOperand(); // Check the operator if (SMP_BITWISE_AND == RightOperator) { delta = (STARS_sval_t) SMP_STACK_POINTER_BITWISE_AND_CODE; } else { if (! RightUseOp->IsImmedOp()) { // Don't know how to deal with adding non-constant to stack pointer delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE; } else if (SMP_ADD == RightOperator) { delta = (STARS_sval_t) RightUseOp->GetImmedValue(); if (((STARS_uval_t) delta) > STARS_ESP_ADDITION_OVERFLOW_THRESHOLD) { // Really a subtraction via addition of a negative. // E.g. add esp, 0xfffffff0 is sub esp,16 int32_t TempDelta = (int32_t) (delta & 0xffffffff); delta = (STARS_sval_t) TempDelta; } } else if (SMP_SUBTRACT == RightOperator) { if (RightUseOp->GetImmedValue() > STARS_ESP_ADDITION_OVERFLOW_THRESHOLD) { // Really a subtraction via addition of a negative. // E.g. add esp, 0xfffffff0 is sub esp,16 int32_t TempDelta = (int32_t) (RightUseOp->GetImmedValue() & 0xffffffff); delta = (0 - ((STARS_sval_t) TempDelta)); } else { delta = (0 - ((STARS_sval_t) RightUseOp->GetImmedValue())); } } else { delta = (STARS_sval_t) SMP_STACK_DELTA_ERROR_CODE; } } } } } } return delta; } // end of SMPRegTransfer::ComputeStackPointerAlteration() // Evaluate constant expressions for SCCP algorithm struct STARS_SCCP_Const_Struct SMPRegTransfer::SCCPEvaluateRTLConsts(list<pair<int, int> > &SSAWorkList) { struct STARS_SCCP_Const_Struct ReturnConstStruct; ReturnConstStruct.ConstType = STARS_CONST_TOP; // default value SMPoperator CurrOper = this->GetOperator(); switch (CurrOper) { case SMP_ASSIGN: { STARSOpndTypePtr LeftOp = this->GetLeftOperand(); if (! LeftOp->IsRegOp()) { break; // Only looking to update registers now } bool NewValueAvailable; if (NULL != this->GetGuard()) { // TODO: Evaluate guard expressions. ReturnConstStruct.ConstType = STARS_CONST_BOTTOM; // Don't know value until we can evaluate guards } else if (this->HasRightSubTree()) { ReturnConstStruct = this->GetRightTree()->SCCPEvaluateRTLConsts(SSAWorkList); // recurse into right subtree } else { STARSOpndTypePtr RightOp = this->GetRightOperand(); this->ParentInst->SCCPFetchConstUseValue(RightOp, ReturnConstStruct); } NewValueAvailable = (STARS_CONST_TOP != ReturnConstStruct.ConstType); // Update const map entry for DEF if (NewValueAvailable) { STARSOpndTypePtr SearchLeftOp = CloneIfSubwordReg(LeftOp); CanonicalizeOpnd(SearchLeftOp); struct STARS_SCCP_Const_Struct OldConstStruct; OldConstStruct.ConstType = STARS_CONST_TOP; set<DefOrUse, LessDefUse>::iterator DefIter = this->ParentInst->FindDef(SearchLeftOp); if (DefIter != this->ParentInst->GetLastDef()) { int DefSSANum = DefIter->GetSSANum(); int DefHashValue = HashGlobalNameAndSSA(SearchLeftOp, DefSSANum); bool LocalName = this->ParentInst->GetBlock()->IsLocalName(SearchLeftOp); this->ParentInst->SCCPFetchConstDefValue(LeftOp, OldConstStruct); bool HasOldValue = (STARS_CONST_TOP != OldConstStruct.ConstType); if (HasOldValue) { // must perform type lattice meet operation to update ReturnConstStruct STARSConstantTypeMeet(OldConstStruct, ReturnConstStruct); } if (ReturnConstStruct.ConstType != OldConstStruct.ConstType) { // type change map<int, struct STARS_SCCP_Const_Struct>::iterator NewConstIter; if (LocalName) { NewConstIter = this->ParentInst->GetBlock()->InsertLocalConstValue(DefHashValue, ReturnConstStruct); } else { NewConstIter = this->ParentInst->GetBlock()->GetFunc()->InsertGlobalConstValue(DefHashValue, ReturnConstStruct); } // Propagate along SSA edges. int BlockNum = this->ParentInst->GetBlock()->GetNumber(); pair<int, int> SSAEdge(BlockNum, DefHashValue); SSAWorkList.push_back(SSAEdge); } } } break; // end case for SMP_ASSIGN } case SMP_ADD: case SMP_SUBTRACT: case SMP_U_MULTIPLY: case SMP_S_MULTIPLY: case SMP_BITWISE_AND: case SMP_BITWISE_OR: case SMP_BITWISE_XOR: case SMP_BITWISE_AND_NOT: case SMP_S_COMPARE: case SMP_U_COMPARE: // binary arithmetic operators // We will initially deal with the simple case: The comparison is of a LeftOp register to a RightOp register or immediate. // If the result is definitely zero, we return zero as the const value (presumably to be put into the zero flag). if (!(this->HasRightSubTree())) { STARSOpndTypePtr LeftOp = this->GetLeftOperand(); STARSOpndTypePtr RightOp = this->GetRightOperand(); if ((LeftOp->IsRegOp()) && ((RightOp->IsRegOp()) || (RightOp->IsImmedOp()))) { size_t LeftByteWidth = LeftOp->GetByteWidth(); size_t RightByteWidth = RightOp->GetByteWidth(); STARSOpndTypePtr SearchLeftOp = CloneIfSubwordReg(LeftOp); STARSOpndTypePtr SearchRightOp = CloneIfSubwordReg(RightOp); CanonicalizeOpnd(SearchLeftOp); CanonicalizeOpnd(SearchRightOp); struct STARS_SCCP_Const_Struct LeftValue, RightValue; this->ParentInst->SCCPFetchConstUseValue(SearchLeftOp, LeftValue); bool LeftValueAvailable = (STARS_CONST_TOP != LeftValue.ConstType); if (STARS_CONST_BOTTOM == LeftValue.ConstType) { ReturnConstStruct = LeftValue; break; // right operand is irrelevant if left is BOTTOM } bool RightValueAvailable = false; if (SearchRightOp->IsImmedOp()) { RightValueAvailable = true; RightValue.ConstType = STARS_CONST_HAS_VALUE; RightValue.ConstValue = SearchRightOp->GetImmedValue(); } else { this->ParentInst->SCCPFetchConstUseValue(SearchRightOp, RightValue); RightValueAvailable = (STARS_CONST_TOP != RightValue.ConstType); if (STARS_CONST_BOTTOM == RightValue.ConstType) { ReturnConstStruct = RightValue; break; // left operand is irrelevant if right is BOTTOM } } if (LeftValueAvailable && RightValueAvailable) { // Apply the operator to the values. HandleConstStructWidths(LeftByteWidth, RightByteWidth, LeftValue, RightValue); ReturnConstStruct.ConstType = STARS_CONST_HAS_VALUE; STARS_uval_t TestValue; bool CompareFlag = ((CurrOper == SMP_S_COMPARE) || (CurrOper == SMP_U_COMPARE)); if (CurrOper == SMP_ADD) { TestValue = (LeftValue.ConstValue + RightValue.ConstValue); } else if ((CurrOper == SMP_U_MULTIPLY) || (CurrOper == SMP_S_MULTIPLY)) { TestValue = (LeftValue.ConstValue * RightValue.ConstValue); } else if ((CurrOper == SMP_SUBTRACT) || (CurrOper == SMP_S_COMPARE)) { // Signed compare is a subtraction operation TestValue = (LeftValue.ConstValue - RightValue.ConstValue); } else if ((CurrOper == SMP_U_COMPARE) || (CurrOper == SMP_BITWISE_AND)) { // Unsigned compare is a bitwise AND operation TestValue = (LeftValue.ConstValue & RightValue.ConstValue); } else if (CurrOper == SMP_BITWISE_OR) { TestValue = (LeftValue.ConstValue | RightValue.ConstValue); } else if (CurrOper == SMP_BITWISE_XOR) { TestValue = (LeftValue.ConstValue ^ RightValue.ConstValue); } else if (CurrOper == SMP_BITWISE_AND_NOT) { TestValue = (LeftValue.ConstValue & (~(RightValue.ConstValue))); } else { break; // should be unreachable } if ((0 != TestValue) && CompareFlag) { TestValue = 1; // i.e. zero flag will be set to false } ReturnConstStruct.ConstValue = TestValue; } } // end if two regs, or one reg and one immediate } // end if no right subtree break; // end of signed and unsigned compare operators case case SMP_ZERO_EXTEND: { STARSOpndTypePtr LeftOp = this->GetLeftOperand(); if (LeftOp->IsImmedOp()) { ReturnConstStruct.ConstType = STARS_CONST_HAS_VALUE; ReturnConstStruct.ConstValue = LeftOp->GetImmedValue(); } else if (LeftOp->IsRegOp()) { size_t LeftByteWidth = LeftOp->GetByteWidth(); STARSOpndTypePtr SearchLeftOp = CloneIfSubwordReg(LeftOp); CanonicalizeOpnd(SearchLeftOp); struct STARS_SCCP_Const_Struct LeftValue; this->ParentInst->SCCPFetchConstUseValue(SearchLeftOp, LeftValue); bool LeftValueAvailable = (STARS_CONST_TOP != LeftValue.ConstType); if (STARS_CONST_BOTTOM == LeftValue.ConstType) { ReturnConstStruct = LeftValue; // return the STARS_CONST_BOTTOM value } else if (STARS_CONST_HAS_VALUE == LeftValue.ConstType) { ReturnConstStruct = LeftValue; // zero-extend does not change it } } } break; default: break; // ignore } // end switch(CurrOper) return ReturnConstStruct; } // end of SMPRegTransfer::SCCPEvaluateRTLConsts() // Is stack ptr (or frame ptr) reg in RT? bool SMPRegTransfer::IsStackPtrUsedInRT(bool UseFP) const { bool StackPtrUsed = false; if (this->GetLeftOperand()->IsRegOp()) { if (this->GetLeftOperand()->MatchesReg(MD_STACK_POINTER_REG) || (UseFP && this->GetLeftOperand()->MatchesReg(MD_FRAME_POINTER_REG))) { StackPtrUsed = true; } } if (!StackPtrUsed) { if (this->HasRightSubTree()) { StackPtrUsed = this->GetRightTree()->IsStackPtrUsedInRT(UseFP); } else if (this->GetRightOperand()->IsRegOp()) { if (this->GetRightOperand()->MatchesReg(MD_STACK_POINTER_REG) || (UseFP && this->GetRightOperand()->MatchesReg(MD_FRAME_POINTER_REG))) { StackPtrUsed = true; } } } return StackPtrUsed; } // end of SMPRegTransfer::IsStackPtrUsedInRT() // Is RT a move of a const or subreg into a subreg? bool SMPRegTransfer::IsSubregMove(void) const { bool SubregMove = false; const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm(); if ((nullptr != LeftOp) && (LeftOp->IsRegOp())) { bool SubregDest = (LeftOp->GetByteWidth() < 4); // move into EAX zeroes out upper RAX, but move into AX does not. SubregMove = (SubregDest && (!this->HasRightSubTree()) && (SMP_ASSIGN == this->GetOperator())); } return SubregMove; } // sign-extend RightOperand if it needs to become 64 bit operand size_t SMPRegTransfer::MDSignExtend64RightOpIfNeeded(void) { size_t OriginalByteWidth = this->RightOperand->GetByteWidth(); size_t FinalByteWidth = OriginalByteWidth; if (this->ParentInst->MDHas64BitOperands() && (this->RightOperand->IsImmedOp() || this->RightOperand->IsMemOp()) && (4 >= OriginalByteWidth)) { // On x86-64, less than 64-bit immediate and memory operands are sign-extended in the hardware on opcodes that // have 64-bit operands. For example, "pushq 0x1234" looks like a 32-bit immediate push, but the pushq opcode // as printed by objdump indicates that it will be sign-extended to 64 bits. Ditto for "pushq [rbp-4]" where the // memory operand is 32 bit in the IRDB view. In both cases, the operand has been sign-extended behind the scenes // by IDA Pro so no action will be needed, as the RightOperand->GetByteWidth() above will return 8 in IDA Pro. SMPRegTransfer *ExtendedRT = new SMPRegTransfer; ExtendedRT->SetOperator(SMP_SIGN_EXTEND); ExtendedRT->SetLeftOperand(this->RightOperand); ExtendedRT->SetRightOperand(this->ParentInst->MakeVoidOpnd()); ExtendedRT->SetParentInst(this->ParentInst); this->SetRightTree(ExtendedRT); FinalByteWidth = 8; SMP_msg("INFO: Sign-extending right RTL operand to 64 bits at %llx\n", (unsigned long long) this->ParentInst->GetAddr()); } return FinalByteWidth; } // end of SMPRegTransfer::MDSignExtend64RightOpIfNeeded() // for SPARK Ada translation bool SMPRegTransfer::RightTreeNeedsWidthCast(FILE *OutFile, std::size_t LeftBitWidth, std::size_t &RightBitWidth) const { RightBitWidth = LeftBitWidth; if (!this->HasRightSubTree()) return false; SMPRegTransfer *RightRT = this->GetRightTree(); assert(NULL != RightRT); // Initial cases: zero-extension and sign-extension; add more cases as required if (SMP_ZERO_EXTEND == RightRT->GetOperator()) { const STARSOpndTypePtr RightLeftOp = RightRT->GetConstLeftOperandNoNorm(); RightBitWidth = RightLeftOp->GetByteWidth() * 8; if (LeftBitWidth != RightBitWidth) { SMP_fprintf(OutFile, "Unsigned%u(", LeftBitWidth); } } else if (SMP_SIGN_EXTEND == RightRT->GetOperator()) { const STARSOpndTypePtr RightLeftOp = RightRT->GetConstLeftOperandNoNorm(); RightBitWidth = RightLeftOp->GetByteWidth() * 8; if (LeftBitWidth != RightBitWidth) { SMP_fprintf(OutFile, "X86.SignExtend%uTo%u(", RightBitWidth, LeftBitWidth); } } return (LeftBitWidth != RightBitWidth); } // end of SMPRegTransfer::RightTreeNeedsWidthCast() // Is RT irrelevant for SPARK, e.g. floating-point operations that the SPARK provers will not model bool SMPRegTransfer::IsSPARKAdaNop(void) const { SMPoperator CurrOperator = this->GetOperator(); bool SPARKNop = ((CurrOperator == SMP_NULL_OPERATOR) || (CurrOperator == SMP_UNARY_NUMERIC_OPERATION) || (CurrOperator == SMP_BINARY_NUMERIC_OPERATION) || (CurrOperator == SMP_UNARY_FLOATING_ARITHMETIC) || (CurrOperator == SMP_BINARY_FLOATING_ARITHMETIC) || (CurrOperator == SMP_UNARY_POINTER_OPERATION)); if (!SPARKNop && this->HasRightSubTree()) { SPARKNop = this->GetRightTree()->IsSPARKAdaNop(); } if (!SPARKNop && (SMP_ASSIGN == CurrOperator)) { const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm(); const STARSOpndTypePtr RightOp = this->GetConstRightOperandNoNorm(); if ((nullptr != LeftOp) && (nullptr != RightOp) && LeftOp->IsFloatingPointRegOp() && RightOp->IsFloatingPointRegOp()) { SPARKNop = (LeftOp->GetReg() == RightOp->GetReg()); // e.g. fld st just duplicates top of stack } } return SPARKNop; } // end of SMPRegTransfer::IsSPARKAdaNop() // Debug print void SMPRegTransfer::Dump(void) const { if (NULL != this->Guard) this->Guard->Dump(); // Left operand if ((nullptr != this->LeftOperand) && (! this->LeftOperand->IsVoidOp())) PrintOperand(this->LeftOperand); // Then the operator SMP_msg(" %s ", OperatorText[this->GetOperator()]); // then the right operand or subtree if (this->HasRightSubTree()) this->GetRightTree()->Dump(); else if ((nullptr != this->RightOperand) && (!this->RightOperand->IsVoidOp())) PrintOperand(this->RightOperand); SMP_msg("\n"); return; } // end of SMPRegTransfer::Dump() // emit SPARK-Ada procedure suffix, e.g. _reg32_reg32( for the add_reg32_reg32() case void SMPRegTransfer::EmitSPARKAdaProcSuffix(FILE *OutFile) const { PrintOperandSPARKAdaSuffix(this->GetLeftOperand(), OutFile); if (!this->HasRightSubTree()) { PrintOperandSPARKAdaSuffix(this->GetRightOperand(), OutFile); } else { PrintOperandSPARKAdaSuffix(this->GetRightTree()->GetRightOperand(), OutFile); } return; } // end of SMPRegTransfer::EmitSPARKAdaProcSuffix() // Helper for right hand side of statements (i.e. RightOperand or RightTree) void SMPRegTransfer::EmitSPARKAdaForRHS(FILE *OutFile, bool RecursiveCall) const { #if 1 std::size_t LeftOpBitWidth, RightOpBitWidth; bool Truncated = false; bool UseFP = this->ParentInst->GetBlock()->GetFunc()->UsesFramePointer(); bool X86ProcCall = this->GetParentInst()->MDIsArithmeticUsingCarryFlag(); size_t ISA_ByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); if (!RecursiveCall && (this->IsTruncatedWidthRTL(LeftOpBitWidth, RightOpBitWidth) || this->IsExpandedWidthRTL(LeftOpBitWidth, RightOpBitWidth))) { // We don't want to cast to 128 bits or more for XMM, YMM et al. registers. In many cases, // the opcode really means to write only the lowest 64 bits and IDA Pro says the reg is 128 bits. if (LeftOpBitWidth > 80) LeftOpBitWidth = 64; if (LeftOpBitWidth != RightOpBitWidth) { Truncated = true; SMP_fprintf(OutFile, "Unsigned%d(", LeftOpBitWidth); } } if (this->HasRightSubTree()) { // NOTE: Handle operators like Shift_right() !!!!****!!!! SMPRegTransfer *RightRT = this->GetRightTree(); size_t LeftByteWidth = this->GetConstLeftOperandNoNorm()->GetByteWidth(); LeftOpBitWidth = LeftByteWidth * 8; bool ShortLeftWidth = (ISA_ByteWidth > LeftByteWidth); size_t RightTreeBitWidth; bool NeedWidthCast = this->RightTreeNeedsWidthCast(OutFile, LeftOpBitWidth, RightTreeBitWidth); string OperatorString; bool OperatorIsProcCall = false; bool PrefixUnaryOperator = false; SMP_fprintf(OutFile, "("); SMPoperator CurrOper = RightRT->GetOperator(); bool ConstFollows = (!RightRT->HasRightSubTree()) && RightRT->GetConstRightOperandNoNorm()->IsImmedOp(); PrintSPARKAdaOperator(CurrOper, OperatorString, OperatorIsProcCall, PrefixUnaryOperator, ConstFollows); const STARSOpndTypePtr LeftOp = RightRT->GetConstLeftOperandNoNorm(); if (!OperatorIsProcCall) { if (!PrefixUnaryOperator) { this->ParentInst->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, "%s", OperatorString.c_str()); RightRT->EmitSPARKAdaForRHS(OutFile, true); // recurse on right tree or operand } else { // unary prefix operator, such as unary negation SMP_fprintf(OutFile, "%s", OperatorString.c_str()); this->ParentInst->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); } } else { // printing something like Interfaces.Shift_Right(LeftOp, RightOp) STARSOpndTypePtr LeftOp2 = LeftOp->clone(); if (X86ProcCall && ShortLeftWidth) { // We have to pass the 64-bit register even for 32-bit add-with-carry and subtract-with-borrow. LeftOp2->SetByteWidth(ISA_ByteWidth); } SMP_fprintf(OutFile, "%s(", OperatorString.c_str()); // proc call name + open parenthesis for arguments this->ParentInst->PrintSPARKAdaOperand(LeftOp2, OutFile, false, UseFP, true, false); // LeftOp is first argument SMP_fprintf(OutFile, " , "); // separate args with a comma RightRT->EmitSPARKAdaForRHS(OutFile, true); // recurse on right tree or operand SMP_fprintf(OutFile, ")"); // close parenthesis for procedure call arguments } if (NeedWidthCast) { SMP_fprintf(OutFile, ")"); // close parenthesis printed within RightTreeNeedsWidthCast() } SMP_fprintf(OutFile, ")"); } else { const STARSOpndTypePtr RightOp = this->GetConstRightOperandNoNorm(); this->ParentInst->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); } if (!RecursiveCall && Truncated) { SMP_fprintf(OutFile, ")"); // close cast of right hand side } #endif return; } // end of SMPRegTransfer::EmitSPARKAdaForRHS() // Emit SPARK-Ada translation of RT void SMPRegTransfer::EmitSPARKAda(FILE *OutFile) { const STARSOpndTypePtr LeftOp = this->GetConstLeftOperandNoNorm(); if ((nullptr == LeftOp) || this->IsSPARKAdaNop()) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "null;\n"); // Ada no-op return; } SMPoperator CurrOper = this->GetOperator(); assert(CurrOper == SMP_ASSIGN); bool X86ProcCall = this->GetParentInst()->MDIsArithmeticUsingCarryFlag(); uint16_t LeftByteWidth = LeftOp->GetByteWidth(); size_t ISA_ByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); bool MemWrite = LeftOp->IsMemOp(); bool ShortLeftWidth = (ISA_ByteWidth > LeftByteWidth); bool LongLeftWidth = (ISA_ByteWidth < LeftByteWidth); bool SubregWrite = (LeftOp->IsRegOp() && ShortLeftWidth); bool OperatorIsProcCall = false; bool PrefixUnaryOperator = false; bool UseFP = this->ParentInst->GetBlock()->GetFunc()->UsesFramePointer(); PrintSPARKIndentTabs(OutFile); if (X86ProcCall) { // We don't emit X := X + Y; we emit ProcName(X, Y); this->EmitSPARKAdaForRHS(OutFile, false); } else { this->ParentInst->PrintSPARKAdaOperand(LeftOp, OutFile, true, UseFP, true, false); if (MemWrite) { // We have printed X86.WriteMem##((Unsigned64(LeftOpnd), // Now we need to print Unsigned##(right-hand-side)) if (ShortLeftWidth || LongLeftWidth) { char CastString[25]; GetSPARKWidthCastString(LeftByteWidth, CastString); SMP_fprintf(OutFile, "%s(", CastString); } this->EmitSPARKAdaForRHS(OutFile, false); if (ShortLeftWidth || LongLeftWidth) { // Close cast parentheses and MemWrite parentheses. SMP_fprintf(OutFile, "))"); } else { // no cast; just close MemWrite parenthesis. SMP_fprintf(OutFile, ")"); } } else { if (!SubregWrite) { // Print := operator unless we are assigning with a procedure call. string OutString; PrintSPARKAdaOperator(CurrOper, OutString, OperatorIsProcCall, PrefixUnaryOperator, false); assert(!OperatorIsProcCall); assert(!PrefixUnaryOperator); SMP_fprintf(OutFile, "%s", OutString.c_str()); } this->EmitSPARKAdaForRHS(OutFile, false); if (SubregWrite) { // Have to write with a procedure call, e.g. Write_AX(Right-Hand-Side). // Close the procedure call parenthesis. SMP_fprintf(OutFile, ")"); } } } SMP_fprintf(OutFile, ";\n"); return; } // end of SMPRegTransfer::EmitSPARKAda() // ***************************************************************** // Class SMPRTL // ***************************************************************** // Constructor SMPRTL::SMPRTL() { this->RTCount = 0; this->ExtraKills.clear(); return; } // Destructor SMPRTL::~SMPRTL() { for (std::size_t index = 0; index < this->RTCount; ++index) { delete (this->RTvector[index]); } this->ExtraKills.clear(); return; } // Get methods SMPRegTransfer *SMPRTL::GetRT(std::size_t index) const { if (index > this->RTCount) return NULL; else return this->RTvector[index]; } // Set methods void SMPRTL::push_back(SMPRegTransfer *NewEffect) { assert(SMP_RT_LIMIT > this->RTCount); this->RTvector[this->RTCount] = NewEffect; ++(this->RTCount); return; } // Printing methods void SMPRTL::Dump(void) const { std::size_t index; if (0 < this->RTCount) { SMP_msg("RTL: "); for (index = 0; index < this->RTCount; ++index) { this->RTvector[index]->Dump(); } if (!this->ExtraKills.empty()) { for (index = 0; index < this->ExtraKills.size(); ++index) { SMP_msg(" KILL: "); PrintOperand(this->ExtraKills.at(index)); } SMP_msg("\n"); } } return; } // end of SMPRTL::Dump() // Accumulate stack pointer alteration total across all RTs. STARS_sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, STARS_sval_t IncomingDelta, STARS_sval_t FramePtrDelta) { STARS_sval_t TotalDelta = 0; STARS_sval_t IncrementalDelta; for (std::size_t index = 0; index < this->RTCount; ++index) { IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, IncomingDelta, FramePtrDelta); if ((SMP_STACK_DELTA_ERROR_CODE == (STARS_uval_t) IncrementalDelta) || (SMP_STACK_POINTER_BITWISE_AND_CODE == (STARS_uval_t) IncrementalDelta)) { TotalDelta = IncrementalDelta; // pass code back break; // exit loop and return coded value } else { TotalDelta += IncrementalDelta; } } return TotalDelta; } // end of SMPRTL::TotalStackPointerAlteration() // ***************************************************************** // Class STARSExpression // ***************************************************************** // Constructors STARSExpression::STARSExpression(void) { this->LeftOperand = nullptr; this->LeftUseAddr = STARS_BADADDR; this->LeftSSANum = SMP_SSA_UNINIT; this->RightOperand = nullptr; this->RightUseAddr = STARS_BADADDR; this->RightSSANum = SMP_SSA_UNINIT; this->ExprOperator = SMP_NULL_OPERATOR; this->LeftExpr = nullptr; this->RightExpr = nullptr; this->ParentInst = nullptr; this->OriginalParentInst = nullptr; this->ParentFunc = nullptr; this->LeftPreLoopDefAddr = STARS_BADADDR; this->RightPreLoopDefAddr = STARS_BADADDR; this->booleans1 = 0; return; } // Construct from an RTL subtree. STARSExpression::STARSExpression(SMPRegTransfer *RTExpr) { this->SetOperator(RTExpr->GetOperator()); this->booleans1 = 0; this->ParentInst = RTExpr->GetParentInst(); this->OriginalParentInst = this->GetParentInst(); this->LeftPreLoopDefAddr = STARS_BADADDR; this->RightPreLoopDefAddr = STARS_BADADDR; STARS_ea_t InstAddr = this->ParentInst->GetAddr(); this->SetParentFunc(this->ParentInst->GetBlock()->GetFunc()); bool UseFP = this->GetParentFunc()->UsesFramePointer(); STARSOpndTypePtr LeftOp = RTExpr->GetLeftOperand(); this->SetLeftOperand(LeftOp); this->SetLeftUseAddr(InstAddr); this->SetLeftTree(nullptr); // RTL subtrees never have left subtrees if (this->GetConstLeftOperand() != nullptr) { if (MDIsDataFlowOpnd(LeftOp, UseFP)) { STARSDefUseIter LeftIter; bool GoodIter = false; if (this->GetOperator() == SMP_ASSIGN) { LeftIter = RTExpr->GetParentInst()->FindDef(LeftOp); GoodIter = (LeftIter != RTExpr->GetParentInst()->GetLastDef()); } else { LeftIter = RTExpr->GetParentInst()->FindUse(LeftOp); GoodIter = (LeftIter != RTExpr->GetParentInst()->GetLastUse()); } if (GoodIter) { this->SetLeftSSANum(LeftIter->GetSSANum()); } else { SMP_msg("ERROR: Bad DefOrUseIter in STARSExpression from RTL at %llx\n", (uint64_t) InstAddr); this->SetLeftSSANum(SMP_SSA_UNINIT); } } else { this->SetLeftSSANum(SMP_SSA_UNINIT); } } if (RTExpr->HasRightSubTree()) { this->SetRightOperand(nullptr); SMPRegTransfer *RightRTExpr = RTExpr->GetRightTree(); STARSExpression *RightSubExpr = new STARSExpression(RightRTExpr); // recurse this->SetRightTree(RightSubExpr); } else { this->SetRightTree(nullptr); STARSOpndTypePtr RightOp = RTExpr->GetRightOperand(); this->SetRightOperand(RightOp); this->SetRightUseAddr(RTExpr->GetParentInst()->GetAddr()); if (this->GetConstRightOperand() != nullptr) { if (MDIsDataFlowOpnd(RightOp, UseFP)) { STARSDefUseIter RightUseIter = RTExpr->GetParentInst()->FindUse(RightOp); if (RightUseIter != RTExpr->GetParentInst()->GetLastUse()) { this->SetRightSSANum(RightUseIter->GetSSANum()); } else { this->SetRightSSANum(SMP_SSA_UNINIT); } } else { this->SetRightSSANum(SMP_SSA_UNINIT); } } } return; } // build from a DEF or USE STARSExpression::STARSExpression(const STARSDefUseIter Ref, SMPInstr *CurrInst) { this->SetParentFunc(CurrInst->GetBlock()->GetFunc()); this->SetParentInst(CurrInst); this->OriginalParentInst = CurrInst; this->SetRightOperand(nullptr); this->RightExpr = nullptr; this->SetRightPreLoopDefAddr(STARS_BADADDR); this->SetRightSSANum(SMP_SSA_UNINIT); this->SetLeftPreLoopDefAddr(STARS_BADADDR); this->booleans1 = 0; if (MDIsDataFlowOpnd(Ref->GetOp(), this->GetParentFunc()->UsesFramePointer())) { this->SetLeftOperand(Ref->GetOp()); this->SetLeftUseAddr(CurrInst->GetAddr()); this->SetLeftSSANum(Ref->GetSSANum()); this->SetOperator(SMP_ASSIGN); } else if (Ref->GetOp()->IsMemOp()) { // must be indirect memory access this->SetOperator(SMP_SYMBOLIC_READ_MEMORY); STARSExpression *MemAddrExpr = this->GetParentFunc()->CreateMemoryAddressExpr(Ref->GetOp(), CurrInst); assert(nullptr != MemAddrExpr); this->SetLeftTree(MemAddrExpr); } return; } // Destructor STARSExpression::~STARSExpression() { if (this->HasRightSubTree() && (nullptr != this->RightExpr)) delete this->RightExpr; if (this->HasLeftSubTree() && (nullptr != this->LeftExpr)) delete this->LeftExpr; return; } // Allocate a new tree, recursively copy in subtrees STARSExpression* STARSExpression::Clone(void) const { STARSExpression *ClonedExpr = new STARSExpression(); ClonedExpr->SetOperator(this->GetOperator()); ClonedExpr->SetParentInst(this->GetParentInst()); ClonedExpr->OriginalParentInst = this->OriginalParentInst; ClonedExpr->SetParentFunc(this->GetParentFunc()); if (this->HasLeftSubTree()) { ClonedExpr->SetLeftTree(this->GetLeftTree()->Clone()); // recurse } else { ClonedExpr->SetLeftOperand(this->GetLeftOperand()); ClonedExpr->SetLeftUseAddr(this->GetLeftUseAddr()); ClonedExpr->SetLeftSSANum(this->GetLeftSSANum()); ClonedExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); } if (this->HasRightSubTree()) { ClonedExpr->SetRightTree(this->GetRightTree()->Clone()); // recurse } else { ClonedExpr->SetRightOperand(this->GetRightOperand()); ClonedExpr->SetRightUseAddr(this->GetRightUseAddr()); ClonedExpr->SetRightSSANum(this->GetRightSSANum()); ClonedExpr->SetRightPreLoopDefAddr(this->GetRightPreLoopDefAddr()); } return ClonedExpr; } // end of STARSExpression::Clone() // Allocate a new tree, make it a copy of left-hand-side of this tree. STARSExpression *STARSExpression::CloneLHS(void) const { if (this->HasLeftSubTree()) { STARSExpression *LeftExpr = this->GetLeftTree()->Clone(); return LeftExpr; } else { STARSOpndTypePtr LeftOp = this->GetLeftOperand(); assert(nullptr != LeftOp); STARSExpression *LeftExpr = new STARSExpression(); LeftExpr->SetParentFunc(this->GetParentFunc()); LeftExpr->SetParentInst(this->GetParentInst()); LeftExpr->OriginalParentInst = this->OriginalParentInst; LeftExpr->SetOperator(SMP_ASSIGN); LeftExpr->SetLeftOperand(LeftOp); LeftExpr->SetLeftUseAddr(this->GetLeftUseAddr()); LeftExpr->SetLeftSSANum(this->GetLeftSSANum()); LeftExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); return LeftExpr; } } // end of STARSExpression::CloneLHS() // Allocate a new tree, make it a copy of right-hand-side of this tree. STARSExpression *STARSExpression::CloneRHS(void) const { if (this->HasRightSubTree()) { STARSExpression *RightExpr = this->GetRightTree()->Clone(); return RightExpr; } else { STARSOpndTypePtr RightOp = this->GetConstRightOperand(); assert(nullptr != RightOp); STARSExpression *RightExpr = new STARSExpression(); RightExpr->SetParentFunc(this->GetParentFunc()); RightExpr->SetParentInst(this->GetParentInst()); RightExpr->OriginalParentInst = this->OriginalParentInst; RightExpr->SetOperator(SMP_ASSIGN); RightExpr->SetLeftOperand(RightOp); RightExpr->SetLeftUseAddr(this->GetRightUseAddr()); RightExpr->SetLeftSSANum(this->GetRightSSANum()); RightExpr->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr()); return RightExpr; } } // end of STARSExpression::CloneRHS() // LessThan operator for ordered containers, such as sets. bool STARSExpression::operator<(const STARSExpression &rExpr) const { bool LessThan = false; bool GreaterThan = false; if (this->GetOperator() < rExpr.GetOperator()) { return true; } else if (this->GetOperator() != rExpr.GetOperator()) { return false; } if (this->HasLeftSubTree()) { if (!rExpr.HasLeftSubTree()) { return false; // operand is less than tree } else { // both exprs have left trees #if 1 // Speed up by checking instruction IDs of OrigParentInst before recursing. STARS_ea_t ThisParentAddr = this->GetOriginalParentInst()->GetAddr(); STARS_ea_t OtherParentAddr = rExpr.GetOriginalParentInst()->GetAddr(); if (ThisParentAddr != OtherParentAddr) return (ThisParentAddr < OtherParentAddr); #endif LessThan = (*(this->GetLeftTree()) < (*(rExpr.GetLeftTree()))); // recurse if (LessThan) { return true; } else { GreaterThan = (*(rExpr.GetLeftTree()) < (*(this->GetLeftTree()))); // recurse if (GreaterThan) return false; } } } else if (rExpr.HasLeftSubTree()) { return true; // operand is less than tree } else { // both have LeftOperand if (nullptr == this->GetConstLeftOperand()) { return (nullptr != rExpr.GetConstLeftOperand()); // nullptr < operand } else if (nullptr == rExpr.GetConstLeftOperand()) { return false; // operand is greater than nullptr } #if 1 // Make SSANum a priority key value because it is faster to compare than operands. if (this->GetLeftSSANum() != rExpr.GetLeftSSANum()) return (this->GetLeftSSANum() < rExpr.GetLeftSSANum()); #endif LessThan = (*(this->GetConstLeftOperand()) < (*(rExpr.GetConstLeftOperand()))); // use STARS_op_t < operator if (LessThan) { return true; } else { GreaterThan = (*(rExpr.GetConstLeftOperand()) < (*(this->GetConstLeftOperand()))); // use STARS_op_t < operator if (GreaterThan) return false; } } // At this point, the left hand sides did not answer the question and we look at the right hand sides. if (this->HasRightSubTree()) { if (!rExpr.HasRightSubTree()) { return false; // operand is less than tree } else { #if 1 // Speed up by checking instruction IDs of OrigParentInst before recursing. STARS_ea_t ThisParentAddr = this->GetOriginalParentInst()->GetAddr(); STARS_ea_t OtherParentAddr = rExpr.GetOriginalParentInst()->GetAddr(); if (ThisParentAddr != OtherParentAddr) return (ThisParentAddr < OtherParentAddr); #endif LessThan = (*(this->GetRightTree()) < (*(rExpr.GetRightTree()))); // recurse if (LessThan) { return true; } } } else if (rExpr.HasRightSubTree()) { return true; // operand is less than tree } else { // both have RightOperand if (nullptr == this->GetConstRightOperand()) { return (nullptr != rExpr.GetConstRightOperand()); // nullptr < operand } else if (nullptr == rExpr.GetConstRightOperand()) { return false; // operand is greater than nullptr } #if 1 // Make SSANum a priority key value because it is faster to compare than operands. if (this->GetRightSSANum() != rExpr.GetRightSSANum()) return (this->GetRightSSANum() < rExpr.GetRightSSANum()); #endif LessThan = (*(this->GetConstRightOperand()) < (*(rExpr.GetConstRightOperand()))); // use STARS_op_t < operator if (LessThan) { return true; } else { GreaterThan = (*(rExpr.GetConstRightOperand()) < (*(this->GetConstRightOperand()))); // use STARS_op_t < operator if (GreaterThan) return false; } } return LessThan; } // end of STARSExpression::operator<() // are exprs identical in operands and operators? bool STARSExpression::IsEqualExpr(const STARSExpression *OtherExpr) const { bool Identical = true; if ((this->GetOperator() == OtherExpr->GetOperator()) && (this->HasLeftSubTree() == OtherExpr->HasLeftSubTree()) && (this->HasRightSubTree() == OtherExpr->HasRightSubTree())) { // Compare operands, if any, or recurse into subtrees. if (!this->HasLeftSubTree()) { if ((this->GetLeftSSANum() != OtherExpr->GetLeftSSANum()) || (!IsEqOp(this->GetConstLeftOperand(), OtherExpr->GetConstLeftOperand()))) { return false; } } else if (!this->GetLeftTree()->IsEqualExpr(OtherExpr->GetLeftTree())) { return false; } if (!this->HasRightSubTree()) { if ((this->GetRightSSANum() != OtherExpr->GetRightSSANum()) || (!IsEqOp(this->GetConstRightOperand(), OtherExpr->GetConstRightOperand()))) { return false; } } else if (!this->GetRightTree()->IsEqualExpr(OtherExpr->GetRightTree())) { return false; } } else { Identical = false; } return Identical; } // end of STARSExpression::IsEqualExpr() // are exprs identical except for ImmedOp values? bool STARSExpression::IsEqualExprExceptingImmedOpnds(const STARSExpression *OtherExpr) const { bool Identical = true; if ((this->GetOperator() == OtherExpr->GetOperator()) && (this->HasLeftSubTree() == OtherExpr->HasLeftSubTree()) && (this->HasRightSubTree() == OtherExpr->HasRightSubTree())) { // Compare operands, if any, or recurse into subtrees. if (!this->HasLeftSubTree()) { if ((this->GetLeftSSANum() != OtherExpr->GetLeftSSANum()) || (!IsEqOpIgnoreImmedValues(this->GetConstLeftOperand(), OtherExpr->GetConstLeftOperand()))) { return false; } } else if (!this->GetLeftTree()->IsEqualExprExceptingImmedOpnds(OtherExpr->GetLeftTree())) { return false; } if (!this->HasRightSubTree()) { if ((this->GetRightSSANum() != OtherExpr->GetRightSSANum()) || (!IsEqOpIgnoreImmedValues(this->GetConstRightOperand(), OtherExpr->GetConstRightOperand()))) { return false; } } else if (!this->GetRightTree()->IsEqualExprExceptingImmedOpnds(OtherExpr->GetRightTree())) { return false; } } else { Identical = false; } return Identical; } // end of STARSExpression::IsEqualExprExceptingImmedOpnds() // Print the stack pointer plus optional offset constant to the AnnotFile. void STARSExpression::AnnotPrintStackPtrPlusOffset(FILE *AnnotFile) const { SMPoperator CurrOper = this->GetOperator(); bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetConstLeftOperand()->IsRegOp() && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG); bool SPPlusOffset = false; bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd; // SMP_ASSIGN in expr means no RHS if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) { const STARSOpndTypePtr RightOp = this->GetConstRightOperand(); bool HasRightTree = this->HasRightSubTree(); bool ImmedRightOp = (nullptr != RightOp) && (!HasRightTree) && RightOp->IsImmedOp(); SPPlusOffset = ImmedRightOp; } if (JustStackPtr) { SMP_fprintf(AnnotFile, "RSP "); } else if (SPPlusOffset) { SMP_fprintf(AnnotFile, "RSP "); bool UnaryOper = false; switch (CurrOper) { case SMP_DECREMENT: UnaryOper = true; SMP_fprintf(AnnotFile, "- 1"); break; case SMP_INCREMENT: UnaryOper = true; SMP_fprintf(AnnotFile, "+ 1"); break; case SMP_ADD: case SMP_ADD_CARRY: SMP_fprintf(AnnotFile, "+"); break; case SMP_SUBTRACT: case SMP_SUBTRACT_BORROW: SMP_fprintf(AnnotFile, "-"); break; default: SMP_msg("FATAL ERROR: Invalid operator in AnnotPrintStackPtrPlusOffset.\n"); this->Dump(); assert(false); } if (!UnaryOper) { // Print the immediate offset AnnotPrintOperand(this->GetConstRightOperand(), AnnotFile, true, true); } } return; } // end of STARSExpression::AnnotPrintStackPtrPlusOffset() // Print the stack pointer plus optional offset constant to the AnnotString void STARSExpression::StringPrintStackPtrPlusOffset(string &AnnotString) const { SMPoperator CurrOper = this->GetOperator(); bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetConstLeftOperand()->IsRegOp() && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG); bool SPPlusOffset = false; bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd; // SMP_ASSIGN in expr means no RHS if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) { const STARSOpndTypePtr RightOp = this->GetConstRightOperand(); bool HasRightTree = this->HasRightSubTree(); bool ImmedRightOp = (nullptr != RightOp) && (!HasRightTree) && RightOp->IsImmedOp(); SPPlusOffset = ImmedRightOp; } if (JustStackPtr) { AnnotString += "RSP "; } else if (SPPlusOffset) { AnnotString += "RSP"; bool UnaryOper = false; switch (CurrOper) { case SMP_DECREMENT: UnaryOper = true; AnnotString += "-1"; break; case SMP_INCREMENT: UnaryOper = true; AnnotString += "+1"; break; case SMP_ADD: case SMP_ADD_CARRY: AnnotString += "+"; break; case SMP_SUBTRACT: case SMP_SUBTRACT_BORROW: AnnotString += "-"; break; default: SMP_msg("FATAL ERROR: Invalid operator in AnnotPrintStackPtrPlusOffset.\n"); this->Dump(); assert(false); } if (!UnaryOper) { // Print the immediate offset StringPrintOperand(this->GetConstRightOperand(), AnnotString, true, true); } } return; } // end of STARSExpression::StringPrintStackPtrPlusOffset() void STARSExpression::Dump(const std::size_t TabCount) const { SMP_msg("\n"); for (size_t count = 0; count < TabCount; ++count) { SMP_msg("\t"); } bool AssignOperator = (SMP_ASSIGN == this->GetOperator()); // RHS is unused for SMP_ASSIGN expressions bool SymbolicMemoryOperator = (SMP_SYMBOLIC_READ_MEMORY == this->GetOperator()); SMP_msg(" OrigParentInst : %llx ParentInst: %llx %s \n", (uint64_t) this->GetOriginalParentInst()->GetAddr(), (uint64_t) this->GetParentInst()->GetAddr(), OperatorText[this->GetOperator()]); for (size_t count = 0; count < TabCount; ++count) { SMP_msg("\t"); } SMP_msg("(\n"); // open parenthesis // Left operand or subtree if (this->HasLeftSubTree()) { this->GetLeftTree()->Dump(1 + TabCount); } else if ((nullptr != this->LeftOperand) && (!this->LeftOperand->IsVoidOp())) { for (size_t count = 0; count < (1 + TabCount); ++count) { SMP_msg("\t"); } PrintOperand(this->GetConstLeftOperand()); if (!this->GetConstLeftOperand()->IsImmedOp()) { SMP_msg(" SSA: %d UseAddr: %llx PreLoopAddr: %llx", this->GetLeftSSANum(), (uint64_t) this->GetLeftUseAddr(), (uint64_t) this->GetLeftPreLoopDefAddr()); } } if (!(AssignOperator || SymbolicMemoryOperator)) { SMP_msg(" ,\n"); // then the right operand or subtree if (this->HasRightSubTree()) { this->GetRightTree()->Dump(1 + TabCount); } else if ((nullptr != this->RightOperand) && (!this->RightOperand->IsVoidOp())) { for (size_t count = 0; count < (1 + TabCount); ++count) { SMP_msg("\t"); } PrintOperand(this->GetConstRightOperand()); if (!this->GetConstRightOperand()->IsImmedOp()) { SMP_msg(" SSA: %d UseAddr: %llx PreLoopAddr: %llx", this->GetRightSSANum(), (uint64_t) this->GetRightUseAddr(), (uint64_t) this->GetRightPreLoopDefAddr()); } } } SMP_msg("\n"); for (size_t count = 0; count < TabCount; ++count) { SMP_msg("\t"); } SMP_msg(");\n"); // close the open parenthesis return; } // end of STARSExpression::Dump() // Emit SPARK Ada translation of expression to OutputFile, perhaps with Reg'Old suffix. // OffByOne should never be true for subtrees, only certain parent trees. void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs, bool UseSavedStackPtr, bool NoLHSArgs) const { #if 1 std::string OutString; this->EmitSPARKAdaString(OutString, ProcessingLoop, OldSuffix, OffByOne, HasLoopArgs, UseSavedStackPtr, NoLHSArgs); SMP_fprintf(OutputFile, "%s", OutString.c_str()); #else bool UseFP = this->GetParentFunc()->UsesFramePointer(); bool PrefixProcCall = false; bool UnaryPrefix = false; string OperatorString; SMPoperator CurrOperator = this->GetOperator(); bool IsRelational = IsRelationalOperator(CurrOperator); bool IsSymbolicReadMem = (SMP_SYMBOLIC_READ_MEMORY == CurrOperator); bool ConstFollows = (!this->HasRightSubTree() && (SMP_ASSIGN != CurrOperator) && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp()); // If we can convert the OffByOne+IsRelational case from > to >=, or from < to <=, then we can avoid adding one to the limit. if (IsRelational && OffByOne) { if (CurrOperator == SMP_GREATER_THAN) { CurrOperator = SMP_GREATER_EQUAL; OffByOne = false; // no more adjustment needed } else if (CurrOperator == SMP_LESS_THAN) { CurrOperator = SMP_LESS_EQUAL; OffByOne = false; // no more adjustment needed } else if (CurrOperator == SMP_ABOVE) { CurrOperator = SMP_ABOVE_EQUAL; OffByOne = false; // no more adjustment needed } else if (CurrOperator == SMP_BELOW) { CurrOperator = SMP_BELOW_EQUAL; OffByOne = false; // no more adjustment needed } } if (SMP_ASSIGN != CurrOperator) { PrintSPARKAdaOperator(CurrOperator, OperatorString, PrefixProcCall, UnaryPrefix, ConstFollows); if (PrefixProcCall) { // operator comes first, as a procedure call SMP_fprintf(OutputFile, "%s(", OperatorString.c_str()); } else if (UnaryPrefix) { // operator comes first SMP_fprintf(OutputFile, "%s", OperatorString.c_str()); if (IsSymbolicReadMem) SMP_fprintf(OutputFile, "("); } } // Left operand or subtree if (this->HasLeftSubTree()) { SMP_fprintf(OutputFile, "("); this->GetLeftTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, NoLHSArgs); SMP_fprintf(OutputFile, ")"); } else if ((nullptr != this->GetConstLeftOperand()) && (!this->GetConstLeftOperand()->IsVoidOp())) { bool IsRegOp = this->GetConstLeftOperand()->IsRegOp(); bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix); STARSOpndTypePtr LeftOp = CloneIfNecessary(this->GetConstLeftOperand(), UseFP); if (MDIsDirectStackAccessOpnd(LeftOp, UseFP)) { this->GetParentInst()->MDGetUnnormalizedOp(LeftOp); } bool InArgOp = false; if (IsRegOp) { STARS_regnum_t RegNum = LeftOp->GetReg(); InArgOp = global_STARS_program->IsArgumentReg(RegNum); } bool ArgSuffix = ProcessingLoop && InArgOp && (!NoLHSArgs && HasLoopArgs) && (STARS_BADADDR != this->GetLeftPreLoopDefAddr()); this->GetParentInst()->PrintSPARKAdaOperand(LeftOp, OutputFile, false, UseFP, !ArgSuffix, OmitTrailingSpace, UseSavedStackPtr); if (ArgSuffix) { // LiveIn to loop, traced back to InArg std::ostringstream AddrString; AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr(); SMP_fprintf(OutputFile, "_%s", AddrString.str().c_str()); } else { if (OldSuffix && IsRegOp) { SMP_fprintf(OutputFile, "'Old"); } } } if (SMP_ASSIGN != CurrOperator) { if (PrefixProcCall) { // need comma in middle to separate parameters SMP_fprintf(OutputFile, ", "); } else if (!UnaryPrefix) { // operator comes in middle SMP_fprintf(OutputFile, "%s", OperatorString.c_str()); if (IsRelational && OffByOne) { // Instead of printing x < y, we will print x < (y + 1) SMP_fprintf(OutputFile, "("); } } // then the right operand or subtree if (this->HasRightSubTree()) { SMP_fprintf(OutputFile, "("); this->GetRightTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, false); SMP_fprintf(OutputFile, ")"); } else if ((nullptr != this->GetConstRightOperand()) && (!this->GetConstRightOperand()->IsVoidOp())) { bool IsRegOp = this->GetConstRightOperand()->IsRegOp(); bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix); STARSOpndTypePtr RightOp = CloneIfNecessary(this->GetConstRightOperand(), UseFP); if (MDIsDirectStackAccessOpnd(RightOp, UseFP)) { this->GetParentInst()->MDGetUnnormalizedOp(RightOp); } this->GetParentInst()->PrintSPARKAdaOperand(RightOp, OutputFile, false, UseFP, !(ProcessingLoop && HasLoopArgs), OmitTrailingSpace, UseSavedStackPtr); if (ProcessingLoop && IsRegOp && HasLoopArgs && (STARS_BADADDR != this->GetRightPreLoopDefAddr())) { // LiveIn to loop, traced back to InArg std::ostringstream AddrString; AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr(); SMP_fprintf(OutputFile, "_%s", AddrString.str().c_str()); } else { if (OldSuffix && IsRegOp) { SMP_fprintf(OutputFile, "'Old"); } } } if (PrefixProcCall || IsSymbolicReadMem) { // operator comes first, as a procedure call; close parenthesis SMP_fprintf(OutputFile, ")"); } else if (IsRelational && OffByOne) { // Instead of printing x < y, we will print x < (y + 1) SMP_fprintf(OutputFile, " + 1)"); } } // end if (SMP_ASSIGN != operator) #endif return; } // end of STARSExpression::EmitSPARKAda() // Emit SPARK Ada translation of expression to OutString, perhaps with Reg'Old suffix. void STARSExpression::EmitSPARKAdaString(std::string &OutString, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs, bool UseSavedStackPtr, bool NoLHSArgs) const { bool UseFP = this->GetParentFunc()->UsesFramePointer(); bool PrefixProcCall = false; bool UnaryPrefix = false; string OperatorString; SMPoperator CurrOperator = this->GetOperator(); bool IsRelational = IsRelationalOperator(CurrOperator); bool IsSymbolicReadMem = (SMP_SYMBOLIC_READ_MEMORY == CurrOperator); bool ConstFollows = (!this->HasRightSubTree() && (SMP_ASSIGN != CurrOperator) && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp()); // If we can convert the OffByOne+IsRelational case from > to >=, or from < to <=, then we can avoid adding one to the limit. if (IsRelational && OffByOne) { if (CurrOperator == SMP_GREATER_THAN) { CurrOperator = SMP_GREATER_EQUAL; OffByOne = false; // no more adjustment needed } else if (CurrOperator == SMP_LESS_THAN) { CurrOperator = SMP_LESS_EQUAL; OffByOne = false; // no more adjustment needed } else if (CurrOperator == SMP_ABOVE) { CurrOperator = SMP_ABOVE_EQUAL; OffByOne = false; // no more adjustment needed } else if (CurrOperator == SMP_BELOW) { CurrOperator = SMP_BELOW_EQUAL; OffByOne = false; // no more adjustment needed } } if (SMP_ASSIGN != CurrOperator) { PrintSPARKAdaOperator(CurrOperator, OperatorString, PrefixProcCall, UnaryPrefix, ConstFollows); if (PrefixProcCall) { // operator comes first, as a procedure call OutString.append(OperatorString); OutString.append("("); } else if (UnaryPrefix) { // operator comes first OutString.append(OperatorString); if (IsSymbolicReadMem) OutString.append("("); } } // Left operand or subtree if (this->HasLeftSubTree()) { OutString.append("("); this->GetLeftTree()->EmitSPARKAdaString(OutString, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, NoLHSArgs); OutString.append(")"); } else if ((nullptr != this->GetConstLeftOperand()) && (!this->GetConstLeftOperand()->IsVoidOp())) { bool IsRegOp = this->GetConstLeftOperand()->IsRegOp(); bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix); STARSOpndTypePtr LeftOp = CloneIfNecessary(this->GetConstLeftOperand(), UseFP); if (MDIsDirectStackAccessOpnd(LeftOp, UseFP)) { this->GetParentInst()->MDGetUnnormalizedOp(LeftOp); } bool InArgOp = false; if (IsRegOp) { STARS_regnum_t RegNum = LeftOp->GetReg(); InArgOp = global_STARS_program->IsArgumentReg(RegNum); } bool ArgSuffix = ProcessingLoop && InArgOp && (!NoLHSArgs && HasLoopArgs) && (STARS_BADADDR != this->GetLeftPreLoopDefAddr()); this->GetParentInst()->SPARKAdaOperandToString(LeftOp, OutString, false, UseFP, !ArgSuffix, OmitTrailingSpace, UseSavedStackPtr); if (ArgSuffix) { // LiveIn to loop, traced back to InArg std::ostringstream AddrString; AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr(); OutString.append("_"); OutString.append(AddrString.str().c_str()); } else { if (OldSuffix && IsRegOp) { OutString.append("'Old"); } } } if (SMP_ASSIGN != CurrOperator) { if (PrefixProcCall) { // need comma in middle to separate parameters OutString.append(", "); } else if (!UnaryPrefix) { // operator comes in middle OutString.append(OperatorString.c_str()); if (IsRelational && OffByOne) { // Instead of printing x < y, we will print x < (y + 1) OutString.append("("); } } // then the right operand or subtree if (this->HasRightSubTree()) { OutString.append("("); this->GetRightTree()->EmitSPARKAdaString(OutString, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr, false); OutString.append(")"); } else if ((nullptr != this->GetConstRightOperand()) && (!this->GetConstRightOperand()->IsVoidOp())) { bool IsRegOp = this->GetConstRightOperand()->IsRegOp(); bool OmitTrailingSpace = IsRegOp && (ProcessingLoop || OldSuffix); STARSOpndTypePtr RightOp = CloneIfNecessary(this->GetConstRightOperand(), UseFP); if (MDIsDirectStackAccessOpnd(RightOp, UseFP)) { this->GetParentInst()->MDGetUnnormalizedOp(RightOp); } bool InArgOp = false; if (IsRegOp) { STARS_regnum_t RegNum = RightOp->GetReg(); InArgOp = global_STARS_program->IsArgumentReg(RegNum); } bool ArgSuffix = ProcessingLoop && InArgOp && HasLoopArgs && (STARS_BADADDR != this->GetRightPreLoopDefAddr()); this->GetParentInst()->SPARKAdaOperandToString(RightOp, OutString, false, UseFP, !ArgSuffix, OmitTrailingSpace, UseSavedStackPtr); if (ArgSuffix) { // LiveIn to loop, traced back to InArg std::ostringstream AddrString; AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr(); OutString.append("_"); OutString.append(AddrString.str().c_str()); } else { if (OldSuffix && IsRegOp) { OutString.append("'Old"); } } } if (PrefixProcCall || IsSymbolicReadMem) { // operator comes first, as a procedure call; close parenthesis OutString.append(")"); } else if (IsRelational && OffByOne) { // Instead of printing x < y, we will print x < (y + 1) OutString.append(" + 1)"); } } // end if (SMP_ASSIGN != operator) return; } // end of STARSExpression::EmitSPARKAdaString() // Emit X86InSafeRegion64(..., X86.RSP) for each byte in memory expr void STARSExpression::EmitSPARKInSafeRegion64(FILE *OutputFile, size_t MemWidth) const { bool UseFP = this->GetParentFunc()->UsesFramePointer(); SMPoperator CurrOperator = this->GetOperator(); string OutString; this->EmitSPARKAdaString(OutString, false, false, false, false, false, false); for (size_t byte = 0; byte < MemWidth; ++byte) { SMP_fprintf(OutputFile, "\n\t\tX86.InSafeRegion64(%s", OutString.c_str()); if (byte > 0) SMP_fprintf(OutputFile, " + %u", byte); if ((byte + 1) < MemWidth) { SMP_fprintf(OutputFile, ", X86.RSP) and"); } else { SMP_fprintf(OutputFile, ", X86.RSP)"); } } return; } // end of STARSExpression::EmitSPARKInSafeRegion64() // create and print vector of strings matching loop-function parameters to their incoming locations void STARSExpression::PrintSPARKArgLocationStrings(FILE *OutputFile, bool LoopInvariant, size_t LoopIndex, size_t &OutputCount, bitset<1 + MD_LAST_REG_NO> &RegsPrinted) { // Walk the expression tree and find non-constant leaves. These must be incoming arguments or basic induction variables (BIVs). // This method should not be called on expressions that were expanded with the StopOnIV option flag, so we will assume that // any non-constant leaf operand is an incoming argument. EXCEPTION: The stack ptr reg is never made into an incoming arg. if (this->HasLeftSubTree()) { this->GetLeftTree()->PrintSPARKArgLocationStrings(OutputFile, LoopInvariant, LoopIndex, OutputCount, RegsPrinted); } else if (nullptr != this->GetConstLeftOperand()) { // leaf operand STARSOpndTypePtr LeafOp = this->GetLeftOperand(); STARS_ea_t PreLoopDefAddr = this->GetLeftPreLoopDefAddr(); if (LeafOp->IsRegOp()) { STARS_regnum_t LeafReg = LeafOp->GetReg(); if (!RegsPrinted[(size_t) LeafReg]) { STARSInductionVarFamilyList::iterator ListIter; size_t FamilyIndex; // Don't print Loop_Invariant assertions about induction variables, basic or derived. if (!(LoopInvariant && this->GetParentFunc()->IsLoopInductionVarForAnySSANum(LoopIndex, LeafOp, ListIter, FamilyIndex))) { this->PrintSPARKArgLocationStringsHelper(OutputFile, LoopInvariant, OutputCount, LeafOp, PreLoopDefAddr); } RegsPrinted.set((size_t) LeafReg); } } } if ((SMP_ASSIGN != this->GetOperator()) && (SMP_SYMBOLIC_READ_MEMORY != this->GetOperator())) { // right hand side is valid if (this->HasRightSubTree()) { this->GetRightTree()->PrintSPARKArgLocationStrings(OutputFile, LoopInvariant, LoopIndex, OutputCount, RegsPrinted); } else if ((nullptr != this->GetConstRightOperand()) && !this->GetConstRightOperand()->IsVoidOp()) { // leaf operand STARSOpndTypePtr LeafOp = this->GetRightOperand(); STARS_ea_t PreLoopDefAddr = this->GetRightPreLoopDefAddr(); if (LeafOp->IsRegOp()) { STARS_regnum_t LeafReg = LeafOp->GetReg(); if (!RegsPrinted[(size_t) LeafReg]) { STARSInductionVarFamilyList::iterator ListIter; size_t FamilyIndex; // Don't print Loop_Invariant assertions about induction variables, basic or derived. if (!(LoopInvariant && this->GetParentFunc()->IsLoopInductionVarForAnySSANum(LoopIndex, LeafOp, ListIter, FamilyIndex))) { this->PrintSPARKArgLocationStringsHelper(OutputFile, LoopInvariant, OutputCount, LeafOp, PreLoopDefAddr); } RegsPrinted.set((size_t)LeafReg); } } } } return; } // end of STARSExpression::PrintSPARKArgLocationStrings() void STARSExpression::PrintSPARKArgLocationStringsHelper(FILE *OutputFile, bool LoopInvariant, size_t &OutputCount, const STARSOpndTypePtr &LeafOp, STARS_ea_t PreLoopDefAddr) { if (!(LeafOp->IsRegOp() && LeafOp->MatchesReg(MD_STACK_POINTER_REG))) { bool UseFP = this->GetParentFunc()->UsesFramePointer(); std::ostringstream AddrString; AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr(); if ((STARS_BADADDR != PreLoopDefAddr) && (!STARS_IsBlockNumPseudoID(PreLoopDefAddr))) { assert(LeafOp->IsRegOp()); STARS_regnum_t RegNo = LeafOp->GetReg(); bool ArgSuffixNeeded = global_STARS_program->IsArgumentReg(RegNo); if (STARS_IsSSAMarkerPseudoID(PreLoopDefAddr)) { // InArg from calling function was unchanged and LiveIn to loop. // We want a string like: "RDI_400586 = X86.RDI" if (LoopInvariant) { PrintSPARKIndentTabs(OutputFile); SMP_fprintf(OutputFile, "pragma Loop_Invariant("); this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true, false); SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str()); this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false, false); SMP_fprintf(OutputFile, ");\n"); } else { if (0 < OutputCount) { SMP_fprintf(OutputFile, " and\n\t("); } else { SMP_fprintf(OutputFile, "("); } this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true); SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str()); this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false); SMP_fprintf(OutputFile, ")"); } ++OutputCount; } else { // A regular instruction is at PreLoopDefAddr // We want a string like: "RDI_400586 = X86.ReadMem64(X86.RBP-8)" SMPInstr *PreLoopInst = this->GetParentFunc()->GetInstFromAddr(PreLoopDefAddr); assert(nullptr != PreLoopInst); STARSOpndTypePtr PreLoopDefOp = PreLoopInst->GetFirstLeftOperandNoNorm(); assert((nullptr != PreLoopDefOp) && (!PreLoopDefOp->IsVoidOp())); if (LoopInvariant) { PrintSPARKIndentTabs(OutputFile); SMP_fprintf(OutputFile, "pragma Loop_Invariant("); this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true); SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str()); this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false); SMP_fprintf(OutputFile, ");\n"); } else { if (0 < OutputCount) { SMP_fprintf(OutputFile, " and\n\t("); } else { SMP_fprintf(OutputFile, "("); } this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true); SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str()); this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false); SMP_fprintf(OutputFile, ")"); } ++OutputCount; } } } return; } // end of STARSExpression::PrintSPARKArgLocationStringsHelper() // swap left and right sides void STARSExpression::SwapSides(void) { STARSExpression *LeftTreeTemp = nullptr; if (this->HasLeftSubTree()) { LeftTreeTemp = this->GetLeftTree(); if (this->HasRightSubTree()) { this->SetLeftTree(this->GetRightTree()); this->SetRightTree(LeftTreeTemp); } else { // Right operand only this->SetLeftOperand(this->GetRightOperand()); this->SetLeftUseAddr(this->GetRightUseAddr()); this->SetLeftSSANum(this->GetRightSSANum()); this->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr()); this->SetRightTree(LeftTreeTemp); this->SetLeftTree(nullptr); } } else { // Left operand only STARSOpndTypePtr LeftOpTemp = this->GetLeftOperand(); int LeftOpSSATemp = this->GetLeftSSANum(); STARS_ea_t LeftOpAddrTemp = this->GetLeftPreLoopDefAddr(); STARS_ea_t LeftUseAddrTemp = this->GetLeftUseAddr(); if (this->HasRightSubTree()) { this->SetLeftTree(this->GetRightTree()); this->SetRightTree(nullptr); this->SetRightOperand(LeftOpTemp); this->SetRightUseAddr(LeftUseAddrTemp); this->SetRightSSANum(LeftOpSSATemp); this->SetRightPreLoopDefAddr(LeftOpAddrTemp); this->SetLeftOperand(nullptr); } else { // Right operand only this->SetLeftOperand(this->GetRightOperand()); this->SetLeftUseAddr(this->GetRightUseAddr()); this->SetLeftSSANum(this->GetRightSSANum()); this->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr()); this->SetRightOperand(LeftOpTemp); this->SetRightUseAddr(LeftUseAddrTemp); this->SetRightSSANum(LeftOpSSATemp); this->SetRightPreLoopDefAddr(LeftOpAddrTemp); } } return; } // end of STARSExpression::SwapSides() // Search OriginalParentInst for MemOp and return its byte width uint16_t STARSExpression::FindOrigMemOpByteWidth(void) const { uint16_t MemOpByteWidth = 0; STARSOpndTypePtr MemOp = this->GetOriginalParentInst()->GetMemDef(); if ((nullptr == MemOp) || (!MemOp->IsMemOp())) { MemOp = this->GetOriginalParentInst()->GetMemUse(); } if ((nullptr != MemOp) && MemOp->IsMemOp()) { MemOpByteWidth = MemOp->GetByteWidth(); } return MemOpByteWidth; } // end of STARSExpression::FindOrigMemOpByteWidth() // Substitute SCCP constants for operands void STARSExpression::EvaluateConsts(void) { STARS_ea_t ConstDefAddr; if (this->HasLeftSubTree()) { // Recurse into LeftExpr this->GetLeftTree()->EvaluateConsts(); } else { // Search for SCCP constant for LeftOperand. STARSOpndTypePtr LeftOp = this->GetLeftOperand(); if ((nullptr != LeftOp) && LeftOp->IsRegOp()) { STARS_uval_t LeftConstValue; bool FoundConst = this->FindConstForOperand(true, LeftConstValue, ConstDefAddr); if (FoundConst) { // Replace LeftOperand with an immediate operand. STARSOpndTypePtr NewLeftOp = this->GetParentInst()->MakeImmediateOpnd(LeftConstValue); this->SetLeftOperand(NewLeftOp); // SSANum is irrelevant, just reset LeftOperand if (STARS_PSEUDO_ID_MIN > ConstDefAddr) { // real inst addr SMPInstr *ConstDefInst = this->GetParentFunc()->GetInstFromAddr(ConstDefAddr); assert(nullptr != ConstDefInst); this->SetParentInst(ConstDefInst); } } } } if ((SMP_ASSIGN == this->GetOperator()) || (SMP_SYMBOLIC_READ_MEMORY == this->GetOperator())) { // Only the left hand side exists. Nothing more to do. return; } if (nullptr != this->GetRightTree()) { // Recurse into RightExpr this->GetRightTree()->EvaluateConsts(); } else { // Search for SCCP constant for RightOperand. STARSOpndTypePtr RightOp = this->GetRightOperand(); if ((nullptr != RightOp) && RightOp->IsRegOp()) { STARS_uval_t RightConstValue; bool FoundConst = this->FindConstForOperand(false, RightConstValue, ConstDefAddr); if (FoundConst) { // Replace RightOperand with an immediate operand. STARSOpndTypePtr NewRightOp = this->GetParentInst()->MakeImmediateOpnd(RightConstValue); this->SetRightOperand(NewRightOp); // SSANum is irrelevant, just reset RightOperand if (STARS_PSEUDO_ID_MIN > ConstDefAddr) { // real inst addr SMPInstr *ConstDefInst = this->GetParentFunc()->GetInstFromAddr(ConstDefAddr); assert(nullptr != ConstDefInst); this->SetParentInst(ConstDefInst); } } } } return; } // end of STARSExpression::EvaluateConsts() // search for SCCP constant value for LeftOperand or RightOperand bool STARSExpression::FindConstForOperand(bool Left, STARS_uval_t &ConstValue, STARS_ea_t &ConstDefAddr) { STARSOpndTypePtr SearchOp = (Left) ? CloneIfSubwordReg(this->GetConstLeftOperand()) : CloneIfSubwordReg(this->GetConstRightOperand()); CanonicalizeOpnd(SearchOp); int SSANum = (Left) ? this->GetLeftSSANum() : this->GetRightSSANum(); SMPBasicBlock *CurrBlock = this->GetParentInst()->GetBlock(); int HashValue = HashGlobalNameAndSSA(SearchOp, SSANum); bool LocalName = CurrBlock->IsLocalName(SearchOp); STARSSCCPMapIter ConstIter; bool FoundConst = CurrBlock->GetFunc()->FindSCCPConstIter(CurrBlock, HashValue, LocalName, ConstIter); if (FoundConst) { ConstValue = ConstIter->second.ConstValue; if (LocalName) { // Can't const DEF be global prior to block even if HashValue op is inside the block? ConstDefAddr = CurrBlock->GetLocalDefAddrForRegHash(HashValue); } else { ConstDefAddr = CurrBlock->GetFunc()->GetGlobalDefAddrForRegHash(HashValue); } } return FoundConst; } // end of STARSExpression::FindConstForOperand() // Widen register operands that are narrower than ByteWidth bool STARSExpression::WidenRegOperands(std::size_t ByteWidth) { bool Widened = false; if (this->HasLeftSubTree()) { Widened = this->GetLeftTree()->WidenRegOperands(ByteWidth); // recurse } else if (nullptr != this->GetConstLeftOperand()) { if (this->GetConstLeftOperand()->IsRegOp() && (ByteWidth > this->GetConstLeftOperand()->GetByteWidth())) { STARSOpndTypePtr NewLeftOp = this->GetParentInst()->MakeRegOpnd(this->GetConstLeftOperand()->GetReg()); NewLeftOp->SetByteWidth((uint16_t)global_STARS_program->GetSTARS_ISA_Bytewidth()); this->SetLeftOperand(NewLeftOp); Widened = true; } else if (this->GetConstLeftOperand()->IsImmedOp() && ((SMP_ZERO_EXTEND == this->GetOperator()) || (SMP_SIGN_EXTEND == this->GetOperator()))) { // Replace extension operator with simple assignment for immediate operands. this->SetOperator(SMP_ASSIGN); Widened = true; } } if (this->HasRightSubTree()) { Widened = (this->GetRightTree()->WidenRegOperands(ByteWidth) || Widened); // recurse } else if (nullptr != this->GetConstRightOperand()) { if (this->GetConstRightOperand()->IsRegOp() && (ByteWidth > this->GetConstRightOperand()->GetByteWidth())) { STARSOpndTypePtr NewRightOp = this->GetParentInst()->MakeRegOpnd(this->GetConstRightOperand()->GetReg()); NewRightOp->SetByteWidth((uint16_t) global_STARS_program->GetSTARS_ISA_Bytewidth()); this->SetRightOperand(NewRightOp); Widened = true; } } return Widened; } // end of STARSExpression::WidenOperands() // Lots of compiler-generated x86-64 code has needless sign-extend or zero-extend opcodes because // quick arithmetic is performed on 32-bit regs and the compiler extends it later before using the 64-bit reg. // Expressions get hard to analyze; the prover can balk as a double-check on unsound simplifications, but // get rid of these extensions for our purposes so we can produce simple exprs. #define STARS_SPARK_DISCARD_BIT_EXTENSIONS 1 // Remove sign-extension and zero-extension operators after widening bool STARSExpression::SimplifyExtensions(STARSExpression *ParentExpr) { bool Simplified = false; if (this->HasLeftSubTree()) Simplified = this->GetLeftTree()->SimplifyExtensions(this); if (this->HasRightSubTree()) Simplified = (this->GetRightTree()->SimplifyExtensions(this) || Simplified); #if STARS_SPARK_DISCARD_BIT_EXTENSIONS if (SMP_ZERO_EXTEND == this->GetOperator() || (SMP_SIGN_EXTEND == this->GetOperator())) { Simplified = (this->ElevateLeftSide(ParentExpr) || Simplified); // eliminate the extension operator } #else if (SMP_ZERO_EXTEND == this->GetOperator() && (nullptr != this->GetConstLeftOperand()) && (!this->HasLeftSubTree())) { // See if we are zero-extending a constant, and transform to just assigning the constant. if (this->GetConstLeftOperand()->IsImmedOp()) { Simplified = this->ElevateLeftSide(ParentExpr); // eliminate the extension operator assert(Simplified); // now fall through to further simplifications } } #endif return Simplified; } // end of STARSExpression::SimplifyExtensions() // Remove SMP_ASSIGN operators below the root level bool STARSExpression::SimplifyAssigns(STARSExpression *ParentExpr) { bool Simplified = false; // Depth-first tree traversal via recursion. if (this->HasLeftSubTree()) Simplified = this->GetLeftTree()->SimplifyAssigns(this); if (this->HasRightSubTree()) Simplified = (this->GetRightTree()->SimplifyAssigns(this) || Simplified); if ((nullptr != ParentExpr) && (SMP_ASSIGN == this->GetOperator())) { bool LeftOperandLifted = this->ElevateLeftSide(ParentExpr); Simplified = true; this->SetLeftTree(nullptr); // Nothing left of this expression this->SetRightTree(nullptr); } return Simplified; } // end of STARSExpression::SimplifyAssigns() // Call WidenRegOperands, SimplifyExtensions, and SimplifyExpr bool STARSExpression::SimplifyDriver(void) { bool AssignsRemoved = this->SimplifyAssigns(nullptr); // Widen the register operands in the expr. bool Widened = this->WidenRegOperands(global_STARS_program->GetSTARS_ISA_Bytewidth()); bool ExtSimplified = this->SimplifyExtensions(nullptr); bool Simplified = this->SimplifyExpr(nullptr); return (AssignsRemoved || Widened || ExtSimplified || Simplified); } // end of STARSExpression::SimplifyDriver() // Simplify operations with operands of zero or one, etc. Return true if expr was raised to parent. bool STARSExpression::SimplifyExpr(STARSExpression *ParentExpr) { bool RootLeftExprLifted = false; if (SMP_SYMBOLIC_READ_MEMORY == this->GetOperator()) { // Nothing to do besides recurse into the memory address. if (this->HasLeftSubTree()) return this->GetLeftTree()->SimplifyExpr(this); else return false; // no changes made } if (this->HasLeftSubTree()) { bool LeftExprLifted = this->GetLeftTree()->SimplifyExpr(this); if (LeftExprLifted && (nullptr != this->GetConstLeftOperand()) && (!this->HasLeftSubTree())) { // nothing remains of left tree.; FALSE if internal SMP_ASSIGN was lifted if (nullptr != this->GetLeftTree()) { delete this->GetLeftTree(); this->SetLeftTree(nullptr); } } } if (this->HasRightSubTree()) { bool RightExprLifted = this->GetRightTree()->SimplifyExpr(this); if (RightExprLifted && (!this->HasRightSubTree())) { // nothing remains of left tree.; FALSE if internal SMP_ASSIGN was lifted if (nullptr != this->GetRightTree()) { delete this->GetRightTree(); this->SetRightTree(nullptr); } } } bool LeftNullTree = (!this->HasLeftSubTree()); bool RightNullTree = (!this->HasRightSubTree()); bool RightOperandLifted = false; // was RightOperand lifted up into ParentExpr? bool LeftOperandLifted = false; // was LeftOperand lifted up into ParentExpr? bool NegativeAddendSimplified = false; // Left + (-k) became Left - k // A left or right tree might be merely an operand after recursive simplification, so test from scratch. if (LeftNullTree || RightNullTree) { bool ConstLeftOperand = (LeftNullTree && (nullptr != this->GetConstLeftOperand()) && this->GetConstLeftOperand()->IsImmedOp()); bool ConstRightOperand = (RightNullTree && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp()); bool TwoConstOperands = (ConstLeftOperand && ConstRightOperand); bool NegativeRightOperand = ConstRightOperand && (((STARS_sval_t) this->GetConstRightOperand()->GetImmedValue()) < 0); // Simplify (Left + (-k)) to be (Left - k) if (NegativeRightOperand && (SMP_ADD == this->GetOperator())) { STARS_sval_t NewImmedVal = 0 - ((STARS_sval_t) this->GetConstRightOperand()->GetImmedValue()); if (0 < NewImmedVal) { // if not signedness error involving MIN_INT STARSOpndTypePtr NewImmedOp = this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t)NewImmedVal); this->SetRightOperand(NewImmedOp); this->SetOperator(SMP_SUBTRACT); NegativeAddendSimplified = true; } } // Handle the case of arithmetic on two constant operands. if (TwoConstOperands) { SMPoperator CurrOperator = this->GetOperator(); STARS_uval_t LeftValue = this->GetConstLeftOperand()->GetImmedValue(); STARS_uval_t RightValue = this->GetConstRightOperand()->GetImmedValue(); bool Simplified = true; STARS_uval_t FinalValue; if (SMP_ADD == CurrOperator) { FinalValue = LeftValue + RightValue; } else if (SMP_SUBTRACT == CurrOperator) { FinalValue = LeftValue - RightValue; } else if ((SMP_U_MULTIPLY == CurrOperator) || (SMP_S_MULTIPLY == CurrOperator)) { FinalValue = LeftValue * RightValue; } else if ((SMP_U_DIVIDE == CurrOperator) || (SMP_S_DIVIDE == CurrOperator)) { if (RightValue == 0) { SMP_msg("SERIOUS WARNING: Divide by zero avoided in SimplifyExpr for expr:\n"); this->Dump(0); this->GetParentFunc()->Dump(); Simplified = false; } else { FinalValue = LeftValue / RightValue; } } else if ((SMP_U_LEFT_SHIFT == CurrOperator) || (SMP_S_LEFT_SHIFT == CurrOperator)) { FinalValue = LeftValue << RightValue; } else if ((SMP_U_RIGHT_SHIFT == CurrOperator) || (SMP_S_RIGHT_SHIFT == CurrOperator)) { FinalValue = LeftValue >> RightValue; } else if (SMP_BITWISE_AND == CurrOperator) { FinalValue = LeftValue & RightValue; } else if (SMP_BITWISE_OR == CurrOperator) { FinalValue = LeftValue | RightValue; } else if (SMP_BITWISE_XOR == CurrOperator) { FinalValue = LeftValue ^ RightValue; } else { Simplified = false; } if (Simplified) { STARSOpndTypePtr FinalOp = this->GetParentInst()->MakeImmediateOpnd(FinalValue); if (nullptr == ParentExpr) { // This is the highest level expr. this->SetOperator(SMP_ASSIGN); this->SetLeftOperand(FinalOp); } else { // Are we the left tree of the ParentExpr? if (this == ParentExpr->GetLeftTree()) { ParentExpr->SetLeftOperand(FinalOp); ParentExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); } else { assert(this == ParentExpr->GetRightTree()); ParentExpr->SetRightOperand(FinalOp); ParentExpr->SetRightPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); } } return true; // Nothing more can be done at this level of the expr. } } if (LeftNullTree) { if (ConstLeftOperand) { STARS_uval_t LeftValue = this->GetConstLeftOperand()->GetImmedValue(); SMPoperator CurrOperator = this->GetOperator(); // Simplify multiplication by 0 or 1, division by 1, addition or subtraction of 0. if (1 == LeftValue) { if ((SMP_U_MULTIPLY == CurrOperator) || (SMP_S_MULTIPLY == CurrOperator)) { // Multiply by 1, produces right tree as result. // We can simplify the current expr by making it just be the RightTree or RightOperand. RightOperandLifted = this->ElevateRightSide(ParentExpr); } } else if (0 == LeftValue) { if ((SMP_U_MULTIPLY <= CurrOperator) && (SMP_S_DIVIDE >= CurrOperator)) { // Multiply by 0, or 0 divided by something, produces zero as result. // We can simplify the current expr by making it just be the LeftOperand, zero. LeftOperandLifted = this->ElevateLeftSide(ParentExpr); assert(LeftOperandLifted || (SMP_ASSIGN == this->GetOperator())); // not lifted => we assign zero instead of mul/div LeftNullTree = (!this->HasLeftSubTree()); // Delete the right tree if it exists. ConstRightOperand = false; if (nullptr != this->GetRightTree()) { delete this->GetRightTree(); this->SetRightTree(nullptr); } return true; } else if (SMP_ADD == CurrOperator) { // Addition of 0, produces right tree as result. // We can simplify the current expr by making it just be the RightTree or RightOperand. RightOperandLifted = this->ElevateRightSide(ParentExpr); } } } } if (!RightOperandLifted && RightNullTree && !LeftOperandLifted) { if (ConstRightOperand) { STARS_uval_t RightValue = this->GetConstRightOperand()->GetImmedValue(); SMPoperator CurrOperator = this->GetOperator(); // Simplify multiplication by 0 or 1, division by 1, addition or subtraction of 0, // and transform shifts into multiplies or divides. if (0 == RightValue) { if ((SMP_U_MULTIPLY == CurrOperator) && (SMP_S_MULTIPLY == CurrOperator)) { // Multiply by 0, produces zero as result. // We can simplify the current expr by making it just be the RightOperand, zero. RightOperandLifted = this->ElevateRightSide(ParentExpr); } else if ((SMP_ADD == CurrOperator) || (SMP_SUBTRACT == CurrOperator)) { // Addition or subtraction of 0, produces left tree as result. // We can simplify the current expr by making it just be the LeftTree or LeftOperand. LeftOperandLifted = this->ElevateLeftSide(ParentExpr); LeftNullTree = (!this->HasLeftSubTree()); } else if ((SMP_U_DIVIDE == CurrOperator) || (SMP_S_DIVIDE == CurrOperator)) { // Divide by 0. Emit error message. SMP_msg("ERROR: Divide by zero after constant propagation at %llx\n", (uint64_t) this->GetParentInst()->GetAddr()); } } else if ((SMP_U_LEFT_SHIFT <= CurrOperator) && (SMP_S_RIGHT_SHIFT >= CurrOperator)) { // Convert constant shift counts into multiply or divide operations. if (RightValue < (8 * sizeof(STARS_uval_t))) { // don't overflow int ShiftCount = (int) RightValue; RightValue = 1; while (ShiftCount > 16) { // C/C++ limit on shifting RightValue = (RightValue << 16); ShiftCount -= 16; } RightValue = (RightValue << ShiftCount); if (SMP_U_LEFT_SHIFT == CurrOperator) CurrOperator = SMP_U_MULTIPLY; else if (SMP_S_LEFT_SHIFT == CurrOperator) CurrOperator = SMP_S_MULTIPLY; else if (SMP_U_RIGHT_SHIFT == CurrOperator) CurrOperator = SMP_U_DIVIDE; else { assert(SMP_S_RIGHT_SHIFT == CurrOperator); CurrOperator = SMP_S_DIVIDE; } STARSOpndTypePtr NewRightOperand = this->GetParentInst()->MakeImmediateOpnd(RightValue); this->SetRightOperand(NewRightOperand); this->SetOperator(CurrOperator); } } else if (1 == RightValue) { if ((SMP_U_MULTIPLY <= CurrOperator) && (SMP_S_DIVIDE >= CurrOperator)) { // Multiply or divide by 1, produces left tree as result. // We can simplify the current expr by making it just be the RightTree or RightOperand. LeftOperandLifted = this->ElevateLeftSide(ParentExpr); LeftNullTree = (!this->HasLeftSubTree()); } } // Handle the multiply by stride and then divide by stride, or vice versa, that are common // in loop iteration count and memory range analyses, e.g. (x / 8) * 8. if (!LeftNullTree && (RightValue > 1) && ((SMP_U_MULTIPLY <= CurrOperator) && (SMP_S_DIVIDE >= CurrOperator))) { SMPoperator LeftOperator = this->GetLeftTree()->GetOperator(); if ((SMP_U_MULTIPLY <= LeftOperator) && (SMP_S_DIVIDE >= LeftOperator)) { STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetConstRightOperand(); if ((nullptr != LeftRightOp) && (!this->GetLeftTree()->HasRightSubTree()) && LeftRightOp->IsImmedOp()) { // We have (x oper1 const1) oper2 const2 where oper1 and oper2 are multiply or divide. STARS_uval_t LeftRightValue = LeftRightOp->GetImmedValue(); if (LeftRightValue == RightValue) { // We have (x oper1 const1) oper2 const1 (same consts) where oper1 and oper2 are multiply or divide. bool LeftMultiply = ((SMP_U_MULTIPLY == LeftOperator) || (SMP_S_MULTIPLY == LeftOperator)); bool RightMultiply = ((SMP_U_MULTIPLY == CurrOperator) || (SMP_S_MULTIPLY == CurrOperator)); if (LeftMultiply != RightMultiply) { // Inverse operations on equal constants. if (this->GetLeftTree()->HasLeftSubTree()) { // We need to elevate the left child of the left child to our parent location (two levels up). // See drawing and comment for left operand case. LeftOperandLifted = this->GetLeftTree()->ElevateLeftSide(this); // assert(LeftOperandLifted); // Could lift a tree, not an operand LeftOperandLifted = this->ElevateLeftSide(ParentExpr); // assert(LeftOperandLifted); // Could lift a tree, not an operand LeftNullTree = (!this->HasLeftSubTree()); } else { // We need to elevate the left operand of the left child to our parent location (two levels up). // We have something like: // MULTIPLY // | // +---+----+ // | | // DIV 8 // | // +----+ // | | // Reg 8 // // We want to elevate Reg to replace the entire Expr that "this" points to. // This can be done with two consecutive ElevateLeftSide calls, the first of which // replaces (Reg DIV 8) by Reg, and the second of which replaces (Reg * 8) with Reg. LeftOperandLifted = this->GetLeftTree()->ElevateLeftSide(this); // assert(LeftOperandLifted); // Could lift a tree, not an operand LeftOperandLifted = this->ElevateLeftSide(ParentExpr); // assert(LeftOperandLifted); // Could lift a tree, not an operand LeftNullTree = true; // NOTE: Need to destroy subtrees in Elevate methods to avoid leaks. } } } } } } // end of multiply/divide pairs simplification // Handle cascading additions and subtractions if (!LeftNullTree && ((SMP_SUBTRACT == CurrOperator) || (SMP_ADD == CurrOperator))) { SMPoperator LeftOperator = this->GetLeftTree()->GetOperator(); if ((SMP_ADD == LeftOperator) || (SMP_SUBTRACT == LeftOperator)) { STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetConstRightOperand(); if ((nullptr != LeftRightOp) && (!this->GetLeftTree()->HasRightSubTree()) && LeftRightOp->IsImmedOp()) { // We have (x oper1 const1) oper2 const2 where oper1 and oper2 are add or subtract. STARS_uval_t LeftRightValue = LeftRightOp->GetImmedValue(); STARS_uval_t SumValue = 0; if (SMP_ADD == LeftOperator) { SumValue = LeftRightValue; } else { // SMP_SUBTRACT SumValue -= LeftRightValue; } if (SMP_ADD == CurrOperator) { SumValue += RightValue; } else { // SMP_SUBTRACT SumValue -= RightValue; } STARS_sval_t SignedSumValue = (STARS_sval_t)SumValue; if (SignedSumValue < 0) { // Negative result. Make CurrOperator SMP_SUBTRACT of a positive value. SignedSumValue = (0 - SignedSumValue); this->SetOperator(SMP_SUBTRACT); } else { // Positive result. Make CurrOperator SMP_ADD of the positive value. this->SetOperator(SMP_ADD); } this->SetLeftUseAddr(this->GetLeftTree()->GetLeftUseAddr()); this->SetLeftSSANum(this->GetLeftTree()->GetLeftSSANum()); if (this->GetLeftTree()->HasLeftSubTree()) { LeftOperandLifted = this->GetLeftTree()->ElevateLeftSide(this); } else { this->SetLeftOperand(this->GetLeftTree()->GetConstLeftOperand()); LeftNullTree = true; } SumValue = (STARS_uval_t)SignedSumValue; this->SetRightOperand(this->GetParentInst()->MakeImmediateOpnd(SumValue)); } } } // end of cascading additions and subtractions } } } // end if (LeftNullTree || RightNullTree) else { // Look for the special case of simplifying address ranges, e.g. if we loop from // RDI + 4 up to RDI + 128, then the iteration count expr will be ((RDI + 128) - (RDI + 4)). // The address register drops out of the expr and the final answer is 124. if (SMP_SUBTRACT == this->GetOperator() && (!this->GetLeftTree()->HasRightSubTree()) && (!this->GetRightTree()->HasRightSubTree())) { // Check for the LeftTree and RightTree having the same LeftOperand register. bool LeftTreeHasLeftOperand = (!(this->GetLeftTree()->HasLeftSubTree())); bool RightTreeHasLeftOperand = (!(this->GetRightTree()->HasLeftSubTree())); bool HasLeftRegOps = (LeftTreeHasLeftOperand && this->GetLeftTree()->GetConstLeftOperand()->IsRegOp()) && (RightTreeHasLeftOperand && this->GetRightTree()->GetConstLeftOperand()->IsRegOp()); if (HasLeftRegOps) { STARS_regnum_t LeftReg = this->GetLeftTree()->GetConstLeftOperand()->GetReg(); STARS_regnum_t RightReg = this->GetRightTree()->GetConstLeftOperand()->GetReg(); if (LeftReg == RightReg) { // The registers will drop out of the expression. // We have ((Reg op RightOp1) - (Reg op RightOp2)) // What to do next depends on the operators and whether we have immediate RightOps SMPoperator LeftOperator = this->GetLeftTree()->GetOperator(); SMPoperator RightOperator = this->GetRightTree()->GetOperator(); if (SMP_ADD == LeftOperator) { // We need RightOp1 - RightOp2 if RightOperator is addition, // and RightOp1 + RightOp2 if RightOperator is subtraction. if ((SMP_ADD == RightOperator) || (SMP_SUBTRACT == RightOperator)) { // Make the LeftTree->RightOperand into the new left tree, // and the RightTree->RightOperand into the new right tree, // leaving SMP_SUBTRACT as the parent operator. LeftOperandLifted = this->GetLeftTree()->ElevateRightSide(this); RightOperandLifted = this->GetRightTree()->ElevateRightSide(this); assert(LeftOperandLifted && RightOperandLifted); if (SMP_SUBTRACT == RightOperator) { // We simplified ((Reg + RightOp1) - (Reg - RightOp2)) // so the answer is (RightOp1 + RightOp2). Change parent operator // to SMP_ADD. this->SetOperator(SMP_ADD); } } } else if (SMP_SUBTRACT == LeftOperator) { // We need (-RightOp1) - RightOp2 if RightOperator is addition, // and RightOp2 - RightOp1 if RightOperator is subtraction. // We will only deal with the negation case if we have a constant RightOp1. if (SMP_SUBTRACT == RightOperator) { // Make the LeftTree->RightOperand into the new right operand, // and the RightTree->RightOperand into the new left operand, // leaving SMP_SUBTRACT as the parent operator. STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetConstRightOperand()->clone(); STARSOpndTypePtr RightRightOp = this->GetRightTree()->GetConstRightOperand()->clone(); this->SetLeftOperand(RightRightOp); this->SetLeftUseAddr(this->GetRightTree()->GetRightUseAddr()); this->SetRightOperand(LeftRightOp); this->SetRightUseAddr(this->GetLeftTree()->GetRightUseAddr()); LeftOperandLifted = RightOperandLifted = true; } else if ((SMP_ADD == RightOperator) && this->GetLeftTree()->GetConstRightOperand()->IsImmedOp()) { // Take ((Reg - immed) - (Reg + operand)) and produce (-immed - operand) by negating the // left immediate value, substituting it for the left tree, and raising the right tree's // right operand and leaving the parent operator as SMP_SUBTRACT. STARS_uval_t LeftRightValue = this->GetLeftTree()->GetConstRightOperand()->GetImmedValue(); LeftRightValue = (0 - LeftRightValue); // negate RightOp1 STARSOpndTypePtr NewLeftOp = this->GetLeftTree()->GetParentInst()->MakeImmediateOpnd(LeftRightValue); STARS_ea_t NewLeftUseAddr = this->GetLeftTree()->GetParentInst()->GetAddr(); RightOperandLifted = this->GetRightTree()->ElevateRightSide(this); assert(RightOperandLifted); this->SetLeftOperand(NewLeftOp); this->SetLeftUseAddr(NewLeftUseAddr); LeftOperandLifted = true; } } } } if (LeftOperandLifted || RightOperandLifted) { // See if our simplifications left us with constants. if (!this->HasLeftSubTree() && (!this->HasRightSubTree())) { if (this->GetConstLeftOperand()->IsImmedOp() && this->GetConstRightOperand()->IsImmedOp()) { bool success = this->SimplifyExpr(ParentExpr); assert(success); } } } } } if (SMP_ASSIGN == this->GetOperator()) { if (this->HasLeftSubTree()) { #if 0 // might have copied RightExpr to LeftExpr and have a dead RightExpr assert(!this->HasRightSubTree()); #endif RootLeftExprLifted = this->ElevateLeftSide(nullptr); assert(RootLeftExprLifted); // now fall through to further simplifications RootLeftExprLifted = false; // reset so that we don't delete the new LeftTree as if it has been lifted and discarded } else { // Only the LeftOperand is valid. This is an InitExpr or an Expr that has been reduced to one operand. // If the current expr has a parent expr, then we can elevate our LeftOperand. if (nullptr == ParentExpr) { return false; // nothing to simplify } else { // Are we the left tree of the ParentExpr? if (this == ParentExpr->GetLeftTree()) { // ParentExpr should have our LeftOperand (our only valid operand) as its LeftOperand, no left tree. ParentExpr->SetLeftOperand(this->GetLeftOperand()); ParentExpr->SetLeftUseAddr(this->GetLeftUseAddr()); ParentExpr->SetLeftSSANum(this->GetLeftSSANum()); ParentExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); } else { assert(this == ParentExpr->GetRightTree()); // ParentExpr should have our LeftOperand (our only valid operand) as its RightOperand, no right tree. ParentExpr->SetRightOperand(this->GetLeftOperand()); ParentExpr->SetRightUseAddr(this->GetLeftUseAddr()); ParentExpr->SetRightSSANum(this->GetLeftSSANum()); ParentExpr->SetRightPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); } return true; // No further simplifications to make } } } return (LeftOperandLifted || RightOperandLifted || RootLeftExprLifted || NegativeAddendSimplified); } // end of STARSExpression::SimplifyExpr() // Expr simplifies to RightExpr or RightOperand, so raise it into ParentExpr. bool STARSExpression::ElevateRightSide(STARSExpression *ParentExpr) { bool RightOperandLifted = false; // was RightOperand lifted up into ParentExpr? if (nullptr != ParentExpr) { // Is this the left or right subtree of ParentExpr? if (ParentExpr->HasLeftSubTree() && (this == ParentExpr->GetLeftTree())) { // New LeftTree of ParentExpr is our RightTree, or new LeftOperand of // ParentExpr is our RightOperand. if (this->HasRightSubTree()) { ParentExpr->SetLeftTree(this->GetRightTree()); } else { // we have only a RightOperand ParentExpr->SetLeftOperand(this->GetRightOperand()); ParentExpr->SetLeftUseAddr(this->GetRightUseAddr()); ParentExpr->SetLeftSSANum(this->GetRightSSANum()); ParentExpr->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr()); RightOperandLifted = true; } } else if (ParentExpr->HasRightSubTree() && (this == ParentExpr->GetRightTree())) { // New RightTree of ParentExpr is our RightTree, or new RightOperand of // ParentExpr is our RightOperand. if (this->HasRightSubTree()) { ParentExpr->SetRightTree(this->GetRightTree()); } else { // we have only a RightOperand ParentExpr->SetRightOperand(this->GetRightOperand()); ParentExpr->SetRightUseAddr(this->GetRightUseAddr()); ParentExpr->SetRightSSANum(this->GetRightSSANum()); ParentExpr->SetRightPreLoopDefAddr(this->GetRightPreLoopDefAddr()); RightOperandLifted = true; } } else { assert(false); } } else { // this is the root expression // We no longer have an expression, just an operand. SMP_ASSIGN will mean to use the LeftOperand. if (!this->HasRightSubTree()) { // We no longer have an expression, just an operand. SMP_ASSIGN will mean to use the LeftOperand. this->SetOperator(SMP_ASSIGN); this->SetLeftOperand(this->GetRightOperand()); this->SetLeftUseAddr(this->GetRightUseAddr()); this->SetLeftSSANum(this->GetRightSSANum()); this->SetLeftPreLoopDefAddr(this->GetRightPreLoopDefAddr()); this->SetRightOperand(nullptr); } else { // Copy our RightSubTree into *this. STARSExpression *RightHandSide = this->GetRightTree(); assert(nullptr != RightHandSide); this->SetOperator(RightHandSide->GetOperator()); if (RightHandSide->HasLeftSubTree()) { this->SetLeftTree(RightHandSide->GetLeftTree()); } else { this->SetLeftOperand(RightHandSide->GetLeftOperand()); this->SetLeftUseAddr(RightHandSide->GetLeftUseAddr()); this->SetLeftSSANum(RightHandSide->GetLeftSSANum()); this->SetLeftPreLoopDefAddr(RightHandSide->GetLeftPreLoopDefAddr()); } if (RightHandSide->HasRightSubTree()) { this->SetRightTree(RightHandSide->GetRightTree()); } else { this->SetRightOperand(RightHandSide->GetRightOperand()); this->SetRightUseAddr(RightHandSide->GetRightUseAddr()); this->SetRightSSANum(RightHandSide->GetRightSSANum()); this->SetRightPreLoopDefAddr(RightHandSide->GetRightPreLoopDefAddr()); RightOperandLifted = true; } } } return RightOperandLifted; } // end of STARSExpression::ElevateRightSide() // Expr simplifies to LeftExpr or LeftOperand, so raise it into ParentExpr. bool STARSExpression::ElevateLeftSide(STARSExpression *ParentExpr) { bool LeftOperandLifted = false; // was LeftOperand lifted up into ParentExpr? if (nullptr != ParentExpr) { // Is this the left or right subtree of ParentExpr? if (ParentExpr->HasLeftSubTree() && (this == ParentExpr->GetLeftTree())) { // New LeftTree of ParentExpr is our LeftTree, or new LeftOperand of // ParentExpr is our LeftOperand. if (this->HasLeftSubTree()) { ParentExpr->SetLeftTree(this->GetLeftTree()); } else { // we have only a LeftOperand ParentExpr->SetLeftTree(nullptr); ParentExpr->SetLeftOperand(this->GetLeftOperand()); ParentExpr->SetLeftUseAddr(this->GetLeftUseAddr()); ParentExpr->SetLeftSSANum(this->GetLeftSSANum()); ParentExpr->SetLeftPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); LeftOperandLifted = true; } } else if (ParentExpr->HasRightSubTree() && (this == ParentExpr->GetRightTree())) { // New RightTree of ParentExpr is our LeftTree, or new RightOperand of // ParentExpr is our LeftOperand. if (this->HasLeftSubTree()) { ParentExpr->SetRightTree(this->GetLeftTree()); } else { // we have only a LeftOperand ParentExpr->SetRightTree(nullptr); ParentExpr->SetRightOperand(this->GetLeftOperand()); ParentExpr->SetRightUseAddr(this->GetLeftUseAddr()); ParentExpr->SetRightSSANum(this->GetLeftSSANum()); ParentExpr->SetRightPreLoopDefAddr(this->GetLeftPreLoopDefAddr()); LeftOperandLifted = true; } } else { assert(false); } if (LeftOperandLifted) { ParentExpr->SetParentInst(this->GetParentInst()); } } else { // this is the root expression if (!this->HasLeftSubTree()) { // We no longer have an expression, just an operand. SMP_ASSIGN will mean to use the LeftOperand. this->SetOperator(SMP_ASSIGN); } else { // Copy our LeftSubTree into *this. STARSExpression *LeftHandSide = this->GetLeftTree(); assert(nullptr != LeftHandSide); this->SetOperator(LeftHandSide->GetOperator()); if (LeftHandSide->HasRightSubTree()) { this->SetRightTree(LeftHandSide->GetRightTree()); } else { this->SetRightOperand(LeftHandSide->GetRightOperand()); this->SetRightUseAddr(LeftHandSide->GetRightUseAddr()); this->SetRightSSANum(LeftHandSide->GetRightSSANum()); this->SetRightPreLoopDefAddr(LeftHandSide->GetRightPreLoopDefAddr()); } if (LeftHandSide->HasLeftSubTree()) { this->SetLeftTree(LeftHandSide->GetLeftTree()); } else { this->SetLeftOperand(LeftHandSide->GetLeftOperand()); this->SetLeftUseAddr(LeftHandSide->GetLeftUseAddr()); this->SetLeftSSANum(LeftHandSide->GetLeftSSANum()); this->SetLeftPreLoopDefAddr(LeftHandSide->GetLeftPreLoopDefAddr()); } LeftOperandLifted = true; } } return LeftOperandLifted; } // end of STARSExpression::ElevateLeftSide() // Replace operands with their definitions, which might be sub-expressions // Stop each expansion at incoming arg definition, or // at DEFs of the form name := immediate value. If we must stop before that point, // e.g. at a Phi function or a non-stack memory read (name := memory value), return false. // Otherwise, return true. // Argument "changed" should be initialized to false before the first call to ExpandExpr(), // and it will be left unchanged or set to true but never reset to false. // When the induction var is the LeftOperand, we expand the RightSideOnly. bool STARSExpression::ExpandExpr(STARS_ea_t UseAddr, size_t LoopIndex, bool RightSideOnly, bool StopOnIV, bool StopOnLoopBoundary, bool RecordLoopRegs, bool InitCase, set<int> &LoopRegHashes, bool &StoppedOnIV, bool &changed, set<STARS_ea_t> &StackPtrCopySet, int &DepthCounter) { bool success = true; StoppedOnIV = false; ++DepthCounter; if (STARS_EXPR_CALL_DEPTH_LIMIT < DepthCounter) { success = false; --DepthCounter; SMP_msg("INFO: ExpandExpr() stopped at DepthCounter %d UseAddr %llx\n", DepthCounter, (uint64_t) UseAddr); return success; } if (!RightSideOnly) { if (this->HasLeftSubTree()) { STARS_ea_t CurrUseAddr = this->GetLeftTree()->GetParentInst()->GetAddr(); success = this->GetLeftTree()->ExpandExpr(CurrUseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } else { // Expand LeftOperand. success = this->ExpandOperand(LoopIndex, true, StopOnIV, this->GetLeftUseAddr(), StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } } if (success) { if (this->HasRightSubTree()) { STARS_ea_t CurrUseAddr = this->GetRightTree()->GetParentInst()->GetAddr(); success = this->GetRightTree()->ExpandExpr(CurrUseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } else { // Expand RightOperand. success = this->ExpandOperand(LoopIndex, false, StopOnIV, this->GetRightUseAddr(), StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } } --DepthCounter; return success; } // end of STARSExpression::ExpandExpr() // Expand LeftOperand (if Left == true) or RightOperand into a new subtree using its DEF. // return false if expansion is forced to stop before constant DEF or SSA #0 DEF. bool STARSExpression::ExpandOperand(std::size_t LoopIndex, bool Left, bool StopOnIV, STARS_ea_t UseAddr, bool StopOnLoopBoundary, bool RecordLoopRegs, bool InitCase, set<int> &LoopRegHashes, bool &StoppedOnIV, bool &changed, set<STARS_ea_t> &StackPtrCopySet, int &DepthCounter) { bool success = true; bool UseFP = this->GetParentFunc()->UsesFramePointer(); STARSOpndTypePtr SearchOp = (Left) ? CloneIfSubwordReg(this->GetConstLeftOperand()) : CloneIfSubwordReg(this->GetConstRightOperand()); if (SearchOp == nullptr) { --DepthCounter; return true; // expansion ends cleanly with no operand to expand } ++DepthCounter; if (STARS_EXPR_CALL_DEPTH_LIMIT < DepthCounter) { success = false; --DepthCounter; SMP_msg("INFO: ExpandOperand() stopped at DepthCounter %d UseAddr %llx\n", DepthCounter, (uint64_t)UseAddr); return success; } STARSInductionVarFamilyList::iterator IVFamilyIter; size_t FamilyIndex; // Check if operand meets criteria for ending the expansion. if (SearchOp->IsVoidOp()) { success = true; } else if (SearchOp->IsImmedOp()) { success = true; STARS_uval_t ImmedVal = SearchOp->GetImmedValue(); bool GlobalStaticRange = IsImmedGlobalAddress((STARS_ea_t) ImmedVal); if (GlobalStaticRange) { StackPtrCopySet.insert(UseAddr); // add global static mem ops to stack ptr copies SMP_msg("INFO: GLOBAL mem def found at %llx in ExpandOperand()\n", (uint64_t) UseAddr); } } else if (SearchOp->IsMemOp() && (SearchOp->GetSegReg() == STARS_x86_R_cs)) { // Cannot go further with CS-relative mem read. !!!!****!!!! Could we fetch a constant value? StackPtrCopySet.insert(UseAddr); // add global static mem ops to stack ptr copies SMP_msg("INFO: GLOBAL CS-relative mem def found at %llx in ExpandOperand()\n", (uint64_t) UseAddr); success = true; } else if (SearchOp->IsMemOp() && (!MDIsDirectStackAccessOpnd(SearchOp, UseFP))) { if (SearchOp->IsStaticMemOp()) { StackPtrCopySet.insert(UseAddr); // add global static mem ops to stack ptr copies SMP_msg("INFO: GLOBAL mem def found at %llx in ExpandOperand()\n", (uint64_t)UseAddr); } list<STARS_ea_t> MemDefAddrs; this->GetParentFunc()->ResetProcessedBlocks(); set<STARS_regnum_t> AddressRegs; SearchOp->GetAddressRegs(AddressRegs); set<int> IntAddressRegs; // convert to int to help g++ allocator problem on packed enum types for (set<STARS_regnum_t>::const_iterator RegIter = AddressRegs.cbegin(); RegIter != AddressRegs.cend(); ++RegIter) { pair<set<int>::iterator, bool> InsertResult = IntAddressRegs.insert((int) (*RegIter)); } SMPBasicBlock *UseAddrBlock = this->GetParentFunc()->GetBlockFromInstAddr(UseAddr); assert(nullptr != UseAddrBlock); this->GetParentFunc()->FindMatchingMemDEFAddrs(UseAddr, UseAddrBlock, SearchOp, MemDefAddrs, IntAddressRegs); IntAddressRegs.clear(); success = (1 >= MemDefAddrs.size()); // reached top of function (size == 0), or found a single MemDef (size == 1) SMP_msg("INFO: SPARK: MemDefAddrs set is of size %zu at %llx\n", MemDefAddrs.size(), (uint64_t) UseAddr); bool UniqueMemDefAddr = (1 == MemDefAddrs.size()); bool ReplaceMemOpndWithMoveSource = (UniqueMemDefAddr && global_STARS_program->ShouldSTARSTranslateToSPARKAda()); #if 0 if (!success) { // Replace with symbolic mem use and expand. #else if (!ReplaceMemOpndWithMoveSource) { // in either case, replace with symbolic mem use and expand. #endif #if 1 success = true; // traced as far as we can go #else // Tracing mem address registers can explode run time. // Replace the MemDefOp with a ReadMem64 expr based on the address regs. // First, we need a UseIter for the SearchOp, but only stack memory ops are in the Use set, // so add this operand to a special SymbolicMemUse set. SMPInstr *UseInst = this->GetParentFunc()->GetInstFromAddr(UseAddr); assert(nullptr != UseInst); UseInst->AddSymbolicMemUse(SearchOp, UNINIT, SMP_SSA_UNINIT); STARSDefUseIter MemUseIter = UseInst->FindSymbolicMemUse(SearchOp); assert(UseInst->GetLastSymbolicMemUse() != MemUseIter); // Now, use the MemUseIter to create a symbolic memory expression. STARSExpression *ReadMemExpr = new STARSExpression(MemUseIter, UseInst); // Replace this->LeftOperand or this->RightOperand with a subtree. if (Left) { this->SetLeftOperand(nullptr); this->SetLeftTree(ReadMemExpr); success = this->GetLeftTree()->ExpandExpr(UseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } else { this->SetRightOperand(nullptr); this->SetRightTree(ReadMemExpr); success = this->GetRightTree()->ExpandExpr(UseAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } changed = true; #endif } else { // Replace the current operand with the MemDefAddr right-hand-side move source operand and recurse. STARS_ea_t NewDefAddr = MemDefAddrs.front(); SMPInstr *NewDefInst = this->GetParentFunc()->GetInstFromAddr(NewDefAddr); STARSOpndTypePtr RHSOperand; success = NewDefInst->IsSimpleCopy(RHSOperand); if (success) { int NewBlockNum = this->GetParentFunc()->GetBlockNumFromInstAddr(NewDefAddr); bool WentBeforeLoop = !this->GetParentFunc()->IsBlockInLoop(NewBlockNum, LoopIndex); if (WentBeforeLoop && StopOnLoopBoundary) { // Do not replace USE with its DEF, as DEF precedes the loop. Stop // inside the loop and declare victory. // !!!!****!!!! Do we need to replace the MemDefOp with a symbolic ReadMem64? return true; } STARSOpndTypePtr NewSearchOp = CloneIfSubwordReg(RHSOperand); STARSDefUseIter UseIter = NewDefInst->FindUse(NewSearchOp); assert(UseIter != NewDefInst->GetLastUse()); int UseSSANum = UseIter->GetSSANum(); if (Left) this->SetLeftSSANum(UseSSANum); else this->SetRightSSANum(UseSSANum); this->SetParentInst(NewDefInst); // Replace current operand with new operand. if (Left) { this->SetLeftOperand(RHSOperand); this->SetLeftUseAddr(NewDefAddr); } else { this->SetRightOperand(RHSOperand); this->SetRightUseAddr(NewDefAddr); } changed = true; // Recurse into new operand at NewDefAddr. success = this->ExpandOperand(LoopIndex, Left, StopOnIV, NewDefAddr, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } } } else if (!MDIsDataFlowOpnd(SearchOp, UseFP)) { success = false; SMP_msg("SPARK: Non-DataFlowOpnd: "); PrintOperand(SearchOp); SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at non-DataFlowOpnd at %llx\n", (uint64_t) UseAddr); } else { // we found a reg or direct stack access operand // Find DEF instruction for operand. CanonicalizeOpnd(SearchOp); int SSANum = (Left) ? this->GetLeftSSANum() : this->GetRightSSANum(); SMPBasicBlock *CurrBlock = this->GetParentFunc()->GetBlockFromInstAddr(UseAddr); bool LocalName = CurrBlock->IsLocalName(SearchOp); STARS_ea_t DefAddr = CurrBlock->GetDefAddrFromUseAddr(SearchOp, UseAddr, SSANum, LocalName); success = this->ExpandOperandHelper(DefAddr, SearchOp, LoopIndex, Left, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } if (success) { // Inherit PreLoopDefAddr. if (Left && (STARS_BADADDR == this->GetLeftPreLoopDefAddr()) && this->HasLeftSubTree()) { // We expanded our left operand into an expr. Our PreLoopDefAddr is not informative. // Inherit the LeftPreLoopDefAddr of the LeftTree we expanded our LeftOperand into. this->SetLeftPreLoopDefAddr(this->GetLeftTree()->GetLeftPreLoopDefAddr()); } else if (!Left && (STARS_BADADDR == this->GetRightPreLoopDefAddr()) && this->HasRightSubTree()) { // We expanded our right operand into an expr. Our PreLoopDefAddr is not informative. // Inherit the LeftPreLoopDefAddr of the RightTree we expanded our RightOperand into. this->SetRightPreLoopDefAddr(this->GetRightTree()->GetLeftPreLoopDefAddr()); } } --DepthCounter; return success; } // end of STARSExpression::ExpandOperand() // recursive helper for ExpandOperand() bool STARSExpression::ExpandOperandHelper(STARS_ea_t DefAddr, const STARSOpndTypePtr &SearchOp, size_t LoopIndex, bool Left, bool StopOnIV, bool StopOnLoopBoundary, bool RecordLoopRegs, bool InitCase, set<int> &LoopRegHashes, bool &StoppedOnIV, bool &changed, set<STARS_ea_t> &StackPtrCopySet, int &DepthCounter) { bool success = true; bool UseFP = this->GetParentFunc()->UsesFramePointer(); // See if we have crossed the beginning-of-loop boundary for the first time. STARS_ea_t CurrLoopDefAddr = Left ? this->GetLeftPreLoopDefAddr() : this->GetRightPreLoopDefAddr(); STARSInductionVarFamilyList::iterator IVFamilyIter; size_t FamilyIndex; ++DepthCounter; if (STARS_EXPR_CALL_DEPTH_LIMIT < DepthCounter) { success = false; --DepthCounter; SMP_msg("INFO: ExpandOperandHelper() stopped at DepthCounter %d DefAddr %llx\n", DepthCounter, (uint64_t) DefAddr); return success; } if (STARS_IsSSAMarkerPseudoID(DefAddr)) { success = true; // DEF is in SSA marker, such as an incoming arg; expansion terminates successfully. if (STARS_BADADDR == CurrLoopDefAddr) { // Crossed from within the loop to the SSA Marker. if (Left) this->SetLeftPreLoopDefAddr(DefAddr); else this->SetRightPreLoopDefAddr(DefAddr); } } else if ((STARS_BADADDR == DefAddr) || STARS_IsLiveInPseudoID(DefAddr)) { success = false; // bad addr, or other non-instruction address. SMP_msg("SPARK: Bad DefAddr SearchOp:"); PrintOperand(SearchOp); SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at bad DefAddr: %llx\n", (uint64_t) DefAddr); } else if (STARS_IsBlockNumPseudoID(DefAddr)) { // Hitting a Phi function is only acceptable for induction variables when StopOnIV is our mode, // or for a Phi function at a loop header block if InitCase, because we can resume expansion // before the loop; or for a Phi function at the loop header block for current LoopIndex. int LoopIndex = -1; success = (StopOnIV && this->GetParentFunc()->IsLoopNestInductionVar(SearchOp, this->GetParentInst(), IVFamilyIter, FamilyIndex, LoopIndex)); if (success) { StoppedOnIV = true; SMP_msg("INFO: StoppedOnIV at DefAddr %llx for ParentInst at %llx\n", (uint64_t) DefAddr, (uint64_t) this->GetParentInst()->GetAddr()); SMP_msg("INFO: StoppedOnIV SearchOp was: "); PrintOperand(SearchOp); SMP_msg("\n"); } if (success && (STARS_BADADDR == CurrLoopDefAddr)) { #if 0 // Did we cross loop boundary? int NewBlockNum = (int) STARS_GetBlockNumFromPseudoID(DefAddr); if (!this->GetParentFunc()->IsBlockInLoop(NewBlockNum, LoopIndex)) { // Crossed from within the loop to a Phi function before the loop. if (Left) this->SetLeftPreLoopDefAddr(DefAddr); else this->SetRightPreLoopDefAddr(DefAddr); } #else // Even the Phi at the top of the loop represents a pre-loop address that is better than STARS_BADADDR if (Left) this->SetLeftPreLoopDefAddr(DefAddr); else this->SetRightPreLoopDefAddr(DefAddr); #endif } else if (!success) { // Check for loop header block phi function special cases. int PhiBlockNum = STARS_GetBlockNumFromPseudoID(DefAddr); SMPBasicBlock *PhiBlock = this->GetParentFunc()->GetBlockByNum((size_t) PhiBlockNum); int PreLoopSSANum = PhiBlock->GetLoopLiveInSSANum(SearchOp); if ((SMP_SSA_UNINIT == PreLoopSSANum) || (!PhiBlock->IsLoopHeaderBlock())) { // failure SMP_msg("SPARK: Phi function SearchOp:"); PrintOperand(SearchOp); SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at phi function at %llx\n", (uint64_t)DefAddr); } else { // Have good PreLoopSSANum at a loop header block. bool AtLoopIndexHeader = false; if (PhiBlock->GetFunc()->IsBlockInLoop(PhiBlockNum, LoopIndex)) { int CurrLoopNum = PhiBlock->GetFunc()->GetLoopNumFromHeaderBlockNum(PhiBlockNum); AtLoopIndexHeader = (CurrLoopNum == (int) LoopIndex); } if (!StopOnLoopBoundary || InitCase) { // Use the PreLoopSSANum to continue before the loop. STARS_ea_t NewDefAddr = PhiBlock->GetFunc()->GetGlobalDefAddr(SearchOp, PreLoopSSANum); success = this->ExpandOperandHelper(NewDefAddr, SearchOp, LoopIndex, Left, StopOnIV, StopOnLoopBoundary, RecordLoopRegs, InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } else if (AtLoopIndexHeader) { // We are right where we are supposed to stop. success = true; } else { // failure SMP_msg("SPARK: Phi function SearchOp:"); PrintOperand(SearchOp); SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at phi function at %llx InitCase: %d\n", (uint64_t) DefAddr, InitCase); } } } } else { // found DEF inst. // 3. Get DEF right-hand-side SMPRegTransfer and create expression from it. SMPInstr *DefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr); int NewBlockNum = this->GetParentFunc()->GetBlockNumFromInstAddr(DefAddr); bool WentBeforeLoop = !this->GetParentFunc()->IsBlockInLoop(NewBlockNum, LoopIndex); bool StackPointerReg = SearchOp->MatchesReg(MD_STACK_POINTER_REG); if (WentBeforeLoop && StopOnLoopBoundary && (!StackPointerReg)) { // Do not replace USE with its DEF, as DEF precedes the loop. Stop // inside the loop and declare victory. Exception for stack pointer reg, // which we want to expand to its func entry value if possible. --DepthCounter; return true; } if (DEFAULT != DefInst->GetDataFlowType()) { SMP_msg("SPARK: Bad control flow type SearchOp:"); PrintOperand(SearchOp); SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at bad control flow type %d at %llx\n", DefInst->GetDataFlowType(), (uint64_t) DefAddr); --DepthCounter; return false; // don't want CALL DEFs, etc. } SMPRegTransfer *DefRT = DefInst->GetDefRT(SearchOp); if (nullptr == DefRT) { SMP_msg("SPARK: Bad DefRT SearchOp:"); PrintOperand(SearchOp); SMP_msg("\nERROR: SPARK: ExpandOperand() stopped at bad DefRT at %llx\n", (uint64_t) DefAddr); --DepthCounter; return false; // some odd opcodes might have a DEF but no normal RT, e.g. "fnstsw ax" } if ((STARS_BADADDR == CurrLoopDefAddr) && (this->GetParentFunc()->GetNumLoops() > LoopIndex)) { // Did we cross loop boundary? if (WentBeforeLoop) { // Crossed from within the loop to a DefInst before the loop. if (Left) this->SetLeftPreLoopDefAddr(DefAddr); else this->SetRightPreLoopDefAddr(DefAddr); } } // See if we have encountered a lea of stack or static memory address expr; record it if so. if (DefInst->IsStackBasedLoadEffectiveAddress(UseFP) || DefInst->IsGlobalStaticLoadEffectiveAddress()) { StackPtrCopySet.insert(DefAddr); } // If an SMP_ASSIGN RT was returned, it means that RT was DEF := USE and // we should use only the USE, i.e. the RightOperand, else use the whole RT. // If we have a stack alignment instruction (RSP := RSP AND bitmask), treat it // as RSP := RSP with only the SSANum being replaced. Alignment might be a no-op, // and we cannot statically analyze its effect, regardless. STARSOpndTypePtr UseOp; if (DefInst->IsStackAlignmentInst() || (SMP_ASSIGN == DefRT->GetOperator())) { // 4. Replace current operand with the USE operand. if (DefInst->IsStackAlignmentInst()) { assert(SMP_BITWISE_AND == DefRT->GetOperator()); UseOp = DefRT->GetLeftOperand(); assert(UseOp->MatchesReg(MD_STACK_POINTER_REG)); } else { assert(!DefRT->HasRightSubTree()); UseOp = DefRT->GetRightOperand(); } bool ConstUse = UseOp->IsImmedOp(); if (!(ConstUse || UseOp->IsRegOp() || UseOp->IsMemOp())) { SMP_msg("SPARK: Non-DataFlowOpnd: "); PrintOperand(UseOp); SMP_msg("\nINFO: SPARK: ExpandOperandHelper() hit non-DataFlow UseOp at %llx\n", (uint64_t) DefAddr); } else { STARSOpndTypePtr SearchOp2 = CloneIfSubwordReg(UseOp); CanonicalizeOpnd(SearchOp2); if (!ConstUse) { STARSDefUseIter UseIter = DefInst->FindUse(SearchOp2); assert(UseIter != DefInst->GetLastUse()); int UseSSANum = UseIter->GetSSANum(); // Until we have alias analysis, cannot trace non-stack memory // operands, which will not be SSA numbered. if (SearchOp2->IsMemOp() && (-1 == UseSSANum)) { --DepthCounter; return true; } if (Left) this->SetLeftSSANum(UseSSANum); else this->SetRightSSANum(UseSSANum); this->ParentInst = DefInst; if (!WentBeforeLoop && RecordLoopRegs && UseOp->IsRegOp()) { int RegHash = HashGlobalNameAndSSA(SearchOp2, UseSSANum); pair<set<int>::iterator, bool> InsertResult = LoopRegHashes.insert(RegHash); #if 1 if (InsertResult.second) { SMP_msg("INFO: SPARK: New LoopRegHash found at %llx\n", (uint64_t) DefAddr); } #endif } } // Replace current operand with new operand. if (Left) { this->SetLeftOperand(UseOp); this->SetLeftUseAddr(DefAddr); } else { this->SetRightOperand(UseOp); this->SetRightUseAddr(DefAddr); } changed = true; if (!ConstUse) { // 5. Recurse into new operand at DefAddr. success = this->ExpandOperand(LoopIndex, Left, StopOnIV, DefAddr, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } else { success = true; } } } else { // not just leftop := rightop STARSExpression *DefExpr = new STARSExpression(DefRT); // 4. Make new expression the sub-tree that replaces the operand. // 5. Recurse into new sub-tree. if (Left) { this->SetLeftTree(DefExpr); success = this->GetLeftTree()->ExpandExpr(DefAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } else { this->SetRightTree(DefExpr); int DepthCounter = 0; success = this->GetRightTree()->ExpandExpr(DefAddr, LoopIndex, false, StopOnIV, StopOnLoopBoundary, (!WentBeforeLoop && RecordLoopRegs), InitCase, LoopRegHashes, StoppedOnIV, changed, StackPtrCopySet, DepthCounter); } changed = true; } } --DepthCounter; return success; } // end of STARSExpression::ExpandOperandHelper() // list incoming argument register numbers encountered (SSA #0 in an InArg reg) void STARSExpression::ListInArgRegsUsed(std::bitset<1 + MD_LAST_REG_NO> &RegNums) { if (this->HasLeftSubTree()) { this->GetLeftTree()->ListInArgRegsUsed(RegNums); } else if ((nullptr != this->GetConstLeftOperand()) && (0 == this->GetLeftSSANum()) && this->GetConstLeftOperand()->IsRegOp()) { STARS_regnum_t CurrRegNum = this->GetLeftOperand()->GetReg(); if (global_STARS_program->IsArgumentReg(CurrRegNum)) { RegNums.set((size_t) CurrRegNum); } } if (this->HasRightSubTree()) { this->GetRightTree()->ListInArgRegsUsed(RegNums); } else if ((nullptr != this->GetConstRightOperand()) && (0 == this->GetRightSSANum()) && this->GetConstRightOperand()->IsRegOp()) { STARS_regnum_t CurrRegNum = this->GetConstRightOperand()->GetReg(); if (global_STARS_program->IsArgumentReg(CurrRegNum)) { RegNums.set((size_t) CurrRegNum); } } return; } // end of STARSExpression::ListInArgRegsUsed() // Is any incoming argument register encountered? (SSA #0 in an InArg reg) bool STARSExpression::UsesInArgReg(void) const { if (this->HasLeftSubTree()) { if (this->GetLeftTree()->UsesInArgReg()) return true; } else if ((nullptr != this->GetConstLeftOperand()) && (0 == this->GetLeftSSANum()) && this->GetConstLeftOperand()->IsRegOp()) { STARS_regnum_t CurrRegNum = this->GetConstLeftOperand()->GetReg(); if (global_STARS_program->IsArgumentReg(CurrRegNum)) { return true; } } if (this->HasRightSubTree()) { if (this->GetRightTree()->UsesInArgReg()) return true; } else if ((nullptr != this->GetConstRightOperand()) && (0 == this->GetRightSSANum()) && this->GetConstRightOperand()->IsRegOp()) { STARS_regnum_t CurrRegNum = this->GetConstRightOperand()->GetReg(); if (global_STARS_program->IsArgumentReg(CurrRegNum)) { return true; } } return false; } // end of STARSExpression::UsesInArgReg() // Is Expr just the stack pointer plus optional offset constant? bool STARSExpression::IsStackPtrPlusOffset(void) const { SMPoperator CurrOper = this->GetOperator(); bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetConstLeftOperand()->IsRegOp() && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG); bool SPPlusOffset = false; bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd; // SMP_ASSIGN in expr means no RHS if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) { const STARSOpndTypePtr RightOp = this->GetConstRightOperand(); bool HasRightTree = this->HasRightSubTree(); bool ImmedRightOp = (nullptr != RightOp) && (!HasRightTree) && RightOp->IsImmedOp(); SPPlusOffset = ImmedRightOp; } return (JustStackPtr || SPPlusOffset); } // end of STARSExpression::IsStackPtrPlusOffset() // Is stack pointer reg found in the expr? bool STARSExpression::IsStackPtrRegUsed(void) const { bool SPFound = false; if (this->HasLeftSubTree()) SPFound = this->GetLeftTree()->IsStackPtrRegUsed(); else { assert(nullptr != this->GetConstLeftOperand()); if (this->GetConstLeftOperand()->IsRegOp()) SPFound = this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG); } if (!SPFound) { if (this->HasRightSubTree()) SPFound = this->GetRightTree()->IsStackPtrRegUsed(); else if (nullptr != this->GetConstRightOperand()) { if (this->GetConstRightOperand()->IsRegOp()) SPFound = this->GetConstRightOperand()->MatchesReg(MD_STACK_POINTER_REG); } } return SPFound; } // end of STARSExpression::IsStackPtrRegUsed() // If expr is SP+offset, add offset to CurrentStackPtrOffset to get FinalStackPtrOffset and return true. // CurrentStackPtrOffset should be relative to function entry and will generally be negative. bool STARSExpression::IsStackPtrOffset(const STARS_sval_t CurrentStackPtrOffset, STARS_sval_t &FinalStackPtrOffset) const { bool StackPtrExpr = false; bool Addition = (SMP_ADD == this->GetOperator()); if (Addition || (SMP_SUBTRACT == this->GetOperator())) { if (!this->HasLeftSubTree() && (nullptr != this->GetConstLeftOperand()) && this->GetConstLeftOperand()->MatchesReg(MD_STACK_POINTER_REG)) { // Definitely adding or subtracting from the stack pointer reg. if (!this->HasRightSubTree() && (nullptr != this->GetConstRightOperand()) && this->GetConstRightOperand()->IsImmedOp()) { // We are adding or subtracting an immediate value. StackPtrExpr = true; STARS_uval_t ImmedValue = this->GetConstRightOperand()->GetImmedValue(); if (Addition) { FinalStackPtrOffset = ((STARS_sval_t) ImmedValue) + CurrentStackPtrOffset; } else { FinalStackPtrOffset = CurrentStackPtrOffset - ((STARS_sval_t) ImmedValue); } } } } return StackPtrExpr; } // end of STARSExpression::IsStackPtrOffset() // Is top-level operator relational? bool STARSExpression::IsRelationalExpr(void) const { SMPoperator TopLevelOperator = this->GetOperator(); return IsRelationalOperator(TopLevelOperator); } // end of STARSExpression::IsRelationalExpr() // Is expr just a constant value? bool STARSExpression::IsConstExpr(void) const { bool AssignOnly = (!this->HasRightSubTree() && (!this->HasLeftSubTree()) && (SMP_ASSIGN == this->GetOperator())); bool ConstOnly = (AssignOnly && (this->GetConstLeftOperand() != nullptr) && (this->GetConstLeftOperand()->IsImmedOp())); return ConstOnly; } // end of STARSExpression::IsConstExpr() // Find all uses of InArgOp, SSANum == 0, and give it NewSSANum; replace all ParentInsts with CallInst void STARSExpression::SubstituteSSANum(SMPInstr *CallInst, const int NewSSANum, const STARSOpndTypePtr &InArgOp) { STARS_ea_t CallAddr = CallInst->GetAddr(); this->SetParentInst(CallInst); this->SetParentFunc(CallInst->GetBlock()->GetFunc()); if (this->HasLeftSubTree()) { this->GetLeftTree()->SubstituteSSANum(CallInst, NewSSANum, InArgOp); // recurse } else if (0 == this->GetLeftSSANum()) { // InArgs will have SSANum of zero if (IsEqOp(InArgOp, this->GetConstLeftOperand())) { this->SetLeftSSANum(NewSSANum); this->SetLeftUseAddr(CallAddr); } } this->SetLeftPreLoopDefAddr(STARS_BADADDR); if (this->HasRightSubTree()) { this->GetRightTree()->SubstituteSSANum(CallInst, NewSSANum, InArgOp); // recurse } else if (0 == this->GetRightSSANum()) { // InArgs will have SSANum of zero if (IsEqOp(InArgOp, this->GetConstRightOperand())) { this->SetRightSSANum(NewSSANum); this->SetRightUseAddr(CallAddr); } } this->SetRightPreLoopDefAddr(STARS_BADADDR); return; } // end of STARSExpression::SubstituteSSANum() // For loop exprs, find the DefOp at LeftPreLoopDefAddr STARSOpndTypePtr STARSExpression::FindLeftPreLoopDefOp(void) const { STARS_ea_t DefAddr = this->GetLeftPreLoopDefAddr(); STARSOpndTypePtr LeftPreLoopDefOp = nullptr; if ((STARS_BADADDR == DefAddr) || STARS_IsSSAMarkerPseudoID(DefAddr) || STARS_IsBlockNumPseudoID(DefAddr) || STARS_IsLiveInPseudoID(DefAddr)) { // Nothing to trace back. LeftPreLoopDefOp = this->GetLeftOperand(); } else { SMPInstr *PreLoopDefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr); LeftPreLoopDefOp = PreLoopDefInst->GetFirstLeftOperandNoNorm(); } return LeftPreLoopDefOp; } // end of STARSExpression::FindLeftPreLoopDefOp() // Detect loop-invariant exprs, which can occur inside loops. bool STARSExpression::AreAllRegsLoopInvariant(void) const { bool LoopInvariantExpr = true; bool UseFP = this->GetParentFunc()->UsesFramePointer(); if (this->HasLeftSubTree()) { LoopInvariantExpr = this->GetLeftTree()->AreAllRegsLoopInvariant(); } else { SMPBasicBlock *CurrBlock = this->GetParentInst()->GetBlock(); STARS_ea_t UseAddr = this->GetLeftUseAddr(); STARSOpndTypePtr CurrOp = CloneIfSubwordReg(this->GetConstLeftOperand()); CanonicalizeOpnd(CurrOp); if (MDIsDataFlowOpnd(CurrOp, UseFP)) { bool LocalName = CurrBlock->IsLocalName(CurrOp); int SSANum = this->GetLeftSSANum(); STARS_ea_t DefAddr = CurrBlock->GetDefAddrFromUseAddr(CurrOp, UseAddr, SSANum, LocalName); if (STARS_IsBlockNumPseudoID(DefAddr)) { SMP_msg("INFO: Phi DEF termination in STARSExpression::AreAllRegsLoopInvariant() at UseAddr %llx DefAddr %llx\n", (uint64_t)UseAddr, (uint64_t)DefAddr); LoopInvariantExpr = false; } else if (STARS_BADADDR == DefAddr) { SMP_msg("ERROR: Bad DefAddr termination in STARSExpression::AreAllRegsLoopInvariant() at UseAddr %llx SSANum: %d CurrOp: ", (uint64_t)UseAddr, (uint64_t)SSANum); PrintOperand(CurrOp); SMP_msg("\n"); LoopInvariantExpr = false; } else { SMPInstr *DefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr); STARSDefUseIter DefIter = DefInst->FindDef(CurrOp); if (DefIter != DefInst->GetLastDef()) { if (DefIter->GetSSANum() == SSANum) { LoopInvariantExpr = DefIter->IsInvariantForAllLoops(); } else { SMP_msg("ERROR: SSANum mismatch in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr); LoopInvariantExpr = false; } } else { SMP_msg("ERROR: FindDef failure in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr); PrintOperand(this->GetConstRightOperand()); SMP_msg("\n"); LoopInvariantExpr = false; } } } } if (LoopInvariantExpr) { if (this->HasRightSubTree()) { LoopInvariantExpr = this->GetRightTree()->AreAllRegsLoopInvariant(); } else { SMPBasicBlock *CurrBlock = this->GetParentInst()->GetBlock(); STARS_ea_t UseAddr = this->GetRightUseAddr(); STARSOpndTypePtr CurrOp = CloneIfSubwordReg(this->GetConstRightOperand()); CanonicalizeOpnd(CurrOp); if (MDIsDataFlowOpnd(CurrOp, UseFP)) { bool LocalName = CurrBlock->IsLocalName(CurrOp); int SSANum = this->GetRightSSANum(); STARS_ea_t DefAddr = CurrBlock->GetDefAddrFromUseAddr(CurrOp, UseAddr, SSANum, LocalName); if (STARS_IsBlockNumPseudoID(DefAddr)) { SMP_msg("INFO: Phi DEF termination in STARSExpression::AreAllRegsLoopInvariant() at UseAddr %llx DefAddr %llx\n", (uint64_t)UseAddr, (uint64_t)DefAddr); LoopInvariantExpr = false; } else { SMPInstr *DefInst = this->GetParentFunc()->GetInstFromAddr(DefAddr); assert(nullptr != DefInst); STARSDefUseIter DefIter = DefInst->FindDef(CurrOp); if (DefIter != DefInst->GetLastDef()) { if (DefIter->GetSSANum() == SSANum) { LoopInvariantExpr = DefIter->IsInvariantForAllLoops(); } else { SMP_msg("ERROR: SSANum mismatch in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr); LoopInvariantExpr = false; } } else { SMP_msg("ERROR: FindDef failure in STARSExpression::AreAllRegsLoopInvariant() at DefAddr %llx\n", (uint64_t)DefAddr); PrintOperand(this->GetConstRightOperand()); SMP_msg("\n"); LoopInvariantExpr = false; } } } } } return LoopInvariantExpr; } // end of STARSExpression::AreAllRegsLoopInvariant() // If this is a relational range expr, produce the lower and limit exprs void STARSExpression::SplitMemoryRangeExpr(bool PositiveIncrement, STARSExpression *&InitExpr, STARSExpression *&LimitExpr) { assert(this->IsRelationalExpr()); SMPoperator CurrOper = this->GetOperator(); // Different cases: < or <=; > or >=; == or != bool LessThanCase = ((SMP_LESS_THAN == CurrOper) || (SMP_LESS_EQUAL == CurrOper) || (SMP_BELOW == CurrOper) || (SMP_BELOW_EQUAL == CurrOper)); bool GreaterThanCase = ((SMP_GREATER_THAN == CurrOper) || (SMP_GREATER_EQUAL == CurrOper) || (SMP_ABOVE == CurrOper) || (SMP_ABOVE_EQUAL == CurrOper)); if (!LessThanCase && !GreaterThanCase) { assert((SMP_EQUAL == CurrOper) || (SMP_NOT_EQUAL == CurrOper)); LessThanCase = PositiveIncrement; GreaterThanCase = (!PositiveIncrement); } if (LessThanCase) { assert(PositiveIncrement); // InitExpr will be the LHS of this expr. InitExpr = this->CloneLHS(); // LimitExpr will be the RHS of this expr. LimitExpr = this->CloneRHS(); } else if (GreaterThanCase) { assert(!PositiveIncrement); // InitExpr will be the RHS of this expr. InitExpr = this->CloneRHS(); // LimitExpr will be the LHS of this expr. LimitExpr = this->CloneLHS(); } return; } // end of STARSExpression::SplitMemoryRangeExpr() // Assuming simple address regs +/- immediate, extract the immediate operand value & return true. bool STARSExpression::ExtractImmedValue(STARS_uval_t &Value) const { bool FoundImmed = false; if (this->HasLeftSubTree()) FoundImmed = this->GetLeftTree()->ExtractImmedValue(Value); else { assert(nullptr != this->GetConstLeftOperand()); if (this->GetConstLeftOperand()->IsImmedOp()) { bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator()); if (AddOrSubtract) { Value = this->GetConstLeftOperand()->GetImmedValue(); bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator()); if (Subtraction) Value = (0 - Value); FoundImmed = true; } } } if (!FoundImmed) { if (this->HasRightSubTree()) FoundImmed = this->GetRightTree()->ExtractImmedValue(Value); else if (nullptr != this->GetConstRightOperand()) { if (this->GetConstRightOperand()->IsImmedOp()) { bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator()); if (AddOrSubtract) { Value = this->GetConstRightOperand()->GetImmedValue(); bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator()); if (Subtraction) Value = (0 - Value); FoundImmed = true; } } } } return FoundImmed; } // end of STARSExpression::ExtractImmedValue() // Find same Immed operand as ExtractImmedValue() (OldValue) and change its value to NewValue. bool STARSExpression::UpdateImmedValue(STARS_uval_t OldValue, STARS_uval_t NewValue) { STARS_sval_t SignedOldValue = (STARS_sval_t) OldValue; STARS_sval_t SignedNewValue = (STARS_sval_t) NewValue; assert(OldValue != 0); bool OldNegative = (0 > SignedOldValue); bool NewNegative = (0 > SignedNewValue); bool SignChange = (OldNegative != NewNegative); bool FoundImmed = false; if (this->HasLeftSubTree()) FoundImmed = this->GetLeftTree()->UpdateImmedValue(OldValue, NewValue); else { assert(nullptr != this->GetConstLeftOperand()); if (this->GetConstLeftOperand()->IsImmedOp()) { bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator()); if (AddOrSubtract) { STARS_sval_t Value = (STARS_sval_t) this->GetConstLeftOperand()->GetImmedValue(); bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator()); FoundImmed = true; if (Subtraction) { Value = (0 - Value); assert(NewNegative && OldNegative); // SMP_SUBTRACT, so we should be changing negative value to smaller negative value // Replace the value. Subtract a positive value. SignedNewValue = (0 - SignedNewValue); // get abs value to subtract } else { // addition if (SignChange) { // Replace the value. Subtract a positive value. SignedNewValue = (0 - SignedNewValue); // get abs value to subtract this->SetOperator(SMP_SUBTRACT); } else { // Leave the SMP_ADD operator alone and change the value added. ; } } assert(OldValue = (STARS_uval_t) Value); this->SetLeftOperand(this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t)SignedNewValue)); } } // end if (this->GetLeftOperand()->IsImmedOp()) } if (!FoundImmed) { if (this->HasRightSubTree()) FoundImmed = this->GetRightTree()->UpdateImmedValue(OldValue, NewValue); else if (nullptr != this->GetConstRightOperand()) { if (this->GetConstRightOperand()->IsImmedOp()) { bool AddOrSubtract = IsIntegerAddOrSubOperator(this->GetOperator()); if (AddOrSubtract) { STARS_sval_t Value = (STARS_sval_t) this->GetConstRightOperand()->GetImmedValue(); bool Subtraction = (SMP_SUBTRACT == this->GetOperator()) || (SMP_SUBTRACT_BORROW == this->GetOperator()); FoundImmed = true; if (Subtraction) { Value = (0 - Value); assert(NewNegative && OldNegative); // SMP_SUBTRACT, so we should be changing negative value to smaller negative value // Replace the value. Subtract a positive value. SignedNewValue = (0 - SignedNewValue); // get abs value to subtract } else { // addition if (SignChange) { // Replace the value. Subtract a positive value. SignedNewValue = (0 - SignedNewValue); // get abs value to subtract this->SetOperator(SMP_SUBTRACT); } else { // Leave the SMP_ADD operator alone and change the value added. ; } } assert(OldValue = (STARS_uval_t)Value); this->SetRightOperand(this->GetParentInst()->MakeImmediateOpnd((STARS_uval_t) SignedNewValue)); } } // end if (this->GetRightOperand()->IsImmedOp()) } } return FoundImmed; } // end of STARSExpression::UpdateImmedValue() // ***************************************************************** // Class SMPInstr // ***************************************************************** // Constructor for instruction. SMPInstr::SMPInstr(STARS_ea_t addr) : STARS_ID(addr) { this->STARS_ID.SetFileNum(global_STARS_program->GetCurrentFileNum()); this->BasicBlock = NULL; #if 0 // get these from STARSInstrPtr now this->SMPcmd.size = 0; this->features = 0; #endif this->type = DEFAULT; // this->OptType = 0; #if 0 // get address from STARS_ID.GetIDWithinFile() this->address = addr; #endif this->StackPtrOffset = 0; this->STARSInstPtr = global_stars_interface->CreateInst(this->STARS_ID); #if 0 this->ResetGoodRTL(); this->ResetJumpTarget(); this->ResetBlockTerm(); this->ResetTailCall(); this->ResetCondTailCall(); this->ResetCallUsedAsJump(); this->ResetDirectRecursiveCall(); this->ResetInterrupt(); #else this->booleans1 = 0; #endif #if 0 this->ResetNop(); this->ResetRegClearIdiom(); this->ResetDefsFlags(); this->ResetUsesFlags(); this->ResetFarBranchComputed(); this->ResetBranchesToFarChunk(); this->ResetIndirectMemWrite(); this->ResetIndirectMemRead(); #else this->booleans2 = 0; #endif #if 0 this->ResetLoadFromStack(); this->ResetMultiplicationBitsDiscarded(); this->ResetTypeInferenceComplete(); this->ResetCategoryInferenceComplete(); this->ResetDEFsTyped(); this->ResetUSEsTyped(); #else this->booleans3 = 0; #endif this->booleans4 = 0; this->booleans5 = 0; this->CallTarget = STARS_BADADDR; this->FarBranchTarget = STARS_BADADDR; this->AddSubSourceType = UNINIT; this->AddSubDefUseType = UNINIT; #if 0 this->AddSubSourceOp = nullptr; this->AddSubDefUseOp = nullptr; #endif this->DEFMemOp = nullptr; this->USEMemOp = nullptr; this->MoveSource = nullptr; this->Defs.clear(); this->Uses.clear(); return; } // Destructor. SMPInstr::~SMPInstr() { if (global_STARS_program->ShouldSTARSPerformFullAnalysis()) { // not already deleted this->Defs.clear(); this->Uses.clear(); } return; } char *SMPInstr::GetDisasm(void) const { return DisAsmText.GetDisAsm(this->GetAddr(), this->IsMarkerInst()); } // Is the instruction the type that terminates a basic block? bool SMPInstr::IsBasicBlockTerminator() const { if (this->GetDataFlowType() == CALL) { STARS_ea_t CallTarget = this->GetCallTarget(); if (STARS_BADADDR != CallTarget) { STARS_Function_t *CalleeFunc = global_stars_interface->get_func(CallTarget); if (NULL != CalleeFunc) { // Terminates basic block if it is a call to a non-returning func (e.g. abort(), exit()) return (!(CalleeFunc->HasReturnPoints())); } } } return ((type == JUMP) || (type == COND_BRANCH) || (type == INDIR_JUMP) || (type == RETURN) || (type == HALT)); } // Get non-flags DEF, usually for arithmetic opcode. set<DefOrUse, LessDefUse>::iterator SMPInstr::GetFirstNonFlagsDef(void) { set<DefOrUse, LessDefUse>::iterator DefIter; for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { STARSOpndTypePtr DefOp = DefIter->GetOp(); assert(nullptr != DefOp); #if 0 if (0x4000 > DefOp) { SMP_msg("ERROR: DefOp pointer value too small in GetFirstNonFlagsDef() at %x\n", this->GetAddr()); } #endif if (!((DefOp->IsRegOp()) && DefOp->MatchesReg(MD_FLAGS_REG))) break; // found a non-flags-reg DEF. } return DefIter; } // Fetch the operands for a shift instruction void SMPInstr::GetShiftOperands(STARSOpndTypePtr &ShiftedOp, STARSOpndTypePtr &ShiftCounterOp) { bool success = false; if (this->RTL.GetRT(0)->HasRightSubTree()) { SMPRegTransfer *RightRT = this->RTL.GetRT(0)->GetRightTree(); SMPoperator RightOper = RightRT->GetOperator(); if ((RightOper == SMP_U_LEFT_SHIFT) || (RightOper == SMP_S_LEFT_SHIFT) || (RightOper == SMP_U_RIGHT_SHIFT) || (RightOper == SMP_S_RIGHT_SHIFT)) { if (!(RightRT->HasRightSubTree())) { success = true; ShiftedOp = RightRT->GetLeftOperand(); ShiftCounterOp = RightRT->GetRightOperand(); } } } if (!success) { ShiftedOp = nullptr; ShiftCounterOp = nullptr; } return; } // end of SMPInstr::GetShiftOperands() void SMPInstr::GetMemDEFAddressRegs(set<STARS_regnum_t> &AddressRegs) const { if (this->GetMemDef() != nullptr) { this->GetMemDef()->GetAddressRegs(AddressRegs); } return; } void SMPInstr::GetDEFRegs(std::set<int> &DefRegs) { for (STARSDefUseIter DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { STARSOpndTypePtr DefOp = DefIter->GetOp(); if (DefOp->IsRegOp()) { int DefReg = (int) DefOp->GetReg(); pair<set<int>::iterator, bool> InsertResult = DefRegs.insert(DefReg); } } return; } // end of SMPInstr::GetDEFRegs() // Is the destination operand a memory reference? bool SMPInstr::HasDestMemoryOperand(void) const { return (! ((nullptr == this->DEFMemOp) || this->DEFMemOp->IsVoidOp())); } // end of SMPInstr::HasDestMemoryOperand() // Is a source operand a memory reference? bool SMPInstr::HasSourceMemoryOperand(void) const { return (! ((nullptr == this->USEMemOp) || this->USEMemOp->IsVoidOp())); } // end of SMPInstr::HasSourceMemoryOperand() bool SMPInstr::HasStaticMemWrite(void) const { return ((nullptr != this->DEFMemOp) && (this->DEFMemOp->IsStaticMemOp())); } bool SMPInstr::HasStaticMemRead(void) const { return ((nullptr != this->USEMemOp) && (this->USEMemOp->IsStaticMemOp())); } int SMPInstr::GetOptType(void) const { if (this->IsNop()) return 1; else return global_STARS_program->GetOptCategory(this->GetIDAOpcode()); } // Get the first memory operand in the DEF list. STARSOpndTypePtr SMPInstr::MDGetMemDefOp(void) const { return this->DEFMemOp; // cached value } // end of SMPInstr::MDGetMemDefOp() // Get the first memory operand in the USE list. STARSOpndTypePtr SMPInstr::MDGetMemUseOp(void) const { return this->USEMemOp; // cached value } // end of SMPInstr::MDGetMemUseOp() // return original Lea instruction [pseudo-]memory operand. STARSOpndTypePtr SMPInstr::GetLeaMemUseOp(void) const { if ((!this->MDIsLoadEffectiveAddressInstr()) || (this->BasicBlock == NULL)) { return nullptr; } else { map<STARS_ea_t, STARSOpndTypePtr>::iterator MapIter = this->GetBlock()->GetFunc()->FindLeaOperand(this->GetAddr()); assert(MapIter != this->GetBlock()->GetFunc()->GetLastLeaOperand()); return MapIter->second; } } STARSOpndTypePtr SMPInstr::GetMoveSource(void) { if (nullptr == this->MoveSource) { this->MoveSource = this->STARSInstPtr->MakeVoidOpnd(); } return this->MoveSource; } STARSOpndTypePtr SMPInstr::GetUseOnlyAddSubOp(void) const { unsigned short opcode = this->GetIDAOpcode(); bool IsAddSubInst = ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode) || (STARS_NN_inc == opcode) || (STARS_NN_dec == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode)); if ((this->RTL.GetCount() < 1) || (!IsAddSubInst)) return this->STARSInstPtr->MakeVoidOpnd(); // no RTL or not an addition or subtraction assert(this->RTL.GetRT(0)->HasRightSubTree()); SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree(); STARSOpndTypePtr RightOp = nullptr; #if SMP_BUILD_SPECIAL_ADC_SBB_RTL if ((STARS_NN_adc != opcode) && (STARS_NN_sbb != opcode)) { assert(!(RightTree->HasRightSubTree())); RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand } else { // Add with carry and subtract with borrow have an extra level // to the tree RTL, e.g. for add with carry: // opnd1 := (opnd1 + (opnd2 + carryflag)) assert(RightTree->HasRightSubTree()); RightTree = RightTree->GetRightTree(); RightOp = RightTree->GetLeftOperand(); } #else RightOp = RightTree->GetRightOperand(); // Use (also DEF) operand #endif return RightOp; }; // end of SMPInstr::GetUseOnlyAddSubOp() STARSOpndTypePtr SMPInstr::GetDefUseAddSubOp(void) const { unsigned short opcode = this->GetIDAOpcode(); bool IsAddSubInst = ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode) || (STARS_NN_inc == opcode) || (STARS_NN_dec == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode)); if ((this->RTL.GetCount() < 1) || (!IsAddSubInst)) return this->STARSInstPtr->MakeVoidOpnd(); // no RTL or not an addition or subtraction assert(this->RTL.GetRT(0)->HasRightSubTree()); SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree(); STARSOpndTypePtr LeftOp = RightTree->GetLeftOperand(); // Use (also DEF) operand return LeftOp; }; // end of SMPInstr::GetDefUseAddSubOp() STARSOpndTypePtr SMPInstr::GetFirstRightOperand(void) const { return this->RTL.GetRT(0)->GetRightOperand(); } STARSOpndTypePtr SMPInstr::GetFirstRightOperandNoNorm(void) const { unsigned short SignMask = 0; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); bool SignOrZeroExtension = CurrRT->HasRightSubTree(); #if 0 if (SignOrZeroExtension) { SMPoperator RightOperator = CurrRT->GetRightTree()->GetOperator(); SignOrZeroExtension = (SMP_SIGN_EXTEND == RightOperator) || (SMP_ZERO_EXTEND == RightOperator); } #endif if (SignOrZeroExtension || this->IsRegUpperBitsClearIdiom() || this->MDIsSignedLoad(SignMask)) return CurrRT->GetRightTree()->GetLeftOperandNoNorm(); else return CurrRT->GetRightOperandNoNorm(); } STARSOpndTypePtr SMPInstr::GetFirstLeftOperandNoNorm(void) const { return this->RTL.GetRT(0)->GetLeftOperandNoNorm(); } SMPRegTransfer * SMPInstr::GetDefRT(STARSOpndTypePtr DefOp) const { for (size_t index = 0; index < this->RTL.GetCount(); ++index) { SMPRegTransfer *CurrRT = this->RTL.GetRT(index); if (SMP_NULL_OPERATOR != CurrRT->GetOperator()) { if (IsEqOpIgnoreBitwidth(CurrRT->GetLeftOperand(), DefOp)) { if (CurrRT->HasRightSubTree()) { return CurrRT->GetRightTree(); } else { // Caller will have to recognize that SMP_ASSIGN operator implies only RightOperand is being returned. return CurrRT; } } } } return nullptr; } // end of SMPInstr::GetDefRT() // return # bytes width of first pushed operand size_t SMPInstr::GetPushedOpndByteSize(void) const { size_t OpndWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); if (this->RTL.GetRT(0)->HasRightSubTree()) { SMP_msg("ERROR: bad RTL structure for push instruction at %llx\n", (unsigned long long) this->GetAddr()); } else { OpndWidth = (size_t) this->RTL.GetRT(0)->GetRightOperand()->GetByteWidth(); } return OpndWidth; } // return first pushed operand STARSOpndTypePtr SMPInstr::GetPushedOpnd(void) const { size_t OpndWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); if ((STARS_NN_push != this->GetIDAOpcode()) || this->RTL.GetRT(0)->HasRightSubTree()) { SMP_msg("ERROR: bad RTL structure for push instruction at %llx\n", (unsigned long long) this->GetAddr()); return this->STARSInstPtr->MakeVoidOpnd(); } else { return this->RTL.GetRT(0)->GetRightOperand(); } } // return STARS_BADADDR if not jump, target addr otherwise. STARS_ea_t SMPInstr::GetJumpTarget(void) const { STARS_ea_t TargetAddr = STARS_BADADDR; if (this->HasGoodRTL() && ((this->type & (JUMP | COND_BRANCH)) || this->IsFixedCallJump())) { // We want to find an RTL of the form: inst_ptr_reg := code_addr SMPRegTransfer *CurrRT = this->RTL.GetRT(0); STARSOpndTypePtr DefOp = CurrRT->GetLeftOperand(); if (DefOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) { if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) { STARSOpndTypePtr UseOp = CurrRT->GetRightOperand(); if (UseOp->IsNearPointer() || UseOp->IsFarPointer()) { // address TargetAddr = UseOp->GetAddr(); } } } else if (this->IsFixedCallJump()) { assert(!CurrRT->HasRightSubTree()); STARSOpndTypePtr UseOp = CurrRT->GetRightOperand(); if (UseOp->IsImmedOp()) { TargetAddr = (STARS_ea_t) UseOp->GetImmedValue(); } else if (UseOp->IsNearPointer() || UseOp->IsFarPointer()) { TargetAddr = UseOp->GetAddr(); } } } return TargetAddr; } // end SMPInstr::GetJumpTarget() // Build set of address reg USEs, return true if any found bool SMPInstr::GetAddressRegs(STARSDefUseSet &AddressRegs) { STARSOpndTypePtr MemOp = nullptr; int BaseReg = STARS_x86_R_none, IndexReg = STARS_x86_R_none; uint16_t ScaleFactor = 0; STARS_ea_t offset = 0; if (this->HasDestMemoryOperand()) { MemOp = this->GetMemDef(); } else if (this->HasSourceMemoryOperand()) { MemOp = this->GetMemUse(); } if (nullptr != MemOp) { MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, offset); if (STARS_x86_R_none != BaseReg) { STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg); STARSDefUseIter BaseIter = this->FindUse(BaseOp); assert(this->GetLastUse() != BaseIter); pair<STARSDefUseIter, bool> InsertResult = AddressRegs.insert(*BaseIter); } if (STARS_x86_R_none != IndexReg) { STARSOpndTypePtr IndexOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg); STARSDefUseIter IndexIter = this->FindUse(IndexOp); assert(this->GetLastUse() != IndexIter); pair<STARSDefUseIter, bool> InsertResult = AddressRegs.insert(*IndexIter); } } return (!AddressRegs.empty()); } // get COND_BRANCH operator that guards the control flow, e.g. SMP_LESS_THAN SMPoperator SMPInstr::GetCondBranchOperator(void) const { SMPoperator GuardOperator = SMP_NULL_OPERATOR; if (this->GetDataFlowType() == COND_BRANCH) { SMPGuard *GuardRT = this->RTL.GetRT(0)->GetGuard(); assert(NULL != GuardRT); GuardOperator = GuardRT->GetOperator(); } return GuardOperator; } // end of SMPInstr::GetCondBranchOperator() // Does any USE have type NEGATEDPTR? bool SMPInstr::HasNegatedPtrUSE(void) { bool UseFound = false; set<DefOrUse, LessDefUse>::iterator UseIter; SMPOperandType UseType; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { UseType = UseIter->GetType(); if (IsEqType(UseType, NEGATEDPTR)) { UseFound = true; break; } } return UseFound; } // end of SMPInstr::HasNegatedPtrUSE() // Detect indirect memory DEFs or USEs void SMPInstr::AnalyzeIndirectRefs(bool UseFP) { STARS_ea_t InstAddr = this->GetAddr(); if (this->HasDestMemoryOperand()) { // Found a memory DEF. Is it indirect? STARSOpndTypePtr DefMemOp = this->MDGetMemDefOp(); if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) { this->SetIndirectMemWrite(); if (NULL != this->GetBlock()) { this->GetBlock()->SetHasIndirectMemWrite(); } } if (DefMemOp->IsStaticMemOp()) { if (NULL != this->GetBlock()) { this->GetBlock()->SetHasStaticMemWrite(); } } } if (this->HasSourceMemoryOperand()) { // Found a memory USE. Is it indirect? STARSOpndTypePtr UseMemOp = this->MDGetMemUseOp(); if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) { this->SetIndirectMemRead(); if (NULL != this->GetBlock()) { this->GetBlock()->SetHasIndirectMemRead(); } } if (UseMemOp->IsStaticMemOp()) { STARS_ea_t AddrOffset = USEMemOp->GetAddr(); if (!IsImmedGlobalAddress(AddrOffset) && (STARS_x86_R_none == UseMemOp->GetSegReg())) { SMP_msg("INFO: Doubtful identification of %llx as StaticMem at %llx\n", (uint64_t) AddrOffset, (uint64_t) InstAddr); } if (NULL != this->GetBlock()) { this->GetBlock()->SetHasStaticMemRead(); } } } return; } // end of SMPInstr::AnalyzeIndirectRefs() set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(const STARSOpndTypePtr &MemOp) { int BaseReg; int IndexReg; uint16_t ScaleFactor; STARS_ea_t displacement; set<DefOrUse, LessDefUse>::iterator PtrIter; if ((NULL == this->BasicBlock) || (NULL == this->BasicBlock->GetFunc())) { SMP_msg("ERROR: NULL member pointers in SMPInstr::GetPointerAddressReg() at %llx \n", (unsigned long long) this->GetAddr()); return this->GetLastUse(); } bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, displacement); if ((STARS_x86_R_none != BaseReg) && (!MDIsStackPtrReg(BaseReg, UseFP))) { STARSOpndTypePtr BaseOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg); PtrIter = this->FindUse(BaseOp); assert(PtrIter != this->GetLastUse()); if (IsDataPtr(PtrIter->GetType())) { return PtrIter; } } if ((STARS_x86_R_none != IndexReg) && (!MDIsStackPtrReg(IndexReg, UseFP))) { STARSOpndTypePtr IndexOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg); PtrIter = this->FindUse(IndexOp); assert(PtrIter != this->GetLastUse()); if (IsDataPtr(PtrIter->GetType())) { return PtrIter; } } PtrIter = this->GetLastUse(); return PtrIter; } // end of SMPInstr::GetPointerAddressReg() // Does the instruction have a numeric type as the second source operand? // NOTE: We can only analyze immediate values now. When data flow analyses are implemented, // we will be able to analyze many non-immediate operands. #define IMMEDNUM_LOWER -8191 #define IMMEDNUM_UPPER 8191 bool SMPInstr::IsSecondSrcOperandNumeric(void) const { bool SecondOpImm = (this->STARSInstPtr->GetOpnd(1)->IsImmedOp()); STARS_uval_t TempImm; if (SecondOpImm) { TempImm = this->STARSInstPtr->GetOpnd(1)->GetImmedValue(); } return (SecondOpImm && IsImmedNumeric((STARS_ea_t) TempImm)); } // end of SMPInstr::IsSecondSrcOperandNumeric() // Determine the type of the USE-only operand for add and subtract // instructions. If it is NUMERIC or PROF_NUMERIC, an optimizing // annotation will result. // As a byproduct, find the type of the USE/DEF operand as well. void SMPInstr::SetAddSubSourceType(void) { // Walk the RTL and find the operands we care about. // The RTL should look like: opnd1 := (opnd1 op opnd2), where op is // and add or subtract operator. Within the parentheses, the type // of opnd1 is our AddSubUseType and opnd1 is our AddSubUseOp, while // the type of opnd2 is our AddSubSourceType. if (this->RTL.GetCount() < 1) return; // no RTL, no leave types as UNINIT. assert(this->RTL.GetRT(0)->HasRightSubTree()); SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree(); STARSOpndTypePtr RightOp = nullptr; STARSOpndTypePtr LeftOp = RightTree->GetLeftOperand(); // Use (also DEF) operand #if SMP_BUILD_SPECIAL_ADC_SBB_RTL if ((STARS_NN_adc != opcode) && (STARS_NN_sbb != opcode)) { assert(!(RightTree->HasRightSubTree())); RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand } else { // Add with carry and subtract with borrow have an extra level // to the tree RTL, e.g. for add with carry: // opnd1 := (opnd1 + (opnd2 + carryflag)) assert(RightTree->HasRightSubTree()); RightTree = RightTree->GetRightTree(); RightOp = RightTree->GetLeftOperand(); } #else assert(!(RightTree->HasRightSubTree())); RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand #endif set<DefOrUse, LessDefUse>::iterator UseIter, SrcIter; SrcIter = this->FindUse(RightOp); assert(SrcIter != this->GetLastUse()); this->AddSubSourceType = SrcIter->GetType(); #if 0 this->AddSubSourceOp = RightOp; #endif UseIter = this->FindUse(LeftOp); assert(UseIter != this->GetLastUse()); this->AddSubDefUseType = UseIter->GetType(); #if 0 this->AddSubDefUseOp = LeftOp; #endif return; } // end of SMPInstr::SetAddSubSourceType() // Are all DEFs in the DEF set NUMERIC type? bool SMPInstr::AllDefsNumeric(void) { bool AllNumeric = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise set<DefOrUse, LessDefUse>::iterator CurrDef; for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) { // We ignore the stack pointer for pop instructions and consider only // the register DEF of the pop. if (this->MDIsPopInstr() && CurrDef->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) continue; AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType())); } return AllNumeric; } // end of SMPInstr::AllDefsNumeric() // Were the types of any DEFs derived from profiler info? bool SMPInstr::AnyDefsProfiled(void) { bool profd = false; set<DefOrUse, LessDefUse>::iterator CurrDef; for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) { profd = (profd || IsProfDerived(CurrDef->GetType())); } return profd; } // Do all DEFs have DEF_METADATA_UNUSED status? bool SMPInstr::AllDefMetadataUnused(void) { bool AllUnused = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise set<DefOrUse, LessDefUse>::iterator CurrDef; for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) { AllUnused = (AllUnused && (DEF_METADATA_UNUSED == CurrDef->GetMetadataStatus())); } return AllUnused; } // end of SMPInstr::AllDefMetadataUnused() // DEBUG print operands for Inst. void SMPInstr::PrintOperands(void) const { for (int i = 0; i < STARS_UA_MAXOP; ++i) { STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(i); if (nullptr == Opnd) // finished processing operands break; PrintOneOperand(Opnd, this->GetInstFeatures(), i); } SMP_msg(" \n"); return; } // end of SMPInstr::PrintOperands() // Complete DEBUG printing. void SMPInstr::Dump(void) const { if (this->IsMarkerInst()) { SMP_msg("%llx 1 SMPitype: %d SPOffset: %lld fnop\n", (unsigned long long) this->GetAddr(), (int) this->type, (long long) this->GetStackPtrOffset()); } else { SMP_msg("%llx %zd SMPitype: %d SPOffset: %lld %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), (int) this->type, (long long) this->GetStackPtrOffset(), DisAsmText.GetDisAsm(this->GetAddr(), false)); } #if STARS_DUMP_FG_INFO SMP_msg("USEs: "); if (NULL == this->GetBlock()) { // during early improvement of disasm this->Uses.Dump(); SMP_msg("DEFs: "); this->Defs.Dump(); } else { set<DefOrUse, LessDefUse>::const_iterator UseIter, DefIter; int UseHashValue, DefHashValue, UseSSANum, DefSSANum; unsigned short SignMiscInfo, SignMask; bool LocalName; for (UseIter = this->GetFirstConstUse(); UseIter != this->GetLastConstUse(); ++UseIter) { UseIter->Dump(); STARSOpndTypePtr UseOp = UseIter->GetOp(); if (UseOp->IsRegOp()) { LocalName = this->GetBlock()->IsLocalName(UseOp); UseSSANum = UseIter->GetSSANum(); UseHashValue = HashGlobalNameAndSSA(UseOp, UseSSANum); if (LocalName) { SignMiscInfo = this->GetBlock()->GetUseSignMiscInfo(UseHashValue); } else { SignMiscInfo = this->GetBlock()->GetFunc()->GetUseSignMiscInfo(UseHashValue); } SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS; if (SignMask == FG_MASK_SIGNED) { SMP_msg(" Si "); } else if (SignMask == FG_MASK_UNSIGNED) { SMP_msg(" Un "); } else if (SignMask == FG_MASK_INCONSISTENT_SIGN) { SMP_msg(" Xs "); } } SMP_msg("\n"); } if (this->Uses.GetSize() == 0) SMP_msg("\n"); SMP_msg("DEFs: "); for (DefIter = this->GetFirstConstDef(); DefIter != this->GetLastConstDef(); ++DefIter) { DefIter->Dump(); STARSOpndTypePtr DefOp = DefIter->GetOp(); if (DefOp->IsRegOp()) { LocalName = this->GetBlock()->IsLocalName(DefOp); DefSSANum = DefIter->GetSSANum(); DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum); if (LocalName) { SignMiscInfo = this->GetBlock()->GetDefSignMiscInfo(DefHashValue); } else { SignMiscInfo = this->GetBlock()->GetFunc()->GetDefSignMiscInfo(DefHashValue); } SignMask = SignMiscInfo & FG_MASK_SIGNEDNESS_BITS; if (SignMask == FG_MASK_SIGNED) { SMP_msg(" Si "); } else if (SignMask == FG_MASK_UNSIGNED) { SMP_msg(" Un "); } else if (SignMask == FG_MASK_INCONSISTENT_SIGN) { SMP_msg(" Xs "); } } SMP_msg("\n"); } if (this->Defs.GetSize() == 0) SMP_msg("\n"); } #else SMP_msg("USEs: "); this->Uses.Dump(); SMP_msg("DEFs: "); this->Defs.Dump(); #endif this->RTL.Dump(); #if SMP_VERBOSE_DUMP this->PrintOperands(); SMP_msg("\n"); #endif SMP_msg("DEFMemOp: "); PrintOperand(this->DEFMemOp); SMP_msg("\n"); SMP_msg("USEMemOp: "); PrintOperand(this->USEMemOp); SMP_msg("\n"); SMP_msg("booleans1: %d booleans2: %d booleans3: %d booleans4: %d booleans5: %d \n", this->booleans1, this->booleans2, this->booleans3, this->booleans4, this->booleans5); SMP_msg("\n"); return; } // end of SMPInstr::Dump() // Print out the destination operand list for the instruction, given // the OptCategory for the instruction as a hint. char * SMPInstr::DestString(int OptType) { static char DestList[STARS_MAXSTR]; int RegDestCount = 0; DestList[0] = 'Z'; // Make sure there are no leftovers from last call DestList[1] = 'Z'; DestList[2] = '\0'; set<DefOrUse, LessDefUse>::iterator CurrDef; for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) { STARSOpndTypePtr DefOpnd = CurrDef->GetOp(); if (DefOpnd->MatchesReg(X86_FLAGS_REG)) // don't print flags as a destination continue; // We want to ignore the stack pointer DEF for pops and just include // the register DEF for the pop. if (DefOpnd->MatchesReg(MD_STACK_POINTER_REG) && this->MDIsPopInstr()) continue; if (DefOpnd->IsRegOp()) { STARS_regnum_t DestReg = DefOpnd->GetReg(); if (0 == RegDestCount) { SMP_strncpy(DestList, MDGetRegName(DefOpnd), 1 + strlen(MDGetRegName(DefOpnd))); } else { SMP_strncat(DestList, " ", STARS_MAXSTR); SMP_strncat(DestList, MDGetRegName(DefOpnd), STARS_MAXSTR); } ++RegDestCount; } } if (0 >= RegDestCount) { SMP_msg("WARNING: No destination registers: %s\n", DisAsmText.GetDisAsm(this->GetAddr())); } else { SMP_strncat(DestList, " ZZ ", STARS_MAXSTR); } return DestList; } // end of SMPInstr::DestString() // print the registers that are dead right before this instruction. void SMPInstr::PrintDeadRegs(FILE *OutputFile) { std::size_t RegNum = (std::size_t) MD_FLAGS_REG; uint16_t ByteWidth = (uint16_t) global_STARS_program->GetSTARS_ISA_Bytewidth(); // Start with the flags register. if (this->DeadRegsBitmap[RegNum]) { SMP_fprintf(OutputFile, "%s ", RegNames[RegNum]); } // Do all other registers for (RegNum = 0; RegNum < MD_FLAGS_REG; ++RegNum) { if (this->DeadRegsBitmap[RegNum]) { SMP_fprintf(OutputFile, "%s ", MDGetRegNumName((STARS_regnum_t) RegNum, ByteWidth)); } } for (RegNum = 1 + MD_FLAGS_REG; RegNum <= MD_LAST_REG_NO; ++RegNum) { if (this->DeadRegsBitmap[RegNum] && (!STARS_x86_is_FP8087_reg((int) RegNum))) { SMP_fprintf(OutputFile, "%s ", MDGetRegNumName((STARS_regnum_t) RegNum, ByteWidth)); } } // Print sequence terminator. SMP_fprintf(OutputFile, "ZZ"); return; } // end of SMPInstr::PrintDeadRegs() // emit SPARK Ada for string operation, perhaps with repeat prefix that makes it a loop; return true if it writes memory. bool SMPInstr::MDEmitSPARKAdaStringOperation(FILE *OutFile) { bool HasRepeatEQPrefix = this->STARSInstPtr->HasRepeatIfEqualPrefix(); bool HasRepeatNEQPrefix = this->STARSInstPtr->HasRepeatIfNotEqualPrefix(); bool HasSomeRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix(); uint16_t opcode = this->GetIDAOpcode(); bool WritesMemory = false; bool GoodOpcode = true; if (opcode == STARS_NN_cmps) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " "); if (HasRepeatEQPrefix) { SMP_fprintf(OutFile, "X86.repe64_"); } else if (HasRepeatNEQPrefix) { SMP_fprintf(OutFile, "X86.repne64_"); } SMP_fprintf(OutFile, "cmps"); // procedure call } else if (opcode == STARS_NN_scas) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " "); if (HasRepeatEQPrefix) { SMP_fprintf(OutFile, "X86.repe64_"); } else if (HasRepeatNEQPrefix) { SMP_fprintf(OutFile, "X86.repne64_"); } SMP_fprintf(OutFile, "scas"); // procedure call } else if (opcode == STARS_NN_stos) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " "); if (HasSomeRepeatPrefix) { SMP_fprintf(OutFile, "X86.rep_stos"); // procedure call } else { SMP_fprintf(OutFile, "X86.stos"); // procedure call } WritesMemory = true; } else if (opcode == STARS_NN_movs) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " "); if (HasSomeRepeatPrefix) { SMP_fprintf(OutFile, "X86.rep_movs"); // procedure call } else { SMP_fprintf(OutFile, "X86.movs"); // procedure call } WritesMemory = true; } #if 0 else if (opcode == STARS_NN_movsd) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " "); if (HasSomeRepeatPrefix) { SMP_fprintf(OutFile, "X86.rep_movsd;\n"); // procedure call } else { SMP_fprintf(OutFile, "X86.movsd;\n"); // procedure call } } else if (opcode == STARS_NN_movsq) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " "); if (HasSomeRepeatPrefix) { SMP_fprintf(OutFile, "X86.rep_movsd;\n"); // procedure call } else { SMP_fprintf(OutFile, "X86.movsd;\n"); // procedure call } } #endif else { // don't expect to see port I/O opcodes STARS_NN_ins or STARS_NN_outs yet. GoodOpcode = false; SMP_fprintf(OutFile, "ERROR: Unknown string opcode at %llx\n", (unsigned long long) this->GetAddr()); } if (GoodOpcode) { // Append the byte-width suffix for the precise procedure call name. STARSOpndTypePtr FirstOpnd = this->GetOperand(0); uint16_t ByteWidth = FirstOpnd->GetByteWidth(); if (1 == ByteWidth) { SMP_fprintf(OutFile, "b;\n"); } else if (2 == ByteWidth) { SMP_fprintf(OutFile, "w;\n"); } else if (4 == ByteWidth) { SMP_fprintf(OutFile, "d;\n"); } else if (8 == ByteWidth) { SMP_fprintf(OutFile, "q;\n"); } else { SMP_fprintf(OutFile, " ERROR ;\n"); } } return WritesMemory; } // end of SMPInstr::MDEmitSPARKAdaStringOperation() // emit SPARK Ada for setting flags only (compare or test opcodes) void SMPInstr::MDEmitSPARKAdaCompareOrTest(FILE *OutFile) { STARS_ea_t InstAddr = this->GetAddr(); char OperatorString[10] = { '\0' }; uint16_t opcode = this->GetIDAOpcode(); bool EmitCarryFlag = false; // no carry flag for test; but yes for compare bool EmitOverflowFlag = false; // no overflow flag for test; but yes for compare bool EmitSignFlag = true; // always emit unless flag is dead bool EmitZeroFlag = true; // always emit unless flag is dead bool EmitParityFlag = true; // always emit unless flag is dead bool BitwiseAndOperation = (STARS_NN_test == opcode); bool SubtractionOperation = (STARS_NN_cmp == opcode); bool FloatingOperation = ((STARS_NN_ucomisd == opcode) || (STARS_NN_ucomiss == opcode)); bool FloatingStackOperation = this->MDIsFloatingStackCompare(); bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); assert(BitwiseAndOperation || SubtractionOperation || FloatingOperation || FloatingStackOperation); if (SubtractionOperation || FloatingOperation) { // compare opcode is subtraction based SMP_strncat(OperatorString, " - ", 4); EmitCarryFlag = true; EmitOverflowFlag = true; // will be zeroed out for FloatingOperation case } else if (BitwiseAndOperation) { // test opcode is based on bitwise AND SMP_strncat(OperatorString, " and ", 6); } else if (FloatingStackOperation) { SMP_strncat(OperatorString, " - ", 4); EmitCarryFlag = true; } else { SMP_fprintf(OutFile, "ERROR: Unknown compare or test opcode at %llx \n", (uint64_t) InstAddr); return; } // NOTE: We can optimize by analyzing which flags are actually live from this instruction. set<int> LiveFlagRegs; bool LiveFlags = this->GetBlock()->AreFlagsLiveAfterInst(InstAddr, LiveFlagRegs); if (!LiveFlags) { SMP_msg("WARNING: Compare or test inst at %llx with no live flags used after inst.\n", (uint64_t) InstAddr); } else { // Reset default flags to false. EmitCarryFlag = false; EmitZeroFlag = false; EmitSignFlag = false; EmitOverflowFlag = false; EmitParityFlag = false; for (set<int>::const_iterator FlagIter = LiveFlagRegs.cbegin(); FlagIter != LiveFlagRegs.cend(); ++FlagIter) { int FlagRegNum = (*FlagIter); switch (FlagRegNum) { case MD_CARRY_FLAG: EmitCarryFlag = true; break; case MD_ZERO_FLAG: EmitZeroFlag = true; break; case MD_SIGN_FLAG: EmitSignFlag = true; break; case MD_OVERFLOW_FLAG: EmitOverflowFlag = true; break; case MD_PARITY_FLAG: EmitParityFlag = true; break; default: SMP_msg("ERROR: Unknown live flag register %d at instruction %llx\n", FlagRegNum, (uint64_t) InstAddr); break; } } } SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); const STARSOpndTypePtr LeftOp = CurrRT->GetConstLeftOperandNoNorm(); const STARSOpndTypePtr RightOp = CurrRT->GetConstRightOperandNoNorm(); bool ReflexiveOperation = IsEqOp(LeftOp, RightOp); std::size_t LeftBitWidth = 8 * LeftOp->GetByteWidth(); // For the common case of test reg1,reg1 we emit "reg1" instead of "reg1 and reg1" below. // ZeroFlag if (EmitZeroFlag) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.ZeroFlag := (("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); if (!(ReflexiveOperation && BitwiseAndOperation)) { SMP_fprintf(OutFile, "%s", OperatorString); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); } SMP_fprintf(OutFile, ") = 0);\n"); } // SignFlag if (!FloatingStackOperation) { if (FloatingOperation) { // zero out the SignFlag PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.SignFlag := false;\n"); } else if (EmitSignFlag) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.SignFlag := (("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); if (!(ReflexiveOperation && BitwiseAndOperation)) { SMP_fprintf(OutFile, "%s", OperatorString); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); } SMP_fprintf(OutFile, ") > X86.MaxSignedInt%d);\n", LeftBitWidth); } } // ParityFlag; opaque to SPARK provers, so both results are possible if (EmitParityFlag) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.ParityFlag := X86.SetParity(X86.Unsigned64("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, "));\n"); } // CarryFlag if (!BitwiseAndOperation && EmitCarryFlag) { // cmp A,B sets CarryFlag if A < B, unsigned PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.CarryFlag := ("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " < ", OperatorString); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, ");\n"); } else if (BitwiseAndOperation) { // TEST opcode always zeroes the CarryFlag PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.CarryFlag := false;\n"); } // OverflowFlag if (EmitOverflowFlag && SubtractionOperation) { // cmp A,B sets OverflowFlag if A is positive, B is negative, but (A-B) is negative, or A/B/(A-B) are neg/pos/pos // Note that our SPARK Ada uses Unsigned values for registers, so we look at magnitudes to infer the "sign bit" PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.OverflowFlag := ((X86.SignFlag and ("); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " > X86.MaxSignedInt%d) and (", LeftBitWidth); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d))", LeftBitWidth); SMP_fprintf(OutFile, " or ((not X86.SignFlag) and ("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " > X86.MaxSignedInt%d) and (", LeftBitWidth); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d)));\n", LeftBitWidth); } else if (BitwiseAndOperation || FloatingOperation) { // TEST opcode and floating compares always zero the OverflowFlag PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.OverflowFlag := false;\n"); } return; } // end of SMPInstr::MDEmitSPARKAdaCompareOrTest() // emit SPARK Ada for ops that set flags (add, sub, etc.) void SMPInstr::MDEmitSPARKAdaArithmeticSetsCondCodes(FILE *OutFile) { STARS_ea_t InstAddr = this->GetAddr(); SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert((nullptr != CurrRT) && CurrRT->HasRightSubTree()); SMPoperator CurrOper = CurrRT->GetRightTree()->GetOperator(); bool ProcCallHandlesCondCodes = ((SMP_SUBTRACT_BORROW == CurrOper) || (SMP_ADD_CARRY == CurrOper)); // X86 package procedure will set condition codes std::string OperatorString; uint16_t opcode = this->GetIDAOpcode(); bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); bool PrefixProcCall = false; bool PrefixUnary = false; const STARSOpndTypePtr LeftOp = CurrRT->GetConstLeftOperandNoNorm(); const STARSOpndTypePtr RightOp = CurrRT->GetRightTree()->GetConstRightOperandNoNorm(); assert((nullptr != LeftOp) && (nullptr != RightOp)); std::size_t LeftBitWidth = 8 * LeftOp->GetByteWidth(); bool ConstFollows = RightOp->IsImmedOp(); bool EmitCarryFlag = true; bool EmitOverflowFlag = true; bool EmitSignFlag = true; bool EmitZeroFlag = true; bool EmitParityFlag = true; // NOTE: We can optimize by analyzing which flags are actually live from this instruction. set<int> LiveFlagRegs; bool LiveFlags = this->GetBlock()->AreFlagsLiveAfterInst(InstAddr, LiveFlagRegs); if (!LiveFlags) { SMP_msg("INFO: Arithmetic inst at %llx with no live flags used after inst.\n", (uint64_t) InstAddr); // Reset default flags to false. EmitCarryFlag = false; EmitZeroFlag = false; EmitSignFlag = false; EmitOverflowFlag = false; EmitParityFlag = false; } else { // Reset default flags to false. EmitCarryFlag = false; EmitZeroFlag = false; EmitSignFlag = false; EmitOverflowFlag = false; EmitParityFlag = false; for (set<int>::const_iterator FlagIter = LiveFlagRegs.cbegin(); FlagIter != LiveFlagRegs.cend(); ++FlagIter) { int FlagRegNum = (*FlagIter); switch (FlagRegNum) { case MD_CARRY_FLAG: EmitCarryFlag = true; break; case MD_ZERO_FLAG: EmitZeroFlag = true; break; case MD_SIGN_FLAG: EmitSignFlag = true; break; case MD_OVERFLOW_FLAG: EmitOverflowFlag = true; EmitSignFlag = true; // overflow flag depends on the sign flag break; case MD_PARITY_FLAG: EmitParityFlag = true; break; default: SMP_msg("ERROR: Unknown live flag register %d at instruction %llx\n", FlagRegNum, (uint64_t) InstAddr); break; } } // end for all LiveFlagRegs set members } PrintSPARKAdaOperator(CurrOper, OperatorString, PrefixProcCall, PrefixUnary, ConstFollows); if (!ProcCallHandlesCondCodes) { bool Subtraction = OperatorString == " - "; bool Addition = OperatorString == " + "; // ZeroFlag if (EmitZeroFlag) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.ZeroFlag := (("); if (!PrefixUnary) { this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, "%s", OperatorString.c_str()); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); } else { // unary operation like negate, bitwise not, etc. SMP_fprintf(OutFile, "%s", OperatorString.c_str()); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); } SMP_fprintf(OutFile, ") = 0);\n"); } // SignFlag if (EmitSignFlag) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.SignFlag := (("); if (!PrefixUnary) { this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, "%s", OperatorString.c_str()); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); } else { // unary operation like negate, bitwise not, etc. SMP_fprintf(OutFile, "%s", OperatorString.c_str()); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); } SMP_fprintf(OutFile, ") > X86.MaxSignedInt%d);\n", LeftBitWidth); } // ParityFlag; opaque to SPARK provers, so both results are possible if (EmitParityFlag) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.ParityFlag := X86.SetParity("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, ");\n"); } // CarryFlag if (EmitCarryFlag) { // sub A,B sets CarryFlag if A < B, unsigned; add A,B sets CarryFlag if result > MaxInt if (Subtraction) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.CarryFlag := ("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " < "); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, ");\n"); } else if (Addition) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.CarryFlag := (("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " %s ", OperatorString.c_str()); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, ") > X86.MaxUnsignedInt%d);\n", LeftBitWidth); } } // OverflowFlag if (EmitOverflowFlag) { // add or sub A,B sets OverflowFlag if A and B have the opposite sign flag from the result. // Note that our SPARK Ada uses Unsigned modulo values for registers, so we look at magnitudes to infer the "sign bit" PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.OverflowFlag := ((X86.SignFlag and ("); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, true); SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d) and (", LeftBitWidth); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, true); SMP_fprintf(OutFile, " <= X86.MaxSignedInt%d))", LeftBitWidth); SMP_fprintf(OutFile, " or ((not X86.SignFlag) and ("); this->PrintSPARKAdaOperand(LeftOp, OutFile, false, UseFP, true, true); SMP_fprintf(OutFile, " > X86.MaxSignedInt%d) and (", LeftBitWidth); this->PrintSPARKAdaOperand(RightOp, OutFile, false, UseFP, true, true); SMP_fprintf(OutFile, " > X86.MaxSignedInt%d)));\n", LeftBitWidth); } } // Now, emit the SPARK Ada for the arithmetic operation. CurrRT->EmitSPARKAda(OutFile); return; } // end of SMPInstr::MDEmitSPARKAdaArithmeticSetsCondCodes() // Emit SPARK Ada for moving a condition code value or expr into a register void SMPInstr::MDEmitSPARKAdaSetCondCodeIntoReg(FILE *OutFile) { bool ErrorFound = false; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); const STARSOpndTypePtr LeftOp = CurrRT->GetConstLeftOperandNoNorm(); std::size_t LeftOpndByteWidth = LeftOp->GetByteWidth(); bool LeftSubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > LeftOpndByteWidth); bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); // We will produce conditional assignments, Ada 2012 style: // RAX := (if (CarryFlag) then 1 else 0); // However, for subword registers, we need procedure calls to write: // X86.Write_AL(if (CarryFlag) then 1 else 0); PrintSPARKIndentTabs(OutFile); this->PrintSPARKAdaOperand(LeftOp, OutFile, true, UseFP, true, false); if (LeftSubwordWidth) { // We have printed "X86.Write_AL(" so far, in the case of LeftOp == AL, for example. SMP_fprintf(OutFile, " if "); } else { SMP_fprintf(OutFile, " := (if "); } uint16_t opcode = this->GetIDAOpcode(); switch (opcode) { case STARS_NN_seta: // Set Byte if Above (CF=0 & ZF=0) case STARS_NN_setnbe: // Set Byte if Not Below or Equal (CF=0 & ZF=0) SMP_fprintf(OutFile, "(not (X86.CarryFlag or X86.ZeroFlag))"); break; case STARS_NN_setae: // Set Byte if Above or Equal (CF=0) case STARS_NN_setnb: // Set Byte if Not Below (CF=0) case STARS_NN_setnc: // Set Byte if Not Carry (CF=0) SMP_fprintf(OutFile, "(not X86.CarryFlag)"); break; case STARS_NN_setb: // Set Byte if Below (CF=1) case STARS_NN_setc: // Set Byte if Carry (CF=1) case STARS_NN_setnae: // Set Byte if Not Above or Equal (CF=1) SMP_fprintf(OutFile, "(X86.CarryFlag)"); break; case STARS_NN_setbe: // Set Byte if Below or Equal (CF=1 | ZF=1) case STARS_NN_setna: // Set Byte if Not Above (CF=1 | ZF=1) SMP_fprintf(OutFile, "(X86.CarryFlag or X86.ZeroFlag)"); break; case STARS_NN_sete: // Set Byte if Equal (ZF=1) case STARS_NN_setz: // Set Byte if Zero (ZF=1) SMP_fprintf(OutFile, "(X86.ZeroFlag)"); break; case STARS_NN_setg: // Set Byte if Greater (ZF=0 & SF=OF) case STARS_NN_setnle: // Set Byte if Not Less or Equal (ZF=0 & SF=OF) SMP_fprintf(OutFile, "((not X86.ZeroFlag) and (X86.SignFlag = X86.OverflowFlag))"); break; case STARS_NN_setge: // Set Byte if Greater or Equal (SF=OF) case STARS_NN_setnl: // Set Byte if Not Less (SF=OF) SMP_fprintf(OutFile, "(X86.SignFlag = X86.OverflowFlag)"); break; case STARS_NN_setl: // Set Byte if Less (SF!=OF) case STARS_NN_setnge: // Set Byte if Not Greater or Equal (ZF=1) SMP_fprintf(OutFile, "(X86.SignFlag /= X86.OverflowFlag)"); break; case STARS_NN_setle: // Set Byte if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_setng: // Set Byte if Not Greater (ZF=1 | SF!=OF) SMP_fprintf(OutFile, "(X86.ZeroFlag or (X86.SignFlag /= X86.OverflowFlag))"); break; case STARS_NN_setne: // Set Byte if Not Equal (ZF=0) case STARS_NN_setnz: // Set Byte if Not Zero (ZF=0) SMP_fprintf(OutFile, "(not X86.ZeroFlag)"); break; case STARS_NN_setno: // Set Byte if Not Overflow (OF=0) SMP_fprintf(OutFile, "(not X86.OverflowFlag)"); break; case STARS_NN_setnp: // Set Byte if Not Parity (PF=0) case STARS_NN_setpo: // Set Byte if Parity Odd (PF=0) SMP_fprintf(OutFile, "(not X86.ParityFlag)"); break; case STARS_NN_setns: // Set Byte if Not Sign (SF=0) SMP_fprintf(OutFile, "(not X86.SignFlag)"); break; case STARS_NN_seto: // Set Byte if Overflow (OF=1) SMP_fprintf(OutFile, "(X86.OverflowFlag)"); break; case STARS_NN_setp: // Set Byte if Parity (PF=1) case STARS_NN_setpe: // Set Byte if Parity Even (PF=1) SMP_fprintf(OutFile, "(X86.ParityFlag)"); break; case STARS_NN_sets: // Set Byte if Sign (SF=1) SMP_fprintf(OutFile, "(X86.SignFlag)"); break; default: ErrorFound = true; SMP_fprintf(OutFile, "ERROR: Unknown set-condition-code opcode at %llx\n", (unsigned long long) this->GetAddr()); break; } // end of switch on opcode if (!ErrorFound) { SMP_fprintf(OutFile, " then 1 else 0);\n"); } return; } // end of SMPInstr::MDEmitSPARKAdaSetCondCodeIntoReg() // Emit SPARK Ada equivalent for the current conditional branch. void SMPInstr::MDEmitSPARKAdaCondition(FILE *OutFile) { uint16_t opcode = this->GetIDAOpcode(); switch (opcode) { case STARS_NN_ja: // Jump if Above (CF=0 & ZF=0) case STARS_NN_jnbe: // Jump if Not Below or Equal (CF=0 & ZF=0) case STARS_NN_cmova: // Move if Above (CF=0 & ZF=0) SMP_fprintf(OutFile, "(not (X86.CarryFlag or X86.ZeroFlag))"); break; case STARS_NN_jae: // Jump if Above or Equal (CF=0) case STARS_NN_jnb: // Jump if Not Below (CF=0) case STARS_NN_jnc: // Jump if Not Carry (CF=0) case STARS_NN_cmovnb: // Move if Not Below (CF=0) SMP_fprintf(OutFile, "(not X86.CarryFlag)"); break; case STARS_NN_jb: // Jump if Below (CF=1) case STARS_NN_jc: // Jump if Carry (CF=1) case STARS_NN_jnae: // Jump if Not Above or Equal (CF=1) case STARS_NN_cmovb: // Move if Below (CF=1) SMP_fprintf(OutFile, "(X86.CarryFlag)"); break; case STARS_NN_jbe: // Jump if Below or Equal (CF=1 | ZF=1) case STARS_NN_jna: // Jump if Not Above (CF=1 | ZF=1) case STARS_NN_cmovbe: // Move if Below or Equal (CF=1 | ZF=1) SMP_fprintf(OutFile, "(X86.CarryFlag or X86.ZeroFlag)"); break; case STARS_NN_jcxz: // Jump if CX is 0 SMP_fprintf(OutFile, "(X86.CX = 0)"); break; case STARS_NN_jecxz: // Jump if ECX is 0 SMP_fprintf(OutFile, "(X86.ECX = 0)"); break; case STARS_NN_jrcxz: // Jump if RCX is 0 SMP_fprintf(OutFile, "(X86.RCX = 0)"); break; case STARS_NN_je: // Jump if Equal (ZF=1) case STARS_NN_jz: // Jump if Zero (ZF=1) case STARS_NN_cmovz: // Move if Zero (ZF=1) SMP_fprintf(OutFile, "(X86.ZeroFlag)"); break; case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) case STARS_NN_cmovg: // Move if Greater (ZF=0 & SF=OF) SMP_fprintf(OutFile, "((not X86.ZeroFlag) and (X86.SignFlag = X86.OverflowFlag))"); break; case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) case STARS_NN_jnl: // Jump if Not Less (SF=OF) case STARS_NN_cmovge: // Move if Greater or Equal (SF=OF) SMP_fprintf(OutFile, "(X86.SignFlag = X86.OverflowFlag)"); break; case STARS_NN_jl: // Jump if Less (SF!=OF) case STARS_NN_jnge: // Jump if Not Greater or Equal (SF!=OF) case STARS_NN_cmovl: // Move if Less (SF!=OF) SMP_fprintf(OutFile, "(X86.SignFlag /= X86.OverflowFlag)"); break; case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) case STARS_NN_cmovle: // Move if Less or Equal (ZF=1 | SF!=OF) SMP_fprintf(OutFile, "(X86.ZeroFlag or (X86.SignFlag /= X86.OverflowFlag))"); break; case STARS_NN_jne: // Jump if Not Equal (ZF=0) case STARS_NN_jnz: // Jump if Not Zero (ZF=0) case STARS_NN_cmovnz: // Move if Not Zero (ZF=0) SMP_fprintf(OutFile, "(not X86.ZeroFlag)"); break; case STARS_NN_jno: // Jump if Not Overflow (OF=0) case STARS_NN_cmovno: // Move if Not Overflow (OF=0) SMP_fprintf(OutFile, "(not X86.OverflowFlag)"); break; case STARS_NN_jnp: // Jump if Not Parity (PF=0) case STARS_NN_jpo: // Jump if Parity Odd (PF=0) case STARS_NN_cmovnp: // Move if Not Parity (PF=0) SMP_fprintf(OutFile, "(not X86.ParityFlag)"); break; case STARS_NN_jns: // Jump if Not Sign (SF=0) case STARS_NN_cmovns: // Move if Not Sign (SF=0) SMP_fprintf(OutFile, "(not X86.SignFlag)"); break; case STARS_NN_jo: // Jump if Overflow (OF=1) case STARS_NN_cmovo: // Move if Overflow (OF=1) SMP_fprintf(OutFile, "(X86.OverflowFlag)"); break; case STARS_NN_jp: // Jump if Parity (PF=1) case STARS_NN_jpe: // Jump if Parity Even (PF=1) case STARS_NN_cmovp: // Move if Parity (PF=1) SMP_fprintf(OutFile, "(X86.ParityFlag)"); break; case STARS_NN_js: // Jump if Sign (SF=1) case STARS_NN_cmovs: // Move if Sign (SF=1) SMP_fprintf(OutFile, "(X86.SignFlag)"); break; default: SMP_fprintf(OutFile, "ERROR: Unknown conditional branch opcode at %llx %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm()); break; } return; } // end of SMPInstr::MDEmitSPARKAdaCondition() // Invert the condition of the current conditional branch and emit SPARK Ada equivalent. void SMPInstr::MDEmitSPARKAdaInvertedCondition(FILE *OutFile) { uint16_t opcode = this->GetIDAOpcode(); switch (opcode) { case STARS_NN_ja: // Jump if Above (CF=0 & ZF=0) case STARS_NN_jnbe: // Jump if Not Below or Equal (CF=0 & ZF=0) SMP_fprintf(OutFile, "(X86.CarryFlag or X86.ZeroFlag)"); break; case STARS_NN_jae: // Jump if Above or Equal (CF=0) case STARS_NN_jnb: // Jump if Not Below (CF=0) case STARS_NN_jnc: // Jump if Not Carry (CF=0) SMP_fprintf(OutFile, "(X86.CarryFlag)"); break; case STARS_NN_jb: // Jump if Below (CF=1) case STARS_NN_jc: // Jump if Carry (CF=1) case STARS_NN_jnae: // Jump if Not Above or Equal (CF=1) SMP_fprintf(OutFile, "(not X86.CarryFlag)"); break; case STARS_NN_jbe: // Jump if Below or Equal (CF=1 | ZF=1) case STARS_NN_jna: // Jump if Not Above (CF=1 | ZF=1) SMP_fprintf(OutFile, "(not (X86.CarryFlag or X86.ZeroFlag))"); break; case STARS_NN_jcxz: // Jump if CX is 0 SMP_fprintf(OutFile, "(X86.CX /= 0)"); break; case STARS_NN_jecxz: // Jump if ECX is 0 SMP_fprintf(OutFile, "(X86.ECX /= 0)"); break; case STARS_NN_jrcxz: // Jump if RCX is 0 SMP_fprintf(OutFile, "(X86.RCX /= 0)"); break; case STARS_NN_je: // Jump if Equal (ZF=1) case STARS_NN_jz: // Jump if Zero (ZF=1) SMP_fprintf(OutFile, "(not X86.ZeroFlag)"); break; case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) SMP_fprintf(OutFile, "(X86.ZeroFlag or (X86.SignFlag /= X86.OverflowFlag))"); break; case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) case STARS_NN_jnl: // Jump if Not Less (SF=OF) SMP_fprintf(OutFile, "(X86.SignFlag /= X86.OverflowFlag)"); break; case STARS_NN_jl: // Jump if Less (SF!=OF) case STARS_NN_jnge: // Jump if Not Greater or Equal (SF!=OF) SMP_fprintf(OutFile, "(X86.SignFlag = X86.OverflowFlag)"); break; case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) SMP_fprintf(OutFile, "((not X86.ZeroFlag) and (X86.SignFlag = X86.OverflowFlag))"); break; case STARS_NN_jne: // Jump if Not Equal (ZF=0) case STARS_NN_jnz: // Jump if Not Zero (ZF=0) SMP_fprintf(OutFile, "(X86.ZeroFlag)"); break; case STARS_NN_jno: // Jump if Not Overflow (OF=0) SMP_fprintf(OutFile, "(X86.OverflowFlag)"); break; case STARS_NN_jnp: // Jump if Not Parity (PF=0) case STARS_NN_jpo: // Jump if Parity Odd (PF=0) SMP_fprintf(OutFile, "(X86.ParityFlag)"); break; case STARS_NN_jns: // Jump if Not Sign (SF=0) SMP_fprintf(OutFile, "(X86.SignFlag)"); break; case STARS_NN_jo: // Jump if Overflow (OF=1) SMP_fprintf(OutFile, "(not X86.OverflowFlag)"); break; case STARS_NN_jp: // Jump if Parity (PF=1) case STARS_NN_jpe: // Jump if Parity Even (PF=1) SMP_fprintf(OutFile, "(not X86.ParityFlag)"); break; case STARS_NN_js: // Jump if Sign (SF=1) SMP_fprintf(OutFile, "(not X86.SignFlag)"); break; default: SMP_fprintf(OutFile, "ERROR: Unknown conditional branch opcode at %llx %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm()); break; } return; } // end of SMPInstr::MDEmitSPARKAdaInvertedCondition() // emit SPARK Ada comparison expr for current signed-compare conditional branch void SMPInstr::MDEmitSPARKAdaExprCompare(FILE *OutFile) { uint16_t opcode = this->GetIDAOpcode(); switch (opcode) { case STARS_NN_je: // Jump if Equal (ZF=1) case STARS_NN_jz: // Jump if Zero (ZF=1) SMP_fprintf(OutFile, " = "); break; case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) SMP_fprintf(OutFile, " > "); break; case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) case STARS_NN_jnl: // Jump if Not Less (SF=OF) SMP_fprintf(OutFile, " >= "); break; case STARS_NN_jl: // Jump if Less (SF!=OF) case STARS_NN_jnge: // Jump if Not Greater or Equal (SF!=OF) SMP_fprintf(OutFile, " < "); break; case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) SMP_fprintf(OutFile, " <= "); break; case STARS_NN_jne: // Jump if Not Equal (ZF=0) case STARS_NN_jnz: // Jump if Not Zero (ZF=0) SMP_fprintf(OutFile, " /= "); break; default: SMP_fprintf(OutFile, "ERROR: Unexpected signed compare conditional branch opcode at %llx %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm()); break; } return; } // end of SMPInstr::MDEmitSPARKAdaExprCompare() // emit SPARK Ada comparison expr for current unsigned-compare conditional branch void SMPInstr::MDEmitSPARKAdaExprTest(FILE *OutFile) { uint16_t opcode = this->GetIDAOpcode(); switch (opcode) { case STARS_NN_je: // Jump if Equal (ZF=1) case STARS_NN_jz: // Jump if Zero (ZF=1) SMP_fprintf(OutFile, " = "); break; case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) SMP_fprintf(OutFile, " > "); break; case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) case STARS_NN_jnl: // Jump if Not Less (SF=OF) SMP_fprintf(OutFile, " >= "); break; case STARS_NN_jl: // Jump if Less (SF!=OF) case STARS_NN_jnge: // Jump if Not Greater or Equal (SF!=OF) SMP_fprintf(OutFile, " < "); break; case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) SMP_fprintf(OutFile, " <= "); break; case STARS_NN_jne: // Jump if Not Equal (ZF=0) case STARS_NN_jnz: // Jump if Not Zero (ZF=0) SMP_fprintf(OutFile, " /= "); break; default: SMP_fprintf(OutFile, "ERROR: Unexpected unsigned compare conditional branch opcode at %llx %s\n", (unsigned long long) this->GetAddr(), this->GetDisasm()); break; } return; } // end of SMPInstr::MDEmitSPARKAdaExprTest() // return SMP_GREATER_THAN for ja and jg opcodes, etc. SMPoperator SMPInstr::MDConvertJumpToOperator(void) const { uint16_t opcode = this->GetIDAOpcode(); SMPoperator RelationalOperator = SMP_NULL_OPERATOR; switch (opcode) { case STARS_NN_ja: // Jump if Above (CF=0 & ZF=0) case STARS_NN_jnbe: // Jump if Not Below or Equal (CF=0 & ZF=0) case STARS_NN_cmova: // Move if Above (CF=0 & ZF=0) case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) case STARS_NN_cmovg: // Move if Greater (ZF=0 & SF=OF) RelationalOperator = SMP_GREATER_THAN; break; case STARS_NN_jae: // Jump if Above or Equal (CF=0) case STARS_NN_jnb: // Jump if Not Below (CF=0) case STARS_NN_jnc: // Jump if Not Carry (CF=0) case STARS_NN_cmovnb: // Move if Not Below (CF=0) case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) case STARS_NN_jnl: // Jump if Not Less (SF=OF) case STARS_NN_cmovge: // Move if Greater or Equal (SF=OF) RelationalOperator = SMP_GREATER_EQUAL; break; case STARS_NN_jb: // Jump if Below (CF=1) case STARS_NN_jc: // Jump if Carry (CF=1) case STARS_NN_jnae: // Jump if Not Above or Equal (CF=1) case STARS_NN_cmovb: // Move if Below (CF=1) case STARS_NN_jl: // Jump if Less (SF!=OF) case STARS_NN_jnge: // Jump if Not Greater or Equal (SF!=OF) case STARS_NN_cmovl: // Move if Less (SF!=OF) RelationalOperator = SMP_LESS_THAN; break; case STARS_NN_jbe: // Jump if Below or Equal (CF=1 | ZF=1) case STARS_NN_jna: // Jump if Not Above (CF=1 | ZF=1) case STARS_NN_cmovbe: // Move if Below or Equal (CF=1 | ZF=1) case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) case STARS_NN_cmovle: // Move if Less or Equal (ZF=1 | SF!=OF) RelationalOperator = SMP_LESS_EQUAL; break; case STARS_NN_jcxz: // Jump if CX is 0 break; case STARS_NN_jecxz: // Jump if ECX is 0 break; case STARS_NN_jrcxz: // Jump if RCX is 0 break; case STARS_NN_je: // Jump if Equal (ZF=1) case STARS_NN_jz: // Jump if Zero (ZF=1) case STARS_NN_cmovz: // Move if Zero (ZF=1) RelationalOperator = SMP_EQUAL; break; case STARS_NN_jne: // Jump if Not Equal (ZF=0) case STARS_NN_jnz: // Jump if Not Zero (ZF=0) case STARS_NN_cmovnz: // Move if Not Zero (ZF=0) RelationalOperator = SMP_NOT_EQUAL; break; case STARS_NN_jno: // Jump if Not Overflow (OF=0) case STARS_NN_cmovno: // Move if Not Overflow (OF=0) RelationalOperator = SMP_NOT_OVERFLOW; break; case STARS_NN_jnp: // Jump if Not Parity (PF=0) case STARS_NN_jpo: // Jump if Parity Odd (PF=0) case STARS_NN_cmovnp: // Move if Not Parity (PF=0) RelationalOperator = SMP_NOT_PARITY; break; case STARS_NN_jns: // Jump if Not Sign (SF=0) case STARS_NN_cmovns: // Move if Not Sign (SF=0) RelationalOperator = SMP_NOT_SIGN_BIT_SET; break; case STARS_NN_jo: // Jump if Overflow (OF=1) case STARS_NN_cmovo: // Move if Overflow (OF=1) RelationalOperator = SMP_OVERFLOW; break; case STARS_NN_jp: // Jump if Parity (PF=1) case STARS_NN_jpe: // Jump if Parity Even (PF=1) case STARS_NN_cmovp: // Move if Parity (PF=1) RelationalOperator = SMP_PARITY; break; case STARS_NN_js: // Jump if Sign (SF=1) case STARS_NN_cmovs: // Move if Sign (SF=1) RelationalOperator = SMP_SIGN_BIT_SET; break; default: SMP_msg("ERROR: Unknown conditional branch opcode at %llx %s\n", (uint64_t) this->GetAddr(), this->GetDisasm()); break; } return RelationalOperator; } // end of SMPInstr::MDConvertJumpToOperator() // Emit SPARK Ada Loop_Invariant pragmas at the top of each loop to assist in proofs. void SMPInstr::EmitSPARKAdaLoopInvariants(FILE *BodyFile) const { assert(this->GetBlock()->GetFunc()->TranslatingLoopToProc()); size_t LoopIndex = this->GetBlock()->GetFunc()->FindLoopNumFromHeadBlockNum(this->GetBlock()->GetNumber()); assert(LoopIndex < this->GetBlock()->GetFunc()->GetNumLoops()); if (this->GetBlock()->GetFunc()->DoesLoopUseStackPtrRegs(LoopIndex)) { // Stack pointer is loop invariant. PrintSPARKIndentTabs(BodyFile); SMP_fprintf(BodyFile, "pragma Loop_Invariant(X86.RSP = X86.RSP'Loop_Entry);\n"); if (this->GetBlock()->GetFunc()->UsesFramePointer()) { // Frame pointer is loop invariant. PrintSPARKIndentTabs(BodyFile); SMP_fprintf(BodyFile, "pragma Loop_Invariant(X86.RBP = X86.RBP'Loop_Entry);\n"); } } this->GetBlock()->GetFunc()->EmitSPARKAdaForLoopLimit(BodyFile, this->GetAddr()); this->GetBlock()->GetFunc()->EmitIncomingLoopRegExprs(BodyFile, LoopIndex, true); // Repeat the same ideas in the post-conditions. FILE *HeaderFile = global_STARS_program->GetSPARKHeaderFile(); bool PostPrintStarted = false; bool HasPreconditions = this->GetBlock()->GetFunc()->DoesLoopHavePreconditions(LoopIndex); if (this->GetBlock()->GetFunc()->DoesLoopUseStackPtrRegs(LoopIndex)) { if (!HasPreconditions) { SMP_fprintf(HeaderFile, ",\n"); // comma after Global section } SMP_fprintf(HeaderFile, "\tPost => (X86.RSP = X86.RSP'Old)"); PostPrintStarted = true; } bool MemoryRangesPrinted = false; if (this->GetBlock()->GetFunc()->DoesLoopWriteMemory(LoopIndex)) { if (this->GetBlock()->GetFunc()->UsesFramePointer()) { if (PostPrintStarted) { SMP_fprintf(HeaderFile, " and \n\t\t (X86.RBP = X86.RBP'Old)"); } else if (HasPreconditions) { SMP_fprintf(HeaderFile, "\tPost => (X86.RBP = X86.RBP'Old)"); PostPrintStarted = true; } else { SMP_fprintf(HeaderFile, ",\n\tPost => (X86.RBP = X86.RBP'Old)"); PostPrintStarted = true; } } // Print the memory writing range postcondition at the SMPFunction level. MemoryRangesPrinted = this->GetBlock()->GetFunc()->EmitSPARKLoopMemRangePostCondition(HeaderFile, BodyFile, this->GetAddr(), PostPrintStarted); if (!(MemoryRangesPrinted || PostPrintStarted)) { SMP_fprintf(HeaderFile, ";\n\n"); // No post-conditions, so emit a line separator before next procedure spec. } } else { // Just close the Globals section. SMP_fprintf(HeaderFile, ";\n\n"); } return; } // end of SMPInstr::EmitSPARKAdaLoopInvariants() // Emit SPARK-Ada translation of instruction void SMPInstr::EmitSPARKAda(FILE *OutFile) { // Print the disassembly as a comment before the SPARK translation. STARS_ea_t InstAddr = this->GetAddr(); SMP_fprintf(OutFile, "\n"); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " -- %llx %s\n", (unsigned long long) InstAddr, this->GetDisasm()); this->SetSPARKTranslated(); if (this->IsNop()) { return; } bool PrintOperands = false; bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); SMPitype CurrDataFlowType = this->GetDataFlowType(); std::string FuncTarget; STARS_ea_t NextAddr; std::size_t STARS_ISA_Bitwidth = global_STARS_program->GetSTARS_ISA_Bitwidth(); // Detect start of a loop or other control structure. if (this->IsFirstInBlock()) { #if 0 if (this->GetBlock()->GetFunc()->IsJumpFollowBlock(InstAddr)) { uint16_t NestingDepth = this->GetBlock()->GetFunc()->GetJumpToFollowNodeCounter(InstAddr); // If we only have an if-then, the counter of jumps will be zero, as we do not // increment the counter when we find the conditional jump around the then-clause. // So, we want to consider this case to have a nesting depth of one. if (0 == NestingDepth) { NestingDepth = 1; } // Now, we want to unindent and print "endif;" for each nesting level. do { --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "endif;\n"); --NestingDepth; } while (NestingDepth > 0); } #endif if (this->GetBlock()->IsLoopHeaderBlock()) { // We want to print "loop" and increase indentation. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "loop \n"); ++STARS_SPARK_IndentCount; this->EmitSPARKAdaLoopInvariants(OutFile); } } ControlFlowType FuncControlFlowType; // Treat tail calls as CALL control flows, then do the RETURN aspect as a special check // inside the CALL case. NOTE: Need special handling for conditional tail calls. if (this->IsTailCall() || this->IsCondTailCall()) { CurrDataFlowType = CALL; } switch (CurrDataFlowType) { case DEFAULT: case LABEL: case CASE: PrintOperands = true; break; case JUMP: case COND_BRANCH: // Special case first: a call instruction within a function, used as a jump // (perhaps as an internal thunk). if (this->IsCallUsedAsJump()) { // We need to translate the implicit push of the return address before falling through // to the jump translation. NextAddr = InstAddr + (STARS_ea_t) this->GetSize(); PrintSPARKIndentTabs(OutFile); // Comment out memory write of return address to speed up prover. SMP_fprintf(OutFile, " -- X86.WriteMem%d(Unsigned%d(X86.RSP - %d), 16#%llx# );\n", STARS_ISA_Bitwidth, STARS_ISA_Bitwidth, global_STARS_program->GetSTARS_ISA_Bytewidth(), (unsigned long long) NextAddr); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP - %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth()); } // Detect loop-related control flow first, then simple if-else control flow otherwise. FuncControlFlowType = this->GetBlock()->GetFunc()->GetControlFlowType(InstAddr); if (FALL_THROUGH == FuncControlFlowType) { if (COND_BRANCH == CurrDataFlowType) { SMP_fprintf(OutFile, "ERROR: Jump instruction of unknown control flow.\n"); } else { // JUMP PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "null;\n"); ; // jumps around else clauses are handled in SMPFunction::EmitSPARKAdaForConditional() } } else if (LOOP_BACK == FuncControlFlowType) { // We must be looping back to the loop header. if (JUMP == CurrDataFlowType) { // simple case --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "end loop;\n\n"); } else { // conditionally loops back, might fall out of loop if condition is false. // We want to invert the condition and exit on the inverted condition, then fall through // to an unconditional loop back (i.e. "end loop;") statement. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "exit when "); this->MDEmitSPARKAdaInvertedCondition(OutFile); SMP_fprintf(OutFile, ";\n"); // Two cases: Loop back from tail block, or loop back from optimized top-testing loop // where the header block is moved to the bottom of the loop and reached on the first // iteration by a JUMP_INTO_LOOP_TEST unconditional jump. In the tail block case, we // are ready for "end loop;" but in the header block case we need to fall through into // the second block of the loop. if (this->GetBlock()->IsLoopTailBlock()) { --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "end loop;\n\n"); } else { assert(this->GetBlock()->IsOptimizedTopLoopTest()); assert(this->GetBlock()->IsLoopHeaderBlock()); } } } else if ((LOOP_EXIT == FuncControlFlowType) || (INVERTED_LOOP_EXIT == FuncControlFlowType)) { PrintSPARKIndentTabs(OutFile); if (JUMP == CurrDataFlowType) { SMP_fprintf(OutFile, "exit;\n"); } else { // conditional SMP_fprintf(OutFile, "exit when "); if (LOOP_EXIT == FuncControlFlowType) this->MDEmitSPARKAdaCondition(OutFile); else // INVERTED_LOOP_EXIT this->MDEmitSPARKAdaInvertedCondition(OutFile); SMP_fprintf(OutFile, ";\n"); } // Check for bottom-testing loop case where we have: // loop // [instructions] // exit when [condition]; // end loop; if (this->GetBlock()->IsLoopTailBlock()) { --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "end loop;\n\n"); } } else if (CASE_BREAK_TO_FOLLOW_NODE == FuncControlFlowType) { ; // No Ada translation; next "when" keyword starts new case with implicit jump before it } else if (JUMP_TO_DEFAULT_CASE == FuncControlFlowType) { ; // No Ada translation; the "others" keyword grabs all default case values } else if ((BRANCH_IF_THEN == FuncControlFlowType) || (BRANCH_IF_THEN_ELSE == FuncControlFlowType)) { // ASM looks like: // test or compare to set condition codes // conditionally jump around the code in the if-then // We want SPARK Ada: // if (negated condition) then // EXCEPTION: An odd case for if-then is to branch to the then-block, which jumps back to the follow-block. // In this odd case, we do not invert the condition: // if (cond) goto then-code // L1: follow-block // code fragment elsewhere: then-code // goto L1 // This needs to translate to: // if (cond) then ; do not invert the condition // then-code // endif // This odd case is detected by noticing that the fall-through block has more than 1 predecessor (the extra // predecessor is the unconditional jump from the then-code to it). bool OddIfThenCase = this->IsOddIfThenCase(); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "if "); if (!OddIfThenCase) { this->MDEmitSPARKAdaInvertedCondition(OutFile); } else { this->MDEmitSPARKAdaCondition(OutFile); } SMP_fprintf(OutFile, " then \n"); ++STARS_SPARK_IndentCount; } else if ((SHORT_CIRCUIT_BRANCH == FuncControlFlowType) || (SHORT_CIRCUIT_LOOP_EXIT == FuncControlFlowType)) { // Multiple short circuit condition branches have been coalesced together. STARSCFGBlock *CurrCFGBlock = this->GetBlock()->GetFunc()->GetCFGBlockByNum((size_t) this->GetBlock()->GetNumber()); assert(NULL != CurrCFGBlock); if (!CurrCFGBlock->IsCoalesced()) { // must be header block of compound conditional; header block is where we emit output PrintSPARKIndentTabs(OutFile); if (SHORT_CIRCUIT_BRANCH == FuncControlFlowType) { SMP_fprintf(OutFile, "if not ("); CurrCFGBlock->GetExpr()->EmitSPARKAdaShortCircuitExpr(OutFile); SMP_fprintf(OutFile, ") then \n"); } else { // SHORT_CIRCUIT_LOOP_EXIT SMP_fprintf(OutFile, "exit when ("); CurrCFGBlock->GetExpr()->EmitSPARKAdaShortCircuitExpr(OutFile); SMP_fprintf(OutFile, ");\n"); // Check for bottom-testing loop case where we have: // loop // [instructions] // exit when [condition]; // end loop; if (this->GetBlock()->IsLoopTailBlock()) { --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "end loop;\n\n"); } } ++STARS_SPARK_IndentCount; } } #if 0 else if (JUMP_BEFORE_ELSE == FuncControlFlowType) { // ASM looks like: // unconditional jump around the else block to the follow block // We want to print SPARK Ada: // else // Then we want to increment the counter of jumps to the follow node. --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "else\n"); ++STARS_SPARK_IndentCount; this->GetBlock()->GetFunc()->IncrementJumpToFollowNodeCounter(InstAddr); } else if (JUMP_BEFORE_ELSIF == FuncControlFlowType) { // ASM looks like: // unconditional jump around the rest of the if-then-elsif-elsif-...-else structure to the follow node. // Currently, we treat this the same as JUMP_BEFORE_ELSE. We might pretty it up in the future. --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "else\n"); ++STARS_SPARK_IndentCount; this->GetBlock()->GetFunc()->IncrementJumpToFollowNodeCounter(InstAddr); } #endif else { SMP_fprintf(OutFile, "ERROR: Jump instruction of unknown control flow.\n"); } break; case INDIR_JUMP: // Start switch table translation. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "case "); this->PrintSPARKAdaOperand(this->RTL.GetRT(0)->GetConstRightOperandNoNorm(), OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, " is\n"); ++STARS_SPARK_IndentCount; break; case CALL: // We emit a "call foo" ASM instruction as a sequence of three SPARK Ada statements: // write return address on the stack // decrement the stack pointer // foo; (Ada form of a call to foo() NextAddr = InstAddr + (STARS_ea_t) this->GetSize(); PrintSPARKIndentTabs(OutFile); // Comment out memory write of return address to speed up prover. SMP_fprintf(OutFile, " -- X86.WriteMem%d((X86.RSP - %d), 16#%llx# );\n", STARS_ISA_Bitwidth, global_STARS_program->GetSTARS_ISA_Bytewidth(), (unsigned long long) NextAddr); FuncTarget = this->GetTrimmedCalledFunctionName(); if ((0 == FuncTarget.compare("exit")) || (0 == FuncTarget.compare("abort"))) { // The exit() call conflicts with the Ada keyword "exit." // FuncTarget = "Zephyr_exit"; // We want to set Exit_Called and return up the call chain. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.Exit_Called := true;\n"); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP + 8;\n"); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " return;\n"); } else { if (IsLibFuncName(FuncTarget)) { FuncTarget = "C_Library." + FuncTarget; // Use C_Library Ada package that we created. } PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP - %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth()); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " %s ;\n", FuncTarget.c_str()); // See if we are calling a function that might call abort() or exit(), et al., somewhere // in its call chain. STARS_ea_t TargetAddr = this->GetCallTarget(); if (STARS_BADADDR != TargetAddr) { SMPBasicBlock *CurrBlock = this->GetBlock(); SMPFunction *TargetFunc = CurrBlock->GetFunc()->GetProg()->FindFunction(TargetAddr); if (nullptr != TargetFunc) { if ((!TargetFunc->FuncReturnsToCaller()) || TargetFunc->HasCallToNonReturningFunc() || TargetFunc->HasCalleeChainWithNonReturningFunc()) { // Call chain could have set X86.Exit_Called, signalling that exit() or something similar was called. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " if X86.Exit_Called then \n"); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "\t return;\n"); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " end if;\n"); } } } } // Handle tail calls, whose data-flow type was altered from RETURN to CALL. if (this->IsTailCall() || this->IsCondTailCall()) { // We increase the stack size by 8 to swallow the return address, then // execute a SPARK Ada return instruction. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP + %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth()); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " return;\n"); } break; case INDIR_CALL: break; case RETURN: // We increase the stack size by 8 to swallow the return address, then // execute a SPARK Ada return instruction. PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " X86.RSP := X86.RSP + %d;\n", global_STARS_program->GetSTARS_ISA_Bytewidth()); PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " return;\n"); break; case HALT: break; } if (PrintOperands) { int BlockNum = this->GetBlock()->GetNumber(); int InnerLoopNum = this->GetBlock()->GetFunc()->GetInnermostLoopNum(BlockNum); if (this->HasIndirectMemoryWrite()) { // If we are in a loop, we need to emit an assertion that the memory address expression is in bounds. STARSOpndTypePtr MemDefOp = this->GetMemDef(); bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); size_t ByteWidth = MemDefOp->GetByteWidth(); #define STARS_EMIT_SPARK_LOOP_INDIRECT_WRITE_INSAFEREGION 0 if (0 <= InnerLoopNum) { // Inst is in a loop. Did we analyze memory bounds for this memory write in this loop? size_t LoopIndex = (size_t) InnerLoopNum; STARSExprBoundsIter ExprIter; SMPFunction *MyFunc = this->GetBlock()->GetFunc(); for (ExprIter = MyFunc->GetFirstLoopMemWriteExprBoundsIter(LoopIndex); ExprIter != MyFunc->GetLastLoopMemWriteExprBoundsIter(LoopIndex); ++ExprIter) { STARSExpression *LowerExpr = ExprIter->first; STARSExpression *UpperExpr = ExprIter->second; if ((nullptr != LowerExpr) && (nullptr != UpperExpr) && (InstAddr == LowerExpr->GetOriginalParentInst()->GetAddr())) { bool HasArgs = this->GetBlock()->GetFunc()->DoesLoopHaveArgs(InnerLoopNum); for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "pragma Assert(X86.InMemoryRange("); this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true); if (0 < ByteIndex) SMP_fprintf(OutFile, "+%u", ByteIndex); SMP_fprintf(OutFile, ", "); LowerExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs, true); SMP_fprintf(OutFile, ", "); UpperExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs, true); SMP_fprintf(OutFile, "));\n"); } break; // Only process expr with matching InstAddr } } // end for all LoopMemWriteBoundExprs in this inner loop #if STARS_EMIT_SPARK_LOOP_INDIRECT_WRITE_INSAFEREGION // Regardless of whether we analyzed the loop, we want to assert that // the memory write is in the safe stack region, unless it is a stack frame write. if (!MDIsStackAccessOpnd(MemDefOp, UseFP)) { for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "pragma Assert(X86.InSafeRegion64("); this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true); if (0 < ByteIndex) SMP_fprintf(OutFile, "+%u", ByteIndex); SMP_fprintf(OutFile, ", SaveStackPtr));\n"); } } #endif } else { // For indirect writes outside of loops, see if we mapped the address reg operand back to an incoming arg. // If so, emit an assert that the address reg is just a copy of the InArg. STARSInArgMap::const_iterator AddrRegInArgMapIter = this->GetBlock()->GetFunc()->GetAddressRegToInArgMapping(InstAddr); if (AddrRegInArgMapIter != this->GetBlock()->GetFunc()->GetLastAddressRegToInArgMapping()) { // If RBX maps to saved InArg RDI in a func that starts at 0x400788, we want to emit: // pragma Assert(X86.RBX = RDI_400788); // The InArg RDI will have been saved in a Ghost variable called RDI_400788 at function entry. STARSOpndTypePtr AddrRegOp = (*AddrRegInArgMapIter).second.first; STARSOpndTypePtr InArgOp = (*AddrRegInArgMapIter).second.second; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "pragma Assert("); this->PrintSPARKAdaOperand(AddrRegOp, OutFile, false, UseFP, true, false); SMP_fprintf(OutFile, "="); this->PrintSPARKAdaOperand(InArgOp, OutFile, false, UseFP, false, true); // At this point, we have "pragma Assert(RBX = RDI" and we need the "_400788" suffix SMP_fprintf(OutFile, "%s );\n", this->GetBlock()->GetFunc()->GetFuncSPARKSuffixString().c_str()); // In addition to being a copy of the InArg, we want to assert that // the memory write is in the safe stack region. for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) { PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "pragma Assert(X86.InSafeRegion64("); this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true); if (0 < ByteIndex) SMP_fprintf(OutFile, "+%u", ByteIndex); SMP_fprintf(OutFile, ", SaveStackPtr));\n"); } } } } // end if indirect memory write if (this->MDIsCompareOrTest()) { this->MDEmitSPARKAdaCompareOrTest(OutFile); } else if (this->MDIsAnySetValue()) { this->MDEmitSPARKAdaSetCondCodeIntoReg(OutFile); } else if (this->MDIsPossibleStringLoopingOpcode()) { bool WroteMemory = this->MDEmitSPARKAdaStringOperation(OutFile); if (WroteMemory && (InnerLoopNum >= 0)) { // Emit loop invariant that states that our memory range written/not-written // constraints still hold immediately after the looping string write. size_t OutputCount = 0; // first thing written STARS_sval_t IncomingStackDelta = this->GetBlock()->GetFunc()->GetLoopIncomingStackDelta((size_t) InnerLoopNum); if (0 > IncomingStackDelta) IncomingStackDelta = (0 - IncomingStackDelta); PrintSPARKIndentTabs(OutFile); this->GetBlock()->GetFunc()->EmitSPARKMemRangeLoopInvariants(OutFile, InnerLoopNum, IncomingStackDelta, false, OutputCount); } } else if (this->MDIsOverflowingOpcode() || this->MDIsUnderflowingOpcode()) { this->MDEmitSPARKAdaArithmeticSetsCondCodes(OutFile); } else { bool Conditional = this->MDIsConditionalMoveInstr(); if (Conditional) { // We allow the move to be emitted below, but surround it with if (cond) .. end if; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " if "); this->MDEmitSPARKAdaCondition(OutFile); SMP_fprintf(OutFile, " then \n"); ++STARS_SPARK_IndentCount; } SMPRegTransfer *CurrRT; for (std::size_t RTLindex = 0; RTLindex < this->RTL.GetCount(); ++RTLindex) { CurrRT = this->RTL.GetRT(RTLindex); CurrRT->EmitSPARKAda(OutFile); } if (Conditional) { --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, " end if;\n"); } } // end if (special cases) ... else ... most insts bool DoubleTailBlock = false; if (this->IsLastInstInOptimizedLoop(DoubleTailBlock)) { --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "end loop;\n\n"); if (DoubleTailBlock) { // end the outer loop also --STARS_SPARK_IndentCount; PrintSPARKIndentTabs(OutFile); SMP_fprintf(OutFile, "end loop;\n\n"); } } } // end if (PrintOperands) return; } // end of SMPInstr::EmitSPARKAda() // Equality operator for SMPInstr. Key field is address. int SMPInstr::operator==(const SMPInstr &rhs) const { if (this->GetAddr() != rhs.GetAddr()) return 0; else return 1; } // Inequality operator for SMPInstr. Key field is address. int SMPInstr::operator!=(const SMPInstr &rhs) const { return (this->GetAddr() != rhs.GetAddr()); } // Less than operator for sorting SMPInstr lists. Key field is address. int SMPInstr::operator<(const SMPInstr &rhs) const { return (this->GetAddr() < rhs.GetAddr()); } // Less than or equal operator for sorting SMPInstr lists. Key field is address. int SMPInstr::operator<=(const SMPInstr &rhs) const { return (this->GetAddr() <= rhs.GetAddr()); } #define MD_FIRST_ENTER_INSTR STARS_NN_enterw #define MD_LAST_ENTER_INSTR STARS_NN_enterq // Is this instruction one that allocates space on the // stack for the local variables? bool SMPInstr::MDIsFrameAllocInstr(void) { // The frame allocating instruction should look like: // sub esp,48 or add esp,-64 etc. STARSOpndTypePtr ESPOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG); unsigned short opcode = this->GetIDAOpcode(); if ((opcode == STARS_NN_sub) || (opcode == STARS_NN_add)) { if (this->GetLastDef() != this->Defs.FindRef(ESPOp)) { // We know that an addition or subtraction is being // performed on the stack pointer. This should not be // possible within the prologue except at the stack // frame allocation instruction, so return true. We // could be more robust in this analysis in the future. **!!** // CAUTION: If a compiler allocates 64 bytes for locals // and 16 bytes for outgoing arguments in a single // instruction: sub esp,80 // you cannot insist on finding sub esp,LocSize // To make this more robust, we are going to insist that // an allocation of stack space is either performed by // adding a negative immediate value, or by subtracting // a positive immediate value. We will throw in, free of // charge, a subtraction of a register, which is how alloca() // usually allocates stack space. set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { if (CurrUse->GetOp()->IsImmedOp()) { signed long TempImm = (signed long) CurrUse->GetOp()->GetImmedValue(); if (((0 > TempImm) && (opcode == STARS_NN_add)) || ((0 < TempImm) && (opcode == STARS_NN_sub))) { return true; } } else if (CurrUse->GetOp()->IsRegOp() && (!CurrUse->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) // skip the ESP operand && (opcode == STARS_NN_sub)) { // sub esp,reg: alloca() ? return true; } } } } else if ((opcode >= MD_FIRST_ENTER_INSTR) && (opcode <= MD_LAST_ENTER_INSTR)) { return true; } return false; } // end of SMPInstr::MDIsFrameAllocInstr() #define MD_FIRST_LEAVE_INSTR STARS_NN_leavew #define MD_LAST_LEAVE_INSTR STARS_NN_leaveq // Is this instruction in the epilogue the one that deallocates the local // vars region of the stack frame? bool SMPInstr::MDIsFrameDeallocInstr(bool UseFP, STARS_asize_t LocalVarsSize) { // The usual compiler idiom for the prologue on x86 is to // deallocate the local var space with: mov esp,ebp // It could be add esp,constant. We can be tricked by // add esp,constant when the constant is just the stack // adjustment after a call. We will have to insist that // the immediate operand have at least the value of // LocalVarsSize for this second form, and that UseFP be true // for the first form. set<DefOrUse, LessDefUse>::iterator FirstDef = this->GetFirstDef(); set<DefOrUse, LessDefUse>::iterator FirstUse = this->GetFirstUse(); unsigned short opcode = this->GetIDAOpcode(); if ((opcode >= MD_FIRST_LEAVE_INSTR) && (opcode <= MD_LAST_LEAVE_INSTR)) return true; else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand() || (!this->IsAnalyzeable())) { // Don't get fooled by USE or DEF entries of EBP or ESP that come // from memory operands, e.g. mov eax,[ebp-20] return false; } else if (UseFP && (opcode == MD_MOVE_INSTRUCTION) && (FirstDef->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) && (FirstUse->GetOp()->MatchesReg(MD_FRAME_POINTER_REG))) return true; else if ((opcode == STARS_NN_add) && (FirstDef->GetOp()->MatchesReg(MD_STACK_POINTER_REG))) { set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse; if (SecondUse == this->Uses.GetLastRef()) return false; // no more USEs ... strange for ADD instruction if (SecondUse->GetOp()->GetImmedValue() == ((STARS_uval_t) LocalVarsSize)) return true; else if (SecondUse->GetOp()->IsImmedOp()) { intptr_t TempImm = (intptr_t) this->STARSInstPtr->GetOpnd(1)->GetImmedValue(); if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc return false; else { SMP_msg("Used imprecise LocalVarsSize to find dealloc instr.\n"); return true; } } else return false; } else return false; } // end of SMPInstr::MDIsFrameDeallocInstr() // Is instruction a no-op? There are 1-byte, 2-byte, etc., versions of no-ops. bool SMPInstr::MDIsNop(void) const { bool IsNop = false; unsigned short opcode = this->GetIDAOpcode(); if ((STARS_NN_nop == opcode) || (STARS_NN_lock == opcode)) IsNop = true; else if ((MD_MOVE_INSTRUCTION == opcode) || (STARS_NN_xchg == opcode)) { if (this->STARSInstPtr->GetOpnd(0)->IsRegOp() && this->STARSInstPtr->GetOpnd(1)->MatchesReg(this->STARSInstPtr->GetOpnd(0)->GetReg())) { // We have a register to register move with source == destination, // or a register exchanged with itself. size_t BinaryByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); bool UpperBitsClear = ((BinaryByteWidth == 8) && (4 == this->STARSInstPtr->GetOpnd(0)->GetByteWidth())); if (!UpperBitsClear) { // We exclude the case of mov eax,eax on x86-64, which clears the upper 32 bits of reg RAX. IsNop = true; } } } else if (STARS_NN_lea == opcode) { bool ZeroMemOffset = (this->STARSInstPtr->GetOpnd(1)->IsMemDisplacementOp() || this->STARSInstPtr->GetOpnd(1)->IsMemNoDisplacementOp()) && (0 == this->STARSInstPtr->GetOpnd(1)->GetAddr()); if (this->STARSInstPtr->GetOpnd(0)->IsRegOp() && ZeroMemOffset) { // We are looking for 6-byte no-ops like lea esi,[esi+0] or 4-byte lea esi,[esi] STARS_regnum_t destreg = this->STARSInstPtr->GetOpnd(0)->GetReg(); if (this->STARSInstPtr->GetOpnd(1)->HasSIBByte()) { if ((destreg == (STARS_regnum_t) MD_STARS_sib_base(this->STARSInstPtr->GetOpnd(1))) && (MD_STACK_POINTER_REG == MD_STARS_sib_index(this->STARSInstPtr->GetOpnd(1)))) { // STARS_x86_R_sp signifies no SIB index register. So, we have // lea reg,[reg+0] with reg being the same in both place, // once as Operands[0] and once as the base reg in Operands[1]. IsNop = true; } } else if (destreg == this->STARSInstPtr->GetOpnd(1)->GetReg()) { // only for non-SIB case IsNop = true; } } } return IsNop; } // end of SMPInstr::MDIsNop() // instruction clears the upper bits of a reg; correct the RTL if true. bool SMPInstr::MDIsUpperBitsClear(void) { unsigned short opcode = this->GetIDAOpcode(); size_t BinaryByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); bool UpperBitsClear = (STARS_NN_mov == opcode) && ((BinaryByteWidth == 8) && (4 == this->STARSInstPtr->GetOpnd(0)->GetByteWidth())); if (UpperBitsClear) { // Correct the RTL. reg1 := reg2 becomes reg1 := (zero-extend reg2) SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(this->RTL.GetRT(0)->GetConstRightOperandNoNorm()); TempRT->SetOperator(SMP_ZERO_EXTEND); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); TempRT->SetRightOperand(VoidOp); this->RTL.GetRT(0)->SetRightOperand(VoidOp); this->RTL.GetRT(0)->SetRightTree(TempRT); } return UpperBitsClear; } // end of SMPInstr::MDIsUpperBitsClear() // Opcode always produces an UNSIGNED DEF. bool SMPInstr::MDAlwaysUnsignedDEF(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((opcode == STARS_NN_bsf) || (opcode == STARS_NN_bsr) || (opcode == STARS_NN_div) || (opcode == STARS_NN_lahf) || (opcode == STARS_NN_lar) || (opcode == STARS_NN_lgs) || (opcode == STARS_NN_lss) || (opcode == STARS_NN_lds) || (opcode == STARS_NN_les) || (opcode == STARS_NN_lfs) || (opcode == STARS_NN_lsl) || (opcode == STARS_NN_movzx) || (opcode == STARS_NN_rcl) || (opcode == STARS_NN_rcr) || (opcode == STARS_NN_rol) || (opcode == STARS_NN_ror) || (opcode == STARS_NN_shl) || (opcode == STARS_NN_shr) || ((opcode >= STARS_NN_seta) && (opcode <= STARS_NN_setz)) || (opcode == STARS_NN_cpuid) || (opcode == STARS_NN_rdtsc) || (opcode == STARS_NN_rdpmc) || (opcode == STARS_NN_fstsw) || (opcode == STARS_NN_setalc) || (opcode == STARS_NN_packuswb) || (opcode == STARS_NN_paddusb) || (opcode == STARS_NN_paddusw) || (opcode == STARS_NN_psllw) || (opcode == STARS_NN_pslld) || (opcode == STARS_NN_psllq) || (opcode == STARS_NN_psrlw) || (opcode == STARS_NN_psrld) || (opcode == STARS_NN_psrlq) || (opcode == STARS_NN_psubusb) || (opcode == STARS_NN_psubusw) || (opcode == STARS_NN_pxor) || (opcode == STARS_NN_pavgusb) || (opcode == STARS_NN_pavgb) || (opcode == STARS_NN_pavgw) || (opcode == STARS_NN_pextrw) || (opcode == STARS_NN_pmaxub) || ((opcode >= STARS_NN_pminub) && (opcode <= STARS_NN_psadbw)) || (opcode == STARS_NN_movmskpd) || (opcode == STARS_NN_pmuludq) || (opcode == STARS_NN_pslldq) || (opcode == STARS_NN_psrldq) || ((opcode >= STARS_NN_pabsb) && (opcode <= STARS_NN_pabsd)) || (opcode == STARS_NN_rdtscp) || (opcode == STARS_NN_mpsadbw) || (opcode == STARS_NN_packusdw) || ((opcode >= STARS_NN_pcmpeqq) && (opcode <= STARS_NN_phminposuw)) || (opcode == STARS_NN_pmaxud) || (opcode == STARS_NN_pmaxuw) || (opcode == STARS_NN_pminud) || (opcode == STARS_NN_pminuw) || ((opcode >= STARS_NN_pmovzxbw) && (opcode <= STARS_NN_pmovzxdq)) || ((opcode >= STARS_NN_crc32) && (opcode <= STARS_NN_pcmpistrm)) || (opcode == STARS_NN_popcnt) || (opcode == STARS_NN_lzcnt) || ((opcode >= STARS_NN_aesenc) && (opcode <= STARS_NN_aeskeygenassist))); } // end of SMPInstr::MDAlwaysUnsignedDEF() // Opcode always produces a SIGNED DEF. bool SMPInstr::MDAlwaysSignedDEF(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((opcode == STARS_NN_cbw) || (opcode == STARS_NN_cwde) || (opcode == STARS_NN_cdqe) || (opcode == STARS_NN_cwd) || (opcode == STARS_NN_cdq) || (opcode == STARS_NN_cqo) || (opcode == STARS_NN_idiv) || (opcode == STARS_NN_movsx) || (opcode == STARS_NN_neg) || (opcode == STARS_NN_sal) || (opcode == STARS_NN_sar) || (opcode == STARS_NN_fist) || (opcode == STARS_NN_fistp) || (opcode == STARS_NN_fbstp) || (opcode == STARS_NN_packsswb) || (opcode == STARS_NN_packssdw) || (opcode == STARS_NN_paddsb) || (opcode == STARS_NN_paddsw) || (opcode == STARS_NN_pmaddwd) || (opcode == STARS_NN_pmulhw) || (opcode == STARS_NN_pmullw) || (opcode == STARS_NN_psraw) || (opcode == STARS_NN_psrad) || (opcode == STARS_NN_psubsb) || (opcode == STARS_NN_psubsw) || (opcode == STARS_NN_pfadd) || (opcode == STARS_NN_pfsub) || (opcode == STARS_NN_pfsubr) || (opcode == STARS_NN_pfacc) || (opcode == STARS_NN_pfmin) || (opcode == STARS_NN_pfmax) || (opcode == STARS_NN_pf2id) || (opcode == STARS_NN_pfrcp) || (opcode == STARS_NN_pfrsqrt) || (opcode == STARS_NN_pfmul) || (opcode == STARS_NN_pfrcpit1) || (opcode == STARS_NN_pfrsqit1) || (opcode == STARS_NN_pfrcpit2) || (opcode == STARS_NN_pmulhrw) || ((opcode >= STARS_NN_addps) && (opcode <= STARS_NN_andps)) || ((opcode >= STARS_NN_cvtpi2ps) && (opcode <= STARS_NN_divss)) || ((opcode >= STARS_NN_maxps) && (opcode <= STARS_NN_movlps)) || ((opcode >= STARS_NN_movss) && (opcode <= STARS_NN_sqrtss)) || (opcode == STARS_NN_subps) || (opcode == STARS_NN_subss) || (opcode == STARS_NN_unpckhps) || (opcode == STARS_NN_unpcklps) || (opcode == STARS_NN_pmaxsw) || (opcode == STARS_NN_pminsw) || (opcode == STARS_NN_movntps) || (opcode == STARS_NN_pf2iw) || (opcode == STARS_NN_pfnacc) || (opcode == STARS_NN_pfpnacc) || (opcode == STARS_NN_pi2fw) || ((opcode >= STARS_NN_addpd) && (opcode <= STARS_NN_andpd)) || ((opcode >= STARS_NN_cvtdq2pd) && (opcode <= STARS_NN_divsd)) || (opcode == STARS_NN_maxpd) || (opcode == STARS_NN_maxsd) || ((opcode >= STARS_NN_minpd) && (opcode <= STARS_NN_movapd)) || (opcode == STARS_NN_movhpd) || (opcode == STARS_NN_movlpd) || (opcode == STARS_NN_movntpd) || ((opcode >= STARS_NN_movsd) && (opcode <= STARS_NN_orpd)) || ((opcode >= STARS_NN_sqrtpd) && (opcode <= STARS_NN_subsd)) || ((opcode >= STARS_NN_unpckhpd) && (opcode <= STARS_NN_xorpd)) || ((opcode >= STARS_NN_movddup) && (opcode <= STARS_NN_movsxd)) || ((opcode >= STARS_NN_addsubpd) && (opcode <= STARS_NN_hsubps)) || (opcode == STARS_NN_fisttp) || ((opcode >= STARS_NN_psignb) && (opcode <= STARS_NN_psignd)) || ((opcode >= STARS_NN_pmulhrsw) && (opcode <= STARS_NN_phsubd)) || (opcode == STARS_NN_pfrcpv) || (opcode == STARS_NN_pfrsqrtv) || ((opcode >= STARS_NN_blendpd) && (opcode <= STARS_NN_insertps)) || (opcode == STARS_NN_pmaxsb) || (opcode == STARS_NN_pmaxsd) || (opcode == STARS_NN_pminsb) || (opcode == STARS_NN_pminsd) || ((opcode >= STARS_NN_pmovsxbw) && (opcode <= STARS_NN_pmovsxdq)) || (opcode == STARS_NN_pmuldq) || (opcode == STARS_NN_pmulld) || ((opcode >= STARS_NN_roundpd) && (opcode <= STARS_NN_roundss)) || (opcode == STARS_NN_movntsd) || (opcode == STARS_NN_movntss)); } // end of SMPInstr::MDAlwaysSignedDEF() bool SMPInstr::MDIsAddition(void) const { unsigned short opcode = this->GetIDAOpcode(); bool FoundAddition = ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode)); if (this->MDIsLoadEffectiveAddressInstr()) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if (CurrRT->HasRightSubTree()) { CurrRT = CurrRT->GetRightTree(); FoundAddition = (SMP_ADD == CurrRT->GetOperator()); } } return FoundAddition; } // Is non-multiply arithmetic instruction that can possibly overflow? bool SMPInstr::MDIsOverflowingOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode) || (STARS_NN_inc == opcode) || (STARS_NN_neg == opcode) || (STARS_NN_xadd == opcode)); } // Is non-multiply arithmetic instruction that can possibly underflow? bool SMPInstr::MDIsUnderflowingOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_dec == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode)); } bool SMPInstr::MDIsPrefetchOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_prefetch == opcode) || (STARS_NN_prefetchw == opcode) || ((STARS_NN_prefetcht0 <= opcode) && (STARS_NN_prefetchnta >= opcode))); } bool SMPInstr::MDIsUndefinedOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); return (STARS_NN_ud2 == opcode); } // Is potentially benign overflow instruction? bool SMPInstr::MDIsMaybeBenignOverflowOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_adc == opcode) || (STARS_NN_add == opcode)); } // Is potentially benign underflow instruction? bool SMPInstr::MDIsMaybeBenignUnderflowOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_neg == opcode) || (STARS_NN_sbb == opcode) || (STARS_NN_sub == opcode)); } // Is definitely benign underflow instruction? // NOTE: Overlaps with MDIsMaybeBenignUnderflowOpcode(), so call this one first. bool SMPInstr::MDIsDefiniteBenignUnderflowOpcode(int &IdiomCode) { unsigned short opcode = this->GetIDAOpcode(); // gcc use: sbb edx,edx as a tricky way to get all zeroes or all ones into edx. // (Some sort of saturation? Often treated as 0 or -1, i.e. it becomes SIGNED // even if it used to be UNSIGNED.) // The "underflow" on the subtraction is irrelevant and benign. bool benign = ((STARS_NN_sbb == opcode) && (this->SubtractsFromItself())); if (benign) { IdiomCode = 4; } return benign; } // DEF feeds into PEASOUP project blacklist for numeric errors: loop decisions, argument passes. bool SMPInstr::HasPEASOUPBlacklistSink(bool DefReachesCall) { bool Blacklisted = false; // Check for argument passing. std::size_t ArgNum; if (DefReachesCall && this->MDIsArgumentPass(ArgNum)) { Blacklisted = true; } else if (this->GetBlock()->GetFunc()->IsBlockInAnyLoop(this->GetBlock()->GetNumber())) { // Check for loop control flow determinations. set<DefOrUse, LessDefUse>::iterator DefIter; for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { STARSOpndTypePtr DefOp = DefIter->GetOp(); if (MDIsGeneralPurposeReg(DefOp)) { int DefSSANum = DefIter->GetSSANum(); Blacklisted = this->GetBlock()->DoesDefControlLoopFlow(DefOp, DefSSANum, this->GetAddr()); if (Blacklisted) { break; } } } } return Blacklisted; } // end of SMPInstr::HasPEASOUPBlacklistSink() // Does a subtraction operator get applied to same left and right operands? bool SMPInstr::SubtractsFromItself(void) { bool SelfSubtract = false; std::size_t RTLCount = this->RTL.GetCount(); for (std::size_t index = 0; index < RTLCount; ++index) { SMPRegTransfer *CurrRT = this->RTL.GetRT(index); if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) { CurrRT = CurrRT->GetRightTree(); SMPoperator CurrOp = CurrRT->GetOperator(); if ((SMP_SUBTRACT_BORROW == CurrOp) || (SMP_SUBTRACT == CurrOp)) { if (!(CurrRT->HasRightSubTree())) { // NOTE: Must change this code when we build more precise SMP_SUBTRACT_BORROW RTL. STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); SelfSubtract = IsEqOp(RightOp, LeftOp); } break; } } } return SelfSubtract; } // end of SMPInstr::SubtractsFromItself() // Does instruction subtract an immediate value that is often used in ASCII computations, // such as the ASCII code for '0', 'a', or 'A' ? bool SMPInstr::SubtractsImmedASCII(void) { STARSOpndTypePtr SubtrahendOp = this->GetUseOnlyAddSubOp(); return (this->MDIsMaybeBenignUnderflowOpcode() && SubtrahendOp->IsImmedOp() && (('0' == SubtrahendOp->GetImmedValue()) || ('a' == SubtrahendOp->GetImmedValue()) || ('A' == SubtrahendOp->GetImmedValue()))); } // Does instruction compare a location to an immediate value that is often used in ASCII computations, // such as the ASCII code for '0' or '9', 'a' or 'A', 'z' or 'Z', or carriage return? #define SMP_ASCII_CARRIAGE_RETURN 13 bool SMPInstr::MDComparesImmedASCII(void) { bool ComparesToASCII = false; if (this->GetIDAOpcode() == STARS_NN_cmp) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) { CurrRT = CurrRT->GetRightTree(); if (!(CurrRT->HasRightSubTree())) { STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp() && ((SMP_ASCII_CARRIAGE_RETURN == RightOp->GetImmedValue()) || ('0' == RightOp->GetImmedValue()) || ('9' == RightOp->GetImmedValue()) || ('a' == RightOp->GetImmedValue()) || ('z' == RightOp->GetImmedValue()) || ('A' == RightOp->GetImmedValue()) || ('Z' == RightOp->GetImmedValue()))) { ComparesToASCII = true; } } } } return ComparesToASCII; } // end of SMPInstr::MDComparesImmedASCII() // Inst destroys original sign bit, e.g. shift left overwrites sign bit. bool SMPInstr::MDDestroysSignBit(void) const { bool SignBitDestroyed; unsigned short opcode = this->GetIDAOpcode(); SignBitDestroyed = (STARS_NN_shl == opcode); // add more cases later. return SignBitDestroyed; } // end of SMPInstr::MDDestroysSignBit() // Inst is cond branch depending only on zero/non-zero status, i.e. uses only the zero flag bool SMPInstr::MDIsZeroFlagCondBranch(void) const { unsigned short opcode = this->GetIDAOpcode(); bool ZeroFlagBranch = ((opcode == STARS_NN_je) || (opcode == STARS_NN_jne) || (opcode == STARS_NN_jz) || (opcode == STARS_NN_jnz)); return ZeroFlagBranch; } // end of SMPInstr::MDIsZeroFlagCondBranch() // Inst is x86 string opcode that can have a repeat prefix to make it loop. bool SMPInstr::MDIsPossibleStringLoopingOpcode(void) const { unsigned short opcode = this->GetIDAOpcode(); bool LoopingStringOperation = ((opcode == STARS_NN_cmps) || (opcode == STARS_NN_scas) || (opcode == STARS_NN_ins) || (opcode == STARS_NN_movs) || (opcode == STARS_NN_outs) || (opcode == STARS_NN_stos) || (opcode == STARS_NN_lods)); return LoopingStringOperation; } // end of SMPInstr::MDIsPossibleStringLoopingOpcode() // Multiply by large constant; overflow is probably intentional. #define STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD 0x20000000 #define STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD 0x10000000 #define STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD)) bool SMPInstr::IsMultiplyByLargeConstant(STARS_uval_t &ConstValue, unsigned short SignMask) { bool LargeConstFound = false; if (this->MDIsMultiply() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) { set<DefOrUse, LessDefUse>::iterator UseIter; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { if (this->FindConstantValue(UseIter, ConstValue)) { if (FG_MASK_UNSIGNED == SignMask) { if (((STARS_uval_t) STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD) <= ConstValue) { LargeConstFound = true; break; } } else if (FG_MASK_SIGNED == SignMask) { int SignedConstValue = (int) ConstValue; if ( (((int) STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD) <= SignedConstValue) || (((int) STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD) >= SignedConstValue)) { LargeConstFound = true; break; } } } } } return LargeConstFound; } // end of SMPInstr::IsMultiplyByLargeConstant() // Subtraction of large constant; underflow is probably intentional. #define STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD 0x80000000 #define STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD 0x40000000 #define STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD)) bool SMPInstr::IsSubtractionOfLargeConstant(STARS_uval_t &ConstValue, unsigned short SignMask) { bool LargeConstFound = false; if (this->MDIsUnderflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) { STARSOpndTypePtr SubtrahendOp = this->GetUseOnlyAddSubOp(); if ((nullptr != SubtrahendOp) && (! SubtrahendOp->IsVoidOp())) { set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SubtrahendOp); if (this->FindConstantValue(UseIter, ConstValue)) { if (FG_MASK_UNSIGNED == SignMask) { if (((STARS_uval_t) STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD) <= ConstValue) { LargeConstFound = true; } } else if (FG_MASK_SIGNED == SignMask) { int SignedConstValue = (int) ConstValue; if ( (((int) STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD) <= SignedConstValue) || (((int) STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD) >= SignedConstValue)) { LargeConstFound = true; } } } } } return LargeConstFound; } // end of SMPInstr::IsSubtractionOfLargeConstant() // Subtraction of large constant; underflow is probably intentional. #define STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD 0x80000000 #define STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD 0x40000000 #define STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD)) bool SMPInstr::IsAdditionOfLargeConstant(STARS_uval_t &ConstValue, unsigned short SignMask) { bool LargeConstFound = false; if (this->MDIsOverflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) { STARSOpndTypePtr AddendOp = this->GetUseOnlyAddSubOp(); if ((nullptr != AddendOp) && (!AddendOp->IsVoidOp())) { set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(AddendOp); if (this->FindConstantValue(UseIter, ConstValue)) { if (FG_MASK_UNSIGNED == SignMask) { if (((STARS_uval_t) STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD) <= ConstValue) { LargeConstFound = true; } } else if (FG_MASK_SIGNED == SignMask) { int SignedConstValue = (int) ConstValue; if ( (((int) STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD) <= SignedConstValue) || (((int) STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD) >= SignedConstValue)) { LargeConstFound = true; } } } } } return LargeConstFound; } // end of SMPInstr::IsAdditionOfLargeConstant() // MACHINE DEPENDENT: Opcode indicates 64-bit operands are the default. bool SMPInstr::MDDefaultsTo64BitOperands(void) const { return this->STARSInstPtr->OpcodeDefaultsTo64BitOperands(); } // end of SMPInstr::MDDefaultsTo64BitOperands() // MACHINE DEPENDENT: Inst has 64-bit operands bool SMPInstr::MDHas64BitOperands(void) const { return this->STARSInstPtr->Has64BitOperands(); } // MACHINE DEPENDENT: is current addressing 32-bit? bool SMPInstr::MDIsAddressing32bit(void) const { return this->STARSInstPtr->Uses32BitAddressing(); } // MACHINE DEPENDENT: is current addressing 64-bit? bool SMPInstr::MDIsAddressing64bit(void) const { return this->STARSInstPtr->Uses64BitAddressing(); } // Is current instruction the SSA marker instruction, with pseudo-address one byte before the start of the function? bool SMPInstr::IsMarkerInst(void) const { return (this->MDIsFloatNop() && STARS_IsSSAMarkerPseudoID(this->GetAddr())); } // Does RTL show a subtraction of a constant value of 1? bool SMPInstr::IsDecrementRTL(void) const { STARS_uval_t ConstValue = 0; STARSOpndTypePtr NonConstOperand = nullptr; bool ConstSubtract = this->IsSubtractionOfConstant(NonConstOperand, ConstValue); return (ConstSubtract && (1 == ConstValue)); } // stack pointer reg is in the DEFs set bool SMPInstr::HasStackPointerDEF(void) { for (STARSDefUseIter DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { STARSOpndTypePtr DefOp = DefIter->GetOp(); if (DefOp->MatchesReg(MD_STACK_POINTER_REG)) { return true; } } return false; } bool SMPInstr::IsSetToZero(void) const { bool SetsToZero = false; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if ((!CurrRT->HasRightSubTree()) && (CurrRT->GetOperator() == SMP_ASSIGN)) { STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); SetsToZero = ((RightOp->IsImmedOp()) && (0 == RightOp->GetImmedValue())); } return SetsToZero; } // MACHINE DEPENDENT: Is instruction a POP instruction? #define FIRST_POP_INST STARS_NN_pop #define LAST_POP_INST STARS_NN_popfq bool SMPInstr::MDIsPopInstr(void) const { return ((this->GetIDAOpcode() >= FIRST_POP_INST) && (this->GetIDAOpcode() <= LAST_POP_INST)); } // MACHINE DEPENDENT: Is instruction a PUSH instruction? #define FIRST_PUSH_INST STARS_NN_push #define LAST_PUSH_INST STARS_NN_pushfq bool SMPInstr::MDIsPushInstr(void) const { return ((this->GetIDAOpcode() >= FIRST_PUSH_INST) && (this->GetIDAOpcode() <= LAST_PUSH_INST)); } // MACHINE DEPENDENT: Is instruction an ENTER instruction? bool SMPInstr::MDIsEnterInstr(void) const { return ((this->GetIDAOpcode() >= MD_FIRST_ENTER_INSTR) && (this->GetIDAOpcode() <= MD_LAST_ENTER_INSTR)); } // MACHINE DEPENDENT: Is instruction a LEAVE instruction? bool SMPInstr::MDIsLeaveInstr(void) const { return ((this->GetIDAOpcode() >= MD_FIRST_LEAVE_INSTR) && (this->GetIDAOpcode() <= MD_LAST_LEAVE_INSTR)); } // MACHINE DEPENDENT: Is instruction a HALT instruction? bool SMPInstr::MDIsHaltInstr(void) const { return (STARS_NN_hlt == this->GetIDAOpcode()); } bool SMPInstr::IsJumpOrBranchInstr(void) const { // A jump is IP := address; a conditional branch is the same with a Guard RT. SMPRegTransfer *RT = this->GetRT(0); return ((1 == this->RTL.GetCount()) && (!RT->HasRightSubTree()) && RT->GetConstLeftOperandNoNorm()->MatchesReg(MD_INSTRUCTION_POINTER_REG)); // return ((STARS_NN_ja <= this->GetIDAOpcode()) && (STARS_NN_jmpshort >= this->GetIDAOpcode())); } #define MD_FIRST_LOOP_INSTR STARS_NN_loopw #define MD_LAST_LOOP_INSTR STARS_NN_loopqne bool SMPInstr::MDIsLoopInstr(void) const { uint16_t opcode = this->GetIDAOpcode(); return ((opcode >= MD_FIRST_LOOP_INSTR) && (opcode <= MD_LAST_LOOP_INSTR)); } #define MD_FIRST_COND_MOVE_INSTR STARS_NN_cmova #define MD_LAST_COND_MOVE_INSTR STARS_NN_fcmovnu // MACHINE DEPENDENT: Is instruction a conditional move? bool SMPInstr::MDIsConditionalMoveInstr(void) const { return ((this->GetIDAOpcode() >= MD_FIRST_COND_MOVE_INSTR) && (this->GetIDAOpcode() <= MD_LAST_COND_MOVE_INSTR)); } // MACHINE DEPENDENT: Is instruction any kind of move? bool SMPInstr::MDIsMoveInstr(void) const { return ((STARS_NN_mov == this->GetIDAOpcode()) || (STARS_NN_movsx == this->GetIDAOpcode()) || (STARS_NN_movzx == this->GetIDAOpcode()) || this->MDIsConditionalMoveInstr()); } // MACHINE DEPENDENT: Do opcode/operands definitely indicate signed arithmetic? // Generally, this is only true for certain variants of multiplication and division. bool SMPInstr::MDIsSignedArithmetic(void) const { unsigned short opcode = this->GetIDAOpcode(); if (STARS_NN_idiv == opcode) return true; if (STARS_NN_imul == opcode) { // If we discard the upper N bits of the multiplication result, then the // lower N bits are the same for signed and unsigned multiplication, and // gcc/g++ often use the IMUL opcode for both signed and unsigned multiplies // when only N bits of result are retained. Therefore, the SIGNED nature of // IMUL operands can only be inferred from the case in which 2N bits are kept. return (!(this->AreMultiplicationBitsDiscarded())); } else { // idiv and imul are only possible signed cases return false; } } // end of SMPInstr::MDIsSignedArithmetic() // MACHINE DEPENDENT: Is instruction a conditional jump based on an unsigned condition? bool SMPInstr::MDIsUnsignedBranch(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_ja == opcode) || (STARS_NN_jae == opcode) || (STARS_NN_jb == opcode) || (STARS_NN_jbe == opcode) || (STARS_NN_jna == opcode) || (STARS_NN_jnae == opcode) || (STARS_NN_jnb == opcode) || (STARS_NN_jnbe == opcode)); } // MACHINE DEPENDENT: Is instruction a conditional jump based on a signed condition? bool SMPInstr::MDIsSignedBranch(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_jg == opcode) || (STARS_NN_jge == opcode) || (STARS_NN_jl == opcode) || (STARS_NN_jle == opcode) || (STARS_NN_jng == opcode) || (STARS_NN_jnge == opcode) || (STARS_NN_jnl == opcode) || (STARS_NN_jnle == opcode) || (STARS_NN_js == opcode) || (STARS_NN_jns == opcode)); } // MACHINE DEPENDENT: Is instruction a boolean set based on an unsigned condition? bool SMPInstr::MDIsUnsignedSetValue(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_seta == opcode) || (STARS_NN_setae == opcode) || (STARS_NN_setb == opcode) || (STARS_NN_setbe == opcode) || (STARS_NN_setna == opcode) || (STARS_NN_setnae == opcode) || (STARS_NN_setnb == opcode) || (STARS_NN_setnbe == opcode)); } // MACHINE DEPENDENT: Is instruction a boolean set based on a signed condition? bool SMPInstr::MDIsSignedSetValue(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_setg == opcode) || (STARS_NN_setge == opcode) || (STARS_NN_setl == opcode) || (STARS_NN_setle == opcode) || (STARS_NN_setng == opcode) || (STARS_NN_setnge == opcode) || (STARS_NN_setnl == opcode) || (STARS_NN_setnle == opcode) || (STARS_NN_sets == opcode) || (STARS_NN_setns == opcode)); } // MACHINE DEPENDENT: Is instruction a boolean set based on any condition? bool SMPInstr::MDIsAnySetValue(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_seta <= opcode) && (STARS_NN_setz >= opcode)); } // MACHINE DEPENDENT: Is instruction a left shift instruction? bool SMPInstr::MDIsLeftShift(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_sal == opcode) || (STARS_NN_shl == opcode)); } // MACHINE DEPENDENT: Is instruction a right shift instruction? bool SMPInstr::MDIsRightShift(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_sar == opcode) || (STARS_NN_shr == opcode)); } // Is kind of shift or rotate that is used in hash functions #define STARS_HASH_SHIFT_THRESHOLD 4 bool SMPInstr::MDIsHashingArithmetic(void) const { bool FoundHashShift = false; unsigned short opcode = this->GetIDAOpcode(); // We are looking for shifts in the leftward direction, or rotates in either directon. bool IsRotate = ((opcode == STARS_NN_ror) || (opcode == STARS_NN_rcr) || (opcode == STARS_NN_rcl) || (opcode == STARS_NN_rol)); if (IsRotate) { FoundHashShift = true; } else if ((opcode == STARS_NN_shl) || (opcode == STARS_NN_shld)) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); do { // double-shift is a deeply nested RTL tree CurrRT = CurrRT->GetRightTree(); } while (CurrRT->HasRightSubTree()); STARSOpndTypePtr ShiftCountOp = CurrRT->GetRightOperand(); assert(nullptr != ShiftCountOp); if (ShiftCountOp->IsImmedOp()) { STARS_uval_t CountValue = ShiftCountOp->GetImmedValue(); FoundHashShift = (CountValue >= STARS_HASH_SHIFT_THRESHOLD); } else { // PEASOUP bug # 144: left shift count in CL reg, accumulates in checksum loop. FoundHashShift = true; } } return FoundHashShift; } // end of SMPInstr::MDIsHashingArithmetic() // Detect comparison of non-immediate to immediate. Return the two operands if true. bool SMPInstr::MDIsCompareToPositiveConstant(STARSOpndTypePtr &NonConstOperand, STARS_uval_t &ConstValue) const { bool CompareToConst = false; if (STARS_NN_cmp == this->GetIDAOpcode()) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); assert(!(CurrRT->HasRightSubTree())); STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { CompareToConst = true; ConstValue = (STARS_uval_t) RightOp->GetImmedValue(); NonConstOperand = CloneIfSubwordReg(LeftOp); } else if (LeftOp->IsImmedOp()) { // rare to see immediate first CompareToConst = true; ConstValue = (STARS_uval_t) LeftOp->GetImmedValue(); NonConstOperand = CloneIfSubwordReg(RightOp); } } return CompareToConst; } // end of SMPInstr::MDIsCompareToPositiveConstant() // Opcode is compare or test bool SMPInstr::MDIsCompareOrTest(void) const { uint16_t opcode = this->GetIDAOpcode(); return ((STARS_NN_cmp == opcode) || (STARS_NN_test == opcode) || (STARS_NN_ucomisd == opcode) || (STARS_NN_ucomiss == opcode) || this->MDIsFloatingStackCompare()); } // end of SMPInstr::MDIsCompareOrTest() // Opcode is comparison of FP stack regs, setting EFLAGS as result bool SMPInstr:: MDIsFloatingStackCompare(void) const { uint16_t opcode = this->GetIDAOpcode(); return ((STARS_NN_fcomi == opcode) || (STARS_NN_fcomip == opcode) || (STARS_NN_fucomi == opcode) || (STARS_NN_fucomip == opcode)); } // end of SMPInstr:: MDIsFloatingStackCompare() bool SMPInstr::IsSubtractionOfConstant(STARSOpndTypePtr &NonConstOperand, STARS_uval_t &ConstValue) const { bool SubtractOfConst = false; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if (CurrRT->HasRightSubTree()) { CurrRT = CurrRT->GetRightTree(); SMPoperator CurrOp = CurrRT->GetOperator(); if (SMP_DECREMENT == CurrOp) { assert(!(CurrRT->HasRightSubTree())); STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); SubtractOfConst = true; ConstValue = 1; NonConstOperand = LeftOp->clone(); } else if (SMP_SUBTRACT == CurrOp) { assert(!(CurrRT->HasRightSubTree())); STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { SubtractOfConst = true; ConstValue = RightOp->GetImmedValue(); NonConstOperand = LeftOp->clone(); } } else if (this->MDIsLoadEffectiveAddressInstr() && (SMP_ADD == CurrOp)) { // We could have an addition of a negative constant via an lea opcode, // e.g. lea ecx,[eax-48] will look like ecx := eax+(-48) in the RTL. if (!(CurrRT->HasRightSubTree())) { STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { ConstValue = RightOp->GetImmedValue(); int SignedConstValue = (int) ConstValue; if (0 > SignedConstValue) { SubtractOfConst = true; NonConstOperand = LeftOp->clone(); ConstValue = (STARS_uval_t)(-SignedConstValue); // make +(-x) into -(+x) } } } } } return SubtractOfConst; } // end of SMPInstr::MDIsSubtractionOfConstant() // RTL is reg := global_var_addr bool SMPInstr::IsLoadGlobalStaticDataAddress(STARS_uval_t &GlobalAddr) { SMPRegTransfer *FirstRT = this->GetRT(0); bool GlobalFound = false; if (nullptr != FirstRT) { if ((SMP_ASSIGN == FirstRT->GetOperator()) && (!FirstRT->HasRightSubTree())) { const STARSOpndTypePtr RightOp = FirstRT->GetConstRightOperandNoNorm(); if (RightOp->IsImmedOp()) { GlobalAddr = RightOp->GetImmedValue(); if (IsImmedGlobalAddress((STARS_ea_t)GlobalAddr)) { GlobalFound = true; } } } } return GlobalFound; } // end of SMPInstr::IsLoadGlobalStaticDataAddress() // RTL is simple x := x op y where op is +, -, * bool SMPInstr::IsBasicInductionVarArithmetic(STARSOpndTypePtr &RhsOperand, SMPoperator &RhsOperator) const { bool BIVOperation = false; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if (CurrRT->HasRightSubTree()) { CurrRT = CurrRT->GetRightTree(); SMPoperator CurrOp = CurrRT->GetOperator(); if (!(CurrRT->HasRightSubTree())) { if ((SMP_SUBTRACT == CurrOp) || (SMP_ADD == CurrOp) || (SMP_S_MULTIPLY == CurrOp) || (SMP_U_MULTIPLY == CurrOp)) { RhsOperator = CurrOp; RhsOperand = CurrRT->GetRightOperand(); BIVOperation = true; } else if ((SMP_S_LEFT_SHIFT == CurrOp) || (SMP_U_LEFT_SHIFT == CurrOp)) { if (CurrRT->GetRightOperand()->IsImmedOp()) { // Left shift by constant is just a multiplication RhsOperator = CurrOp; RhsOperand = CurrRT->GetRightOperand(); BIVOperation = true; } } else if ((SMP_INCREMENT == CurrOp) || (SMP_DECREMENT == CurrOp)) { // Make these special case look like SMP_ADD or SMP_SUBTRACT of immediate value 1. STARSOpndTypePtr ImmedOneOp = this->MakeImmediateOpnd(1); RhsOperand = ImmedOneOp; if (SMP_INCREMENT == CurrOp) RhsOperator = SMP_ADD; else RhsOperator = SMP_SUBTRACT; BIVOperation = true; } } } return BIVOperation; } // end of SMPInstr::IsBasicInductionVarArithmetic() // RTL is linear function Add1 + Mult1*Mult2 + Add2 or some portion of it, with nullptr returned for missing operands. bool SMPInstr::IsDependentInductionVarArithmetic(STARSOpndTypePtr &Mult1, STARSOpndTypePtr &Mult2, STARSOpndTypePtr &Add1, STARSOpndTypePtr &Add2, SMPoperator &RhsOperator) { bool DIVOperation = false; // Three cases: basic arithmetic, a copy instruction, or an LEA opcode that does multiple operations. STARSOpndTypePtr RhsOperand = nullptr; RhsOperator = SMP_NULL_OPERATOR; if (this->IsBasicInductionVarArithmetic(RhsOperand, RhsOperator)) { if ((SMP_S_MULTIPLY == RhsOperator) || (SMP_U_MULTIPLY == RhsOperator) || (SMP_S_LEFT_SHIFT == RhsOperator) || (SMP_U_LEFT_SHIFT == RhsOperator)) { Add1 = nullptr; Add2 = nullptr; Mult2 = RhsOperand; Mult1 = this->RTL.GetRT(0)->GetRightTree()->GetLeftOperand(); DIVOperation = true; } else if ((SMP_ADD == RhsOperator) || (SMP_SUBTRACT == RhsOperator)) { // Turn x + y into 1 * x + y. Mult1 = this->MakeImmediateOpnd(1); Mult2 = this->RTL.GetRT(0)->GetRightTree()->GetLeftOperand(); Add1 = RhsOperand; Add2 = nullptr; DIVOperation = true; } } else if (this->MDIsLoadEffectiveAddressInstr()) { // Need to signal our caller that we have more than one operation. RhsOperator = SMP_SIGNAL; // random junk operator STARSOpndTypePtr LeaOpnd = this->GetLeaMemUseOp(); int BaseReg, IndexReg; uint16_t Scale; STARS_ea_t offset; LeaOpnd->MDExtractAddressFields(BaseReg, IndexReg, Scale, offset); if (STARS_x86_R_none == IndexReg) { if (STARS_x86_R_none != BaseReg) { // Simple case: Lhs := BaseReg + offset STARS_uval_t ImmedValue = (STARS_uval_t) offset; Add1 = this->MakeRegOpnd((STARS_regnum_t) BaseReg); Add2 = this->MakeImmediateOpnd(ImmedValue); Mult1 = nullptr; Mult2 = nullptr; DIVOperation = true; } else { // both regs are null, e.g. PC-relative expression Add1 = nullptr; Add2 = nullptr; Mult1 = nullptr; Mult2 = nullptr; DIVOperation = false; } } else { STARS_uval_t ImmedValue = (STARS_uval_t) offset; if (BaseReg != STARS_x86_R_none) Add1 = this->MakeRegOpnd((STARS_regnum_t) BaseReg); else Add1 = nullptr; Add2 = this->MakeImmediateOpnd(ImmedValue); Mult1 = this->MakeRegOpnd((STARS_regnum_t) IndexReg); ImmedValue = (STARS_uval_t) (1 << Scale); // turn exponent into multiplier Mult2 = this->MakeImmediateOpnd(ImmedValue); DIVOperation = true; } } else if (this->IsSimpleCopy(RhsOperand)) { Add1 = nullptr; Add2 = nullptr; Mult1 = RhsOperand; STARS_uval_t ImmedValue = 1; // Assignment is multiplication by 1 Mult2 = this->MakeImmediateOpnd(ImmedValue); DIVOperation = true; } return DIVOperation; } // end of SMPInstr::IsDependentInductionVarArithmetic() // is AND operation that masks off lower BytesMasked bytes bool SMPInstr::MDIsSubregMaskInst(std::size_t &BytesMasked) { bool MaskingFound = false; if (this->MDIsBitwiseAndOpcode()) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if (CurrRT->HasRightSubTree()) { CurrRT = CurrRT->GetRightTree(); SMPoperator CurrOp = CurrRT->GetOperator(); assert(SMP_BITWISE_AND == CurrOp); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { STARS_uval_t MaskValue = RightOp->GetImmedValue(); if (0x01000000 > MaskValue) { MaskingFound = true; if (0x100 > MaskValue) { BytesMasked = 1; } else if (0x10000 > MaskValue) { BytesMasked = 2; } else { BytesMasked = 3; } } } } } return MaskingFound; } // MACHINE DEPENDENT: Does instruction use a callee-saved register? bool SMPInstr::MDUsesCalleeSavedReg(void) { set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { STARSOpndTypePtr CurrOp = CurrUse->GetOp(); if (CurrOp->MatchesReg(MD_FRAME_POINTER_REG) || CurrOp->MatchesReg(STARS_x86_R_si) || CurrOp->MatchesReg(STARS_x86_R_di) || CurrOp->MatchesReg(STARS_x86_R_bx)) { return true; } } return false; } // end of SMPInstr::MDUsesCalleeSavedReg() // Is the instruction a register to register copy of a stack pointer or frame pointer // into a general purpose register (which mmStrata will now need to track as a stack // relative pointer)? bool SMPInstr::MDIsStackPointerCopy(bool UseFP) { if (!this->HasGoodRTL()) return false; // OptType 3 indicates a move instruction // The lea instruction can perform three operand arithmetic, e.g. // lea ebx,[esp+12] is just ebx := esp+12, so it is a stack pointer copy. if (((this->GetOptType() == 3) || this->MDIsLoadEffectiveAddressInstr()) && this->IsAnalyzeable() && (this->GetFirstDef()->GetOp()->IsRegOp()) && (!(this->GetFirstDef()->GetOp()->MatchesReg(MD_STACK_POINTER_REG))) // not rsp := rsp operator opnd && (!(this->HasSourceMemoryOperand()))) { // reg to reg move set<DefOrUse, LessDefUse>::iterator UseIter = this->GetFirstUse(); if (UseIter == this->GetLastUse()) { if (!this->MDIsLoadEffectiveAddressInstr()) { // lea reg,immediate_address can have no USEs, so skip ERROR msg in that case. SMP_msg("ERROR: No first USE at %llx in MDIsStackPointerCopy\n", (unsigned long long) this->GetAddr()); } } else if (UseFP) { if (UseIter->GetOp()->MatchesReg(MD_FRAME_POINTER_REG)) // Move of base pointer EBP into a general register return true; else if ((UseIter->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) && !(this->GetFirstDef()->GetOp()->MatchesReg(MD_FRAME_POINTER_REG))) // Move of ESP into something besides a base pointer return true; } else if (this->GetFirstUse()->GetOp()->MatchesReg(MD_STACK_POINTER_REG)) { // Move of ESP into a register; no base pointer used in this function return true; } } return false; } // end of SMPInstr::MDIsStackPointerCopy() bool SMPInstr::IsStackBasedLoadEffectiveAddress(bool UseFP) const { bool StackPtrLEA = false; if (this->MDIsLoadEffectiveAddressInstr()) { StackPtrLEA = this->GetRT(0)->IsStackPtrUsedInRT(UseFP); } return StackPtrLEA; } // end of SMPInstr::IsStackBasedLoadEffectiveAddress() bool SMPInstr::IsGlobalStaticLoadEffectiveAddress(void) const { bool GlobalStatic = false; if (this->MDIsLoadEffectiveAddressInstr()) { GlobalStatic = this->GetLeaMemUseOp()->IsStaticMemOp(); } return GlobalStatic; } // end of SMPInstr::IsGlobalStaticLoadEffectiveAddress() // Does any RTL fit the alloca() pattern: stack_pointer -= non-immediate-operand bool SMPInstr::HasAllocaRTL(void) { bool FoundAlloca = false; std::size_t RTLCount = this->RTL.GetCount(); std::size_t RTLIndex; for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) { SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex); if (CurrRT->IsAllocaRTL()) { FoundAlloca = true; break; } } return FoundAlloca; } // end of SMPInstr::HasAllocaRTL() // Determine if the instruction saves or restores a pointer into the stack frame. // If it saves a stack pointer, set Save to true, set the StackDelta saved, and set // the operand that received the saved stack pointer into CopyOp. and return true. // If it restores a stack pointer, set Save to false, set CopyOp to the operand that // held the value being restored, set RestoreOp to the stack pointer or frame pointer // register (whichever was restored), leave StackDelta alone for later computation // based on reaching definitions, and return true. // For most instructions, no save or restore of a stack pointer, so return false. bool SMPInstr::MDIsStackPtrSaveOrRestore(bool UseFP, STARS_sval_t FPDelta, bool &Save, STARS_sval_t &StackDelta, STARSOpndTypePtr &CopyOp, bool &Error) { bool StackPointerSaveOrRestore = false; std::size_t RTLCount = this->RTL.GetCount(); std::size_t RTLIndex; STARSOpndTypePtr TempOp = nullptr; int BaseReg, IndexReg, CopyReg; uint16_t Scale; STARS_ea_t offset; SMPoperator CurrOper; bool LookUpStackDelta; // Get stack delta from reaching defs for TempOp STARS_sval_t DeltaAdjust; // add to StackDelta after computing from reaching defs, e.g. lea esp,[ecx-4] get TempOp of ecx // and DeltaAdjust of -4 Error = false; if ((!this->IsAnalyzeable()) || (this->GetDataFlowType() != DEFAULT)) return false; for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) { bool FPRestore = false; // frame pointer is restored bool SPRestore = false; // stack pointer is restored StackPointerSaveOrRestore = false; // default unless we detect a save or restore of the stack or frame pointer LookUpStackDelta = false; DeltaAdjust = 0; Save = false; // default unless we detect a stack pointer save // The stack alignment instructions (SP := SP bitwise_and immediate_value) // look like something that needs to be processed here, but we always ignore // these instructions. They have a variable effect on the stack pointer, from zero // to -15 delta, but we assume that the delta is zero. This works for us because // no stack accesses will occur into the padding region. // Also, any instruction that definitely does not restore the stack pointer or // frame pointer from an arbitrary register or memory location, e.g. a leave instruction // in x86 CPUs, is already handled in normal stack delta computations and needs // no lookups from reaching defs, etc. if (this->IsStackAlignmentInst() || this->MDIsLeaveInstr() || this->MDIsFrameAllocInstr()) { break; // exit and return false } SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex); CurrOper = CurrRT->GetOperator(); if (SMP_ASSIGN != CurrOper) { break; // not a regular RTL } STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); if (4 > LeftOp->GetByteWidth()) { continue; // Not tracking copies of less than the full stack or frame pointer // NOTE: We hard code 4 bytes because we will track bottom 32 bits, often seen in 64-bit code. } if (LeftOp->MatchesReg(MD_STACK_POINTER_REG)) { SPRestore = true; // temporary; might just be a push or pop RTL, etc., in which case we will reset. } else if (UseFP && LeftOp->MatchesReg(MD_FRAME_POINTER_REG)) { FPRestore = true; // likewise temporary } if (!(SPRestore || FPRestore)) { #if 0 if (LeftOp->MatchesReg(MD_FLAGS_REG)) { break; // No point in looking for a save into the flags register } #endif Save = true; // Maybe; keep looking for save } // If we are assigning to the stack pointer reg or the frame pointer reg, we need to analyze the right // hand side of the RTL to see if it is a stack/frame pointer value, and not a simple push, pop, etc. if (!(CurrRT->HasRightSubTree())) { // Simple assignment. STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsRegOp() || IsMemOperand(RightOp)) { // register or memory if (RightOp->MatchesReg(MD_STACK_POINTER_REG)) { // Stack pointer reg is being saved. Save = true; StackDelta = this->GetStackPtrOffset(); // LeftOp := SP, so saved delta is just current delta CopyOp = LeftOp; StackPointerSaveOrRestore = true; FPRestore = false; // treat FP := SP as a save of SP rather than a restoration of FP break; } else if (!SPRestore && UseFP && RightOp->MatchesReg(MD_FRAME_POINTER_REG)) { // Frame pointer is being saved Save = true; StackDelta = FPDelta; CopyOp = LeftOp; StackPointerSaveOrRestore = true; break; } else if (SPRestore || FPRestore) { // stack or frame pointer is being restored; leave Save=false and set other outgoing arguments. TempOp = RightOp; CopyOp = RightOp; StackPointerSaveOrRestore = true; LookUpStackDelta = true; } else { // RightOp is register or non-stack-pointer memory expr; either might hold stack delta TempOp = RightOp; CopyOp = LeftOp; LookUpStackDelta = true; // See if RightOp is holding a stack delta StackPointerSaveOrRestore = true; // Maybe; flag tells us to keep looking } } else { if (SPRestore || FPRestore) { SMP_msg("ERROR: Invalid operand type for assignment to stack or frame pointer at %llx\n", (unsigned long long) this->GetAddr()); } StackPointerSaveOrRestore = false; break; } } else { // we have a right subtree in the CurrRT SMPRegTransfer *RightRT = CurrRT->GetRightTree(); // In order to have a right subtree, we must have something like: // lea esp,[ecx-4] which produces the RTL: esp := ecx - 4 // We should consider any other RTL structure besides a basic addition or // subtraction on the right subtree to be invalid. CurrOper = RightRT->GetOperator(); if ((SMP_ADD == CurrOper) || (SMP_SUBTRACT == CurrOper)) { STARSOpndTypePtr RightLeftOp = RightRT->GetLeftOperand(); if (RightLeftOp->IsRegOp()) { if (RightRT->HasRightSubTree()) { // Complex RTL such as lea esp,[ebx+ecx*4] ; cannot analyze StackPointerSaveOrRestore = false; } else { STARSOpndTypePtr RightRightOp = RightRT->GetRightOperand(); if (!RightRightOp->IsImmedOp()) { // Complex RTL such as lea esp,[ebx+ecx] ; cannot analyze StackPointerSaveOrRestore = false; } else { TempOp = RightLeftOp; DeltaAdjust = (STARS_sval_t) RightRightOp->GetImmedValue(); if ((STARS_uval_t) DeltaAdjust > STARS_ESP_ADDITION_OVERFLOW_THRESHOLD) { // Really a subtraction via addition of a negative, // or addition via subtraction of a negative. // E.g. add esp, 0xfffffff0 is sub esp,16 and sub esp,0xfffffff0 is add esp,16 int32_t TempDelta = (int32_t) (DeltaAdjust & 0xffffffff); DeltaAdjust = (STARS_sval_t) TempDelta; } if (SMP_SUBTRACT == CurrOper) { // Negate the stack delta adjustment, e.g. lea esp,[ecx-4] needs DeltaAdjust of -4, not 4. DeltaAdjust = (0 - DeltaAdjust); } LookUpStackDelta = true; StackPointerSaveOrRestore = true; if (SPRestore || FPRestore) { CopyOp = RightLeftOp; } else { CopyOp = LeftOp; } } } } else { // weird RTL; LeftOp := (MemoryOp OPER ???) StackPointerSaveOrRestore = false; } } else { // not ADD or SUBTRACT StackPointerSaveOrRestore = false; } } if (LookUpStackDelta) { bool StackAccess = false; bool NonStackMemAccess = false; // We need to set StackDelta based on the reaching defs for TempOp // A reg is probably a general register, but could have lea ebx,[esp+4] so it could be stack or frame pointer. if (TempOp->MatchesReg(MD_STACK_POINTER_REG)) { // Weed out RTs that increment or decrement the stack pointer, e.g. SP := SP -4. // These are not the kind of "save" or "restore" RTs that we are tracking. if (CopyOp->MatchesReg(MD_STACK_POINTER_REG)) { StackPointerSaveOrRestore = false; SPRestore = false; FPRestore = false; Save = false; } else { StackDelta = this->GetStackPtrOffset(); StackDelta += DeltaAdjust; LookUpStackDelta = false; // just got it; no need for reaching defs StackPointerSaveOrRestore = true; } } else if (UseFP && TempOp->MatchesReg(MD_FRAME_POINTER_REG)) { StackDelta = FPDelta; StackDelta += DeltaAdjust; LookUpStackDelta = false; // just got it; no need for reaching defs StackPointerSaveOrRestore = true; } else if (TempOp->IsRegOp()) { // general reg, not frame or stack pointer reg CopyReg = TempOp->GetReg(); } else { MDExtractAddressFields(TempOp, BaseReg, IndexReg, Scale, offset); CopyReg = BaseReg; bool IndexedAccess = ((STARS_x86_R_none != BaseReg) && (STARS_x86_R_none != IndexReg)); if (IndexedAccess) { StackPointerSaveOrRestore = false; // Cannot analyze indexed accesses into the stack } else if (MDIsStackPtrReg(BaseReg, UseFP)) { StackAccess = true; } else { // memory expr that is not stack or frame pointer NonStackMemAccess = true; // something like [ecx] might actually turn out to be stack access DeltaAdjust = (STARS_sval_t) TempOp->GetAddr(); // get normalized delta from addr field } } if (StackPointerSaveOrRestore && LookUpStackDelta) { STARSOpndTypePtr FindOp = nullptr; if (StackAccess || NonStackMemAccess) { FindOp = TempOp; } else { FindOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) CopyReg); } if (this->GetBlock()->GetFunc()->IsInStackPtrCopySet(FindOp)) { // Screened out time wasters that are not in copy set; now, // look up reaching defs. // We need to find out which are the reaching definitions for the FindOp at the current InstAddr. this->GetBlock()->GetFunc()->ComputeTempReachingDefs(FindOp, this->GetAddr()); this->GetBlock()->GetFunc()->ComputeTempStackDeltaReachesList(FindOp); // See if TempStackDeltaReachesList has a consistent delta value. StackPointerSaveOrRestore = this->GetBlock()->GetFunc()->FindReachingStackDelta(StackDelta); // consistent SavedDelta value across entire list StackDelta += DeltaAdjust; if (StackPointerSaveOrRestore && NonStackMemAccess) { // We have something like [ecx] or [ecx+DeltaAdjust]. It turns out that // ECX has a copy of the stack pointer or frame pointer in it, but that // does not mean that the memory location [ecx] has a copy of a stack or // frame pointer. We need to look up the normalized stack address [esp+StackDelta] // in the StackPtrCopySet just like we did for ECX before we conclude that a // stack pointer save or restore is happening. FindOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, (STARS_ea_t) StackDelta); if (this->GetBlock()->GetFunc()->IsInStackPtrCopySet(FindOp)) { // Screened out time wasters that are not in copy set; now, // look up reaching defs. // We need to find out which are the reaching definitions for the FindOp at the current InstAddr. this->GetBlock()->GetFunc()->ComputeTempReachingDefs(FindOp, this->GetAddr()); this->GetBlock()->GetFunc()->ComputeTempStackDeltaReachesList(FindOp); // See if TempStackDeltaReachesList has a consistent delta value. StackPointerSaveOrRestore = this->GetBlock()->GetFunc()->FindReachingStackDelta(StackDelta); // consistent SavedDelta value across entire list // StackPointerSaveOrRestore will now be true only if [ecx] pointed to a saved stack or frame pointer with consistent delta. } else { // E.g. [ecx] pointed to stack location that was not holding a saved stack or frame pointer. StackPointerSaveOrRestore = false; } } } else { StackPointerSaveOrRestore = false; // reset, not in stack pointer copy set } } } // end if (LookupStackDelta) if (!StackPointerSaveOrRestore && !Save && (SPRestore || FPRestore)) { // Any restore that could not be analyzed is an error. Error = true; break; // error exit } else if (StackPointerSaveOrRestore) { if (FPRestore) { // If we succeeded in looking up a stack delta that goes into the frame pointer reg, // then we want to consider this instruction to be a save of a stack delta into // a register (which happens to be the frame pointer reg in this case). FPRestore = false; Save = true; } break; // assume only one save or restore in an instruction; exit with success } } // end for all RTs in the RTL return StackPointerSaveOrRestore; } // end of SMPInstr::MDIsStackPtrSaveOrRestore() // return true if current inst mem write is unsafe, false otherwise bool SMPInstr::DetectUnsafeMemWrite(void) { bool UnsafeWrite = false; STARS_ea_t InstAddr = this->GetAddr(); if (this->HasIndirectMemoryWrite()) { this->GetBlock()->GetFunc()->ResetProcessedBlocks(); set<DefOrUse, LessDefUse> SearchDEFs; bool FoundAddressRegs = this->GetAddressRegs(SearchDEFs); assert(FoundAddressRegs); assert(!SearchDEFs.empty()); // Pre-screen SearchDEFs for unsafe criteria before calling IsMemWriteUnsafe(). STARSDefUseIter UseIter = SearchDEFs.begin(); while (UseIter != SearchDEFs.end()) { bool Prescreened = this->GetBlock()->PrescreenUnsafeAddrReg(UseIter, InstAddr); if (Prescreened) { UseIter = SearchDEFs.erase(UseIter); UnsafeWrite = true; } else { ++UseIter; } } if (!UnsafeWrite) { UnsafeWrite = this->GetBlock()->IsMemWriteUnsafe(this->GetAddr(), true, SearchDEFs); } SearchDEFs.clear(); } this->SetAnalyzedWriteSafety(); return UnsafeWrite; } // end of SMPInstr::DetectUnsafeMemWrite() // Make list of regs and their stack offsets in RTLs for any push instruction bool SMPInstr::GetPushedRegsList(map<uint32_t, STARS_sval_t> &PushedRegs) { std::size_t RTLCount = this->RTL.GetCount(); std::size_t RTLIndex; STARSOpndTypePtr LeftOp = nullptr, RightOp = nullptr; int BaseReg, IndexReg; uint16_t Scale; STARS_ea_t offset; SMPoperator CurrOper; for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) { SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex); CurrOper = CurrRT->GetOperator(); // Only process simple pushes of registers LeftOp = CurrRT->GetLeftOperand(); if (MDIsStackAccessOpnd(LeftOp, false) && (!(CurrRT->HasRightSubTree())) && (SMP_ASSIGN == CurrOper)) { RightOp = CurrRT->GetRightOperand(); if (RightOp->IsRegOp()) { MDExtractAddressFields(LeftOp, BaseReg, IndexReg, Scale, offset); // Exclude indexed stack writes. if (STARS_x86_R_none == IndexReg) { STARS_sval_t ESPOffset = (STARS_sval_t) offset; map<uint32_t, STARS_sval_t>::iterator FindIter = PushedRegs.find((uint32_t) RightOp->GetReg()); if (FindIter == PushedRegs.end()) { // Not already pushed earlier pair<uint32_t, STARS_sval_t> TempPair((uint32_t) RightOp->GetReg(), ESPOffset); pair<map<uint32_t, STARS_sval_t>::iterator, bool> InsertResult; InsertResult = PushedRegs.insert(TempPair); assert(InsertResult.second); } } } } } // end for all RTs in RTL return (!PushedRegs.empty()); } // end of SMPInstr::GetPushedRegsList() // Make list of regs and their stack offsets in RTLs for any pop instruction bool SMPInstr::GetPoppedRegsList(bool FirstReturnBlock, map<uint32_t, STARS_sval_t> &PoppedRegs) { bool MisMatch = false; std::size_t RTLCount = this->RTL.GetCount(); std::size_t RTLIndex; std::size_t IncomingSize = PoppedRegs.size(); // from return blocks already processed std::size_t MatchCount = 0; // count of matches to incoming data STARSOpndTypePtr LeftOp = nullptr, RightOp = nullptr; int BaseReg, IndexReg; uint16_t Scale; STARS_ea_t offset; SMPoperator CurrOper; for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) { SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex); CurrOper = CurrRT->GetOperator(); // Only process simple pops of registers LeftOp = CurrRT->GetLeftOperand(); if ((LeftOp->IsRegOp()) && (!(CurrRT->HasRightSubTree())) && (SMP_ASSIGN == CurrOper)) { RightOp = CurrRT->GetRightOperand(); if (MDIsStackAccessOpnd(RightOp, false)) { MDExtractAddressFields(RightOp, BaseReg, IndexReg, Scale, offset); // Exclude indexed stack reads. if (STARS_x86_R_none == IndexReg) { STARS_sval_t ESPOffset = (STARS_sval_t) offset; map<uint32_t, STARS_sval_t>::iterator FindIter = PoppedRegs.find((uint32_t) LeftOp->GetReg()); if (FindIter == PoppedRegs.end()) { // Not already popped in another block if (FirstReturnBlock) { pair<uint32_t, STARS_sval_t> TempPair((uint32_t) LeftOp->GetReg(), ESPOffset); pair<map<uint32_t, STARS_sval_t>::iterator, bool> InsertResult; InsertResult = PoppedRegs.insert(TempPair); assert(InsertResult.second); } else { // We should not find a new pop in return block N not seen in return block N-1 MisMatch = true; PoppedRegs.clear(); // causes a return value of false break; } } else { // Already in map; check for consistency across return points. if (ESPOffset != FindIter->second) { // inconsistent MisMatch = true; PoppedRegs.clear(); // causes a return value of false break; } else { ++MatchCount; } } } } } } // end for all RTs in RTL if (FirstReturnBlock) { IncomingSize = 0; // Not trying to match within first return block } return ((!MisMatch) && (!PoppedRegs.empty())); } // end of SMPInstr::GetPoppedRegsList() // If call instruction is to malloc(), set the DEF register EAX type to // HEAPPTR and return true. bool SMPInstr::MDFindMallocCall(const STARSOpndTypePtr &TargetOp) { bool changed = false; STARS_Function_t *TargetFunc = SMP_get_func(TargetOp->GetAddr()); #if 0 if (TargetFunc) { #endif string FuncName = this->GetTrimmedCalledFunctionName(); if (0 == strcmp("malloc", FuncName.c_str())) { #if SMP_VERBOSE_FIND_POINTERS SMP_msg("Found call to malloc at %x\n", this->GetAddr()); #endif this->GetBlock()->GetFunc()->SetHasMallocCall(); STARSOpndTypePtr SearchOp = this->STARSInstPtr->MakeRegOpnd(MD_RETURN_VALUE_REG); set<DefOrUse, LessDefUse>::iterator EAXDEF = this->SetDefType(SearchOp, HEAPPTR); int SSANum = EAXDEF->GetSSANum(); changed = true; if (this->BasicBlock->IsLocalName(SearchOp)) { (void) this->BasicBlock->PropagateLocalDefType(SearchOp, HEAPPTR, this->GetAddr(), SSANum, false); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(SearchOp, HEAPPTR, SSANum, false, false); } } // end if "malloc" #if 0 } // end if (TargetFunc) #endif return changed; } // end of SMPInstr::MDFindMallocCall() // Is instruction a branch (conditional or unconditional) to a // code target that is not in the current chunk? bool SMPInstr::IsBranchToFarChunk(void) { if (this->IsFarBranchComputed()) { // answer is cached return this->IsBranchesToFarChunk(); } bool FarBranch = false; if ((JUMP | COND_BRANCH) & this->GetDataFlowType()) { // Instruction is a direct branch, conditional or unconditional if (this->NumUses() > 0) { FarBranch = this->STARSInstPtr->IsBranchToFarChunk(this, this->FarBranchTarget); if (FarBranch) { this->SetBranchesToFarChunk(); } } } this->SetFarBranchComputed(); return FarBranch; } // end of SMPInstr::IsBranchToFarChunk() // instr branches or jumps to another function bool SMPInstr::IsBranchToOtherFunc(void) { bool Safe = (NULL != this->GetBlock()); STARS_ea_t FarTarget = this->GetJumpTarget(); return (Safe && (STARS_BADADDR != FarTarget) && (!this->GetBlock()->GetFunc()->IsInstIDInFunc(FarTarget))); } // is poorly-optimized if-then COND_BRANCH with extra jumps bool SMPInstr::IsOddIfThenCase(void) const { // The common case is to jump around the ThenBlock, which can then fall through to the FollowBlock: // if (cond) then goto L1; // then-block // L1: // However, it is also possible to jump to the ThenBlock, which then jumps or falls through to the FollowBlock: // if (cond) then goto L2; // L1: // somewhere else: L2: then-block // goto L1 // This could be odd code generation or hand-written code. // In this odd case, the FallThroughBlock has more than 1 predecessor. In the normal case, the // FallThroughBlock has only one predecessor (the COND_BRANCH block falls through to it). We can use // the number of predecessor blocks to distinguish the two cases, with the additional limitation // that one predecessor reaches the fall-through block via unconditional direct jump. bool OddIfThenCase = false; SMPBasicBlock *CurrBlock = this->GetBlock(); STARS_ea_t InstAddr = this->GetAddr(); ControlFlowType FuncControlFlowType = CurrBlock->GetFunc()->GetControlFlowType(InstAddr); if (BRANCH_IF_THEN == FuncControlFlowType) { list<SMPBasicBlock *>::const_iterator SuccIter = CurrBlock->GetFallThroughSucc(); assert(SuccIter != CurrBlock->GetLastConstSucc()); size_t PredCount = (*SuccIter)->GetNumPredsMinusBackEdges(); // Don't let loop-back edges increase the PredCount, e.g.: // if cond then // loop // [loop body] // end loop; // ... // end if; // The normal if-then case will fall through to a loop header block, and branch to the follow block // for the if-then. That is not the odd case. OddIfThenCase = (1 < PredCount); // fall-through block has more than 1 predecessor #if 1 // See if we have an unconditional jump to the fall-through block. if (OddIfThenCase) { OddIfThenCase = false; for (list<SMPBasicBlock *>::const_iterator PredIter = (*SuccIter)->GetFirstConstPred(); PredIter != (*SuccIter)->GetLastConstPred(); ++PredIter) { if ((*PredIter)->HasDirectJump()) { OddIfThenCase = true; break; } } if (!OddIfThenCase) { SMP_msg("INFO: SMPInstr::IsOddIfThenCase() false due to second criterion at %llx in func %s\n", (uint64_t) InstAddr, this->GetBlock()->GetFunc()->GetFuncName()); } } #endif } return OddIfThenCase; } // end of SMPInstr::IsOddIfThenCase() set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseSSA(const STARSOpndTypePtr &CurrOp, int SSASub) { return this->Uses.SetSSANum(CurrOp, SSASub); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefSSA(const STARSOpndTypePtr &CurrOp, int SSASub) { return this->Defs.SetSSANum(CurrOp, SSASub); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseType(const STARSOpndTypePtr &CurrOp, SMPOperandType CurrType) { return this->Uses.SetType(CurrOp, CurrType, this); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefType(const STARSOpndTypePtr &CurrOp, SMPOperandType CurrType) { return this->Defs.SetType(CurrOp, CurrType, this); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefMetadata(const STARSOpndTypePtr &CurrOp, SMPMetadataType Status) { return this->Defs.SetMetadata(CurrOp, Status); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefIndWrite(const STARSOpndTypePtr &CurrOp, bool IndWriteFlag) { return this->Defs.SetIndWrite(CurrOp, IndWriteFlag); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefLoopInvariant(const STARSOpndTypePtr &CurrOp) { return this->Defs.SetLoopInvariant(CurrOp); }; STARSDefUseIter SMPInstr::SetDefSafeMemWrite(const STARSOpndTypePtr &CurrOp) { return this->Defs.SetSafeMemWrite(CurrOp); } set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseNoTruncate(const STARSOpndTypePtr &CurrOp, bool NoTruncFlag) { return this->Uses.SetNoTruncation(CurrOp, NoTruncFlag); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefNoOverflow(const STARSOpndTypePtr &DefOp, bool NoOverflowFlag) { return this->Defs.SetNoOverflow(DefOp, NoOverflowFlag); }; // Set the DeadRegsBitmap entry for Regnum. void SMPInstr::SetRegDead(std::size_t RegNum) { this->DeadRegsBitmap.set(RegNum); return; } bool SMPInstr::FillCmd(void) { // Fill cmd structure with disassembly of instr assert(STARS_SSA_MARKER_PSEUDO_ID != this->GetAddr()); return this->STARSInstPtr->STARS_GetCmd(); } // Analyze the instruction and its operands. void SMPInstr::Analyze(void) { bool DebugFlag = false; if (0x8049b00 == this->GetAddr()) { // Setting up breakpoint line. DebugFlag = true; } if (!(this->FillCmd())) return; size_t BinaryByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); uint16_t opcode = this->GetIDAOpcode(); // Record what type of instruction this is, simplified for the needs // of data flow and type analysis. this->type = DFACategory[opcode]; // Record optimization category. // this->OptType = global_STARS_program->GetOptCategory(opcode); if ((STARS_NN_int == opcode) || (STARS_NN_into == opcode) || (STARS_NN_int3 == opcode)) { this->SetInterrupt(); } else { this->ResetInterrupt(); } // Fix the IDA Pro mistakes in the operand list. this->MDFixupIDAProOperandList(); // See if instruction is an ASM idiom for clearing a register. if ((STARS_NN_xor == opcode) || (STARS_NN_lea == opcode) || (STARS_NN_pxor == opcode)) { STARSOpndTypePtr FirstOpnd = this->STARSInstPtr->GetOpnd(0); STARSOpndTypePtr SecondOpnd = this->STARSInstPtr->GetOpnd(1); if (!(FirstOpnd->IsMemOp() || FirstOpnd->IsNearPointer() || FirstOpnd->IsFarPointer())) { if ((STARS_NN_xor == opcode) || (STARS_NN_pxor == opcode)) { // Check for xor of reg with itself // NOTE: We code with IsEqOp() instead of MatchesReg() because we want to include // odd reg types like xmm, ymm, mmx, etc. if (IsEqOp(FirstOpnd, SecondOpnd)) { if (FirstOpnd->GetByteWidth() >= 4) { // xor using 1-byte or 2-byte regs does not clear the upper bits, // so those are not reg clear idioms. 4-byte xor reg1,reg1 is a clear // of the entire reg1, even on x86-64, e.g. xor eax,eax is a shorter way // of encoding xor rax,rax or mov rax,0. this->SetRegClearIdiom(); } } } else { // must be lea // check for lea reg,[nobasereg+noindexreg+0] if (SecondOpnd->IsMemOp()) { int BaseReg, IndexReg; uint16_t ScaleFactor; STARS_ea_t Offset; MDExtractAddressFields(SecondOpnd, BaseReg, IndexReg, ScaleFactor, Offset); if ((STARS_x86_R_none == BaseReg) && (STARS_x86_R_none == IndexReg) && (0 == Offset)) { this->SetRegClearIdiom(); } } } } } // See if instruction is simple nop or ASM idiom for nop. if (this->MDIsNop()) { this->SetNop(); } // Build the tree RTL for the inst. this->FindMemOps(); bool GoodRTL = this->BuildRTL(); if (GoodRTL) { this->SetGoodRTL(); this->MDFixFloatingPointRTL(); } else { SMP_msg("ERROR: RTL not built at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); return; } if (this->MDIsUpperBitsClear()) { this->SetRegUpperBitsClearIdiom(); // SMP_msg("INFO: Found x86-64 upper-bits-clear idiom at %p and fixed RTL.\n", this->GetAddr()); } // Build the DEF and USE lists for the instruction. this->BuildSMPDefUseLists(); // Determine whether the instruction is a jump target by looking // at its cross references and seeing if it has "TO" code xrefs. if (global_stars_interface->IsInstJumpTarget(this->GetInstID())) { this->SetJumpTarget(); } // If instruction is a call or indirect call, see if a call target has been recorded // by IDA Pro. if (this->GetDataFlowType() == INDIR_CALL) { if (this->MDIsSystemCall()) { this->CallTarget = STARS_BADADDR; if (NULL != this->GetBlock()) { this->GetBlock()->GetFunc()->SetHasSystemCalls(); } } else { STARS_InstructionID_t CallTargetInstID = global_stars_interface->FindFirstCallTarget(this->GetInstID()); this->CallTarget = CallTargetInstID.GetIDWithinFile(); } } // end if INDIR_CALL else if (this->GetDataFlowType() == CALL) { set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { if (CurrUse->GetOp()->IsNearPointer() || CurrUse->GetOp()->IsFarPointer()) { this->CallTarget = CurrUse->GetOp()->GetAddr(); } } if (STARS_BADADDR == this->CallTarget) { SMP_msg("ERROR: Target not found for direct call at %llx\n", (unsigned long long) this->GetAddr()); } } if (this->MDIsPushInstr()) { if (this->STARSInstPtr->IsPushFromFixedCall()) { this->SetFixedCallPush(); SMP_msg("INFO: Found internal code address push from fixed call at %llx\n", (unsigned long long) this->GetAddr()); } } if (DebugFlag) { SMP_msg("Analyzed debug instruction at %llx\n", (unsigned long long) this->GetAddr()); } return; } // end of SMPInstr::Analyze() // Analyze the floating point NOP marker instruction at the top of the function. void SMPInstr::AnalyzeMarker(void) { // Set the instr disassembly text. DisAsmText.SetMarkerInstText(this->GetAddr()); // Record what type of instruction this is, simplified for the needs // of data flow and type analysis. this->type = DFACategory[this->GetIDAOpcode()]; // Record optimization category. // this->OptType = global_STARS_program->GetOptCategory(this->GetIDAOpcode()); bool GoodRTL = BuildRTL(); if (GoodRTL) { this->SetGoodRTL(); } return; } // end of SMPInstr::AnalyzeMarker() // fix machine-specific FP reg encodings void SMPInstr::MDFixFloatingPointRTL(void) { for (size_t RTindex = 0; RTindex < this->RTL.GetCount(); ++RTindex) { this->RTL.GetRT(RTindex)->MDFixFloatingPointRTL(); } return; } // Detect oddities of call instructions, such as pseudo-calls that are // actually jumps within a function void SMPInstr::AnalyzeCallInst(STARS_ea_t FirstFuncAddr) { STARS_ea_t TargetAddr = this->GetCallTarget(); if (STARS_BADADDR != TargetAddr) { if (this->GetCallTarget() == FirstFuncAddr) { this->SetDirectRecursiveCall(); } else { this->ResetDirectRecursiveCall(); if (this->GetBlock()->GetFunc()->IsInstIDInFunc(TargetAddr)) { this->SetCallUsedAsJump(); // Remove the call target from the sets and lists in the function. bool Removed; if (CALL == this->GetDataFlowType()) { set<STARS_ea_t>::iterator NextTarget = this->GetBlock()->GetFunc()->RemoveDirectCallTarget(TargetAddr); } else if (INDIR_CALL == this->GetDataFlowType()) { Removed = this->GetBlock()->GetFunc()->RemoveIndirectCallTarget(TargetAddr); // assert(Removed); } this->type = JUMP; } else { this->ResetCallUsedAsJump(); // See if we call a non-returning function. if (CALL == this->GetDataFlowType()) { if (TargetAddr != STARS_BADADDR) { SMPBasicBlock *CurrBlock = this->GetBlock(); SMPFunction *TargetFunc = CurrBlock->GetFunc()->GetProg()->FindFunction(TargetAddr); if ((nullptr != TargetFunc) && (!TargetFunc->FuncReturnsToCaller())) { CurrBlock->SetHasNonReturningCall(); CurrBlock->GetFunc()->SetCallsNonReturningFunc(); } } } } } } return; } // end of SMPInstr::AnalyzeCallInst() STARS_sval_t SMPInstr::AnalyzeStackPointerDelta(STARS_sval_t IncomingDelta, STARS_sval_t PreAllocDelta) { uint16_t InstType = this->GetIDAOpcode(); STARS_sval_t InstDelta = global_STARS_program->GetStackAlteration(InstType); SMPitype FlowType = this->GetDataFlowType(); bool TailCall = this->IsTailCall(); if (this->IsCallUsedAsJump() || this->IsInterruptCall() || this->IsCondTailCall()) { // Call is used within function as a jump. Happens when setting up // thunk offsets, for example; OR, call is an interrupt call, in which // the interrupt return cleans up the stack, leaving a delta of zero, but // we do not have the system call code to analyze, OR, the call is a conditional // jump to another function (conditional tail call), in which case the current // function must have a return statement to fall into which will clean up the // only thing left on the stack (the return address) and the conditional jump // has no effect on the stack pointer. ; // leave InstDelta equal to negative or zero value from StackAlterationTable[] } else if (this->IsRecursiveCall() || TailCall) { // We don't have the net stack delta for our own function yet, so we cannot // look it up. We must assume that each call has no net effect on the stack delta. // Alternatively, we could call this->GetBlock()->GetFunc()->GetStackDeltaForCallee() as below. // Also, a tail call happens when the stack delta is down to zero, and the callee does not // return to the caller, unlike the call cases below, so the callee's net stack delta is // irrelevant to the caller. if (this->IsFixedCallJump()) { // Fixed call push has happened with delta of -4 or -8; correct it InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA; } else { InstDelta = 0; } } else if (this->IsAllocaCall() || this->HasAllocaRTL()) { InstDelta = STARS_DEFAULT_ALLOCA_SIZE; } else if ((CALL == FlowType) || (INDIR_CALL == FlowType)) { // A real call instruction, which pushes a return address on the stack, // not a call used as a branch within the function. A return instruction // will usually cancel out the stack push that is implicit in the call, which // means that the function will have a net stack ptr delta of +4, which will // cancel out the -4 value of the call instruction and set the delta to zero. // However, this is not true in all cases, so we get the net stack ptr delta // directly from the called function unless it is an unresolved indirect call, // in which case we assume +4. !!!!****!!!! In the future, we could analyze // the code around an unresolved indirect call to see if it seems to be // removing items left on the stack by the callee. #if 0 // SPECIAL CASE: A jump used as a tail call will have a stack ptr effect that is equal // to the net stack ptr effect of its target function, usually +4, whereas a jump // would otherwise have a net stack ptr effect of 0. #endif STARS_ea_t CalledFuncAddr = this->GetCallTarget(); if ((STARS_BADADDR == CalledFuncAddr) || (0 == CalledFuncAddr)) { if (this->IsFixedCallJump()) { // push happens previously; callee should swallow return address InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA; } else { InstDelta = 0; } } else { // We have a call target SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr); STARS_sval_t AdjustmentDelta; if (nullptr != CalleeFunc) { if (!CalleeFunc->HasSTARSStackPtrAnalysisCompleted()) { // Phase ordering issue in the call graph. A mutually recursive clique of functions has to // be broken by starting processing somewhere, and all callees cannot be processed before // we start. If we got our stack down to zero and then made a tail call, then we have to assume // that the callee will use our return address, so we assume the default stack delta. If not a // tail call, we ask our function to see if the information is available from IDA Pro analyses, // or if it can be inferred from the fact that the call is followed by a stack adjustment. if (TailCall) { InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA; SMP_msg("WARNING: Callee stack ptr analysis not yet performed at tail call inst %llx ; normal delta assumed\n", (unsigned long long) this->GetAddr()); } else { AdjustmentDelta = this->GetBlock()->GetFunc()->GetStackDeltaForCallee(CalledFuncAddr); InstDelta += AdjustmentDelta; SMP_msg("WARNING: Callee stack ptr analysis not yet performed at inst %llx ; stack adjustment used\n", (unsigned long long) this->GetAddr()); } } else if (!CalleeFunc->StackPtrAnalysisSucceeded()) { // Callee analyses were done, but they failed. In order to proceed, we have to assume // the same situation as we just did in the case where analyses have not been performed. SMP_msg("WARNING: Callee stack ptr analysis failed at inst %llx ; normal delta assumed\n", (unsigned long long) this->GetAddr()); if (TailCall) { InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA; } else { AdjustmentDelta = this->GetBlock()->GetFunc()->GetStackDeltaForCallee(this->GetAddr()); InstDelta += AdjustmentDelta; } } else { // Callee's analyses have succeeded, so get delta straight from callee. InstDelta += CalleeFunc->GetNetStackPtrDelta(); } } else { #if 0 SMP_msg("ERROR: SMPInstr::AnalyzeStackPointerDelta failed to find func at %llx in inst %llx\n", (unsigned long long) CalledFuncAddr, (unsigned long long) this->GetAddr()); InstDelta = SMP_STACK_DELTA_ERROR_CODE; #else SMP_msg("ERROR: SMPInstr::AnalyzeStackPointerDelta failed to find func at %llx in inst %llx\n", (unsigned long long) CalledFuncAddr, (unsigned long long) this->GetAddr()); if (TailCall) { InstDelta = CALLING_CONVENTION_DEFAULT_FUNCTION_STACK_DELTA; } else { InstDelta = 0; } #endif } } } // end CALL or INDIR_CALL or TailCall case else if (1 == InstDelta) { // value of 1 is trigger to investigate the RTL for the // true value, which cannot be found simply by table lookup // In the special case of an x86 LEAVE instruction, the effect // on the stack pointer is to deallocate the local frame size, // plus pop the saved frame pointer into EBP. Helper functions // need to know whether to look for this special case. bool IsLeaveInstr = this->MDIsLeaveInstr(); InstDelta = this->RTL.TotalStackPointerAlteration(IsLeaveInstr, IncomingDelta, PreAllocDelta); } return InstDelta; } // end of SMPInstr::AnalyzeStackPointerDelta() // Total the stack adjustment bytes, as happens after a call to a function that leaves // outgoing args on the stack or swallows incoming args from the stack. STARS_sval_t SMPInstr::FindStackAdjustment(void) { uint16_t InstType = this->GetIDAOpcode(); STARS_sval_t InstDelta = global_STARS_program->GetStackAlteration(InstType); if (1 == InstDelta) { // value of 1 is trigger to investigate the RTL for the // true value, which cannot be found simply by table lookup // In the special case of an x86 LEAVE instruction, the effect // on the stack pointer is to deallocate the local frame size, // plus pop the saved frame pointer into EBP. Helper functions // need to know whether to look for this special case. bool IsLeaveInstr = this->MDIsLeaveInstr(); if (!IsLeaveInstr) { InstDelta = this->RTL.TotalStackPointerAlteration(IsLeaveInstr, 0, 0); } else { InstDelta = 0; // LEAVE is not the kind of instr we are looking for } } return InstDelta; } // end of SMPInstr::FindStackAdjustment() // Normalize stack operands to have a displacement from the stack pointer value on entry to the function, // rather than the current stack pointer value. // UseFP indicates we are using a frame pointer in the function. // FPDelta holds the stack delta (normalized) for the frame pointer. // DefOp comes in with the operand to be normalized, and contains the normalized operand upon return. // Return true if operand is a register or stack location, false otherwise (true => include in data flow analysis sets and SSA.) bool SMPInstr::MDComputeNormalizedDataFlowOp(bool UseFP, STARS_sval_t FPDelta, STARSOpndTypePtr &DefOp) { #if 0 if ((nullptr == DefOp) || (this->GetStackPtrOffset() == 0)) return false; #else // instead of optimizing, need all stack operands to pass through SIBWithNoIndexReg check and correction if (nullptr == DefOp) return false; #endif if (DefOp->IsRegOp()) { return true; } else if (MDIsStackAccessOpnd(DefOp, UseFP)) { STARSOpndTypePtr OldOp = DefOp->clone(); int SignedOffset = (int) DefOp->GetAddr(); STARS_sval_t NormalizedDelta = 0; if (DefOp->HasSIBByte()) { // We must deal with a potentially indexed memory expression. We want to // normalize two different cases here: e.g. [esp+ebx+4] will become [esp+ebx-24] // and [ebp+ebx-8] will become [esp+ebx-12] after normalization. A wrinkle // on the second case is when the base register and index register are swapped // in the SIB byte, and we make [ebx+ebp-4] into [esp+ebx-12], which involves // correcting the index/base reg order in the SIB, because an index reg of ESP // is the SIB encoding for "no index register" and we cannot leave it like that. int BaseReg = MD_STARS_sib_base(DefOp); int IndexReg = (int) MD_STARS_sib_index(DefOp); if (X86_STACK_POINTER_REG == IndexReg) { // signifies no index register IndexReg = STARS_x86_R_none; } if (BaseReg == X86_STACK_POINTER_REG) { // We probably have an indexed ESP-relative operand. // We leave the sib byte alone and normalize the offset. NormalizedDelta = this->GetStackPtrOffset() + (STARS_sval_t) SignedOffset; } else { // Must be EBP-relative. NormalizedDelta = FPDelta + (STARS_sval_t) SignedOffset; // Unfortunately, when we are dealing with a SIB byte in the opcode, we cannot // just say DefOp.reg = MD_STACK_POINTER_REG to convert from the frame pointer // to the stack pointer. Instead, we have to get into the nasty machine code // level and change the SIB bits that specify either the base register or the // index register, whichever one is the frame pointer. if (BaseReg == X86_FRAME_POINTER_REG) { // The three least significant bits of the SIB byte are the base register. // They must contain a 5, which is the x86 value for register EBP, and we // want to convert it to a 4, denoting register ESP. We can just zero out // the least significant bit to accomplish that. char OldSIB = DefOp->GetSIB(); DefOp->SetSIB(OldSIB & 0xfe); } else { // We sometimes have an instruction in which the frame pointer is used as // the "index" register in the SIB byte, and the true index register is // in the "base" register position in the SIB byte. assert(IndexReg == X86_FRAME_POINTER_REG); // The true index reg is in the lowest three bits, while the next three // bits must contain a 5 (register EBP) and we want to make them a 4 (ESP). // We must swap base and index regs as we normalize (see explanation above). char SIBtemp = DefOp->GetSIB(); char SIBindex = SIBtemp & 0x38; char SIBbase = SIBtemp & 0x07; assert ((SIBindex >> 3) == 5); // must be EBP SIBtemp &= 0xa0; // zero out lower 6 bits; upper 2 bits are scale factor - leave them alone SIBtemp &= (SIBbase << 3); // make old base reg (e.g. ebx) into a proper index reg SIBtemp |= 0x04; // make the new base reg be 4 (reg ESP) DefOp->SetSIB(SIBtemp); } this->SetFPNormalizedToSP(); // Add the stack pointer to the USE set for the instruction. this->MDAddRegUse(X86_STACK_POINTER_REG, false); } } // end if SIB byte else if (DefOp->GetReg() == MD_FRAME_POINTER_REG) { // no SIB byte, just o_displ with one address reg // If FPDelta is -4 and SignedOffset is +8, then we have [ebp+8] as DefOp, and this // is equivalent to [esp+4] where esp has its entry value, i.e. this would be the first incoming // argument. If SignedOffset is -12, we have [ebp-12] as DefOp, and this is [esp-16] when // normalized to the entry point value of the stack pointer. In both cases, we can see that the // normalized stack delta is just FPDelta+SignedOffset. NormalizedDelta = FPDelta + (STARS_sval_t) SignedOffset; // Now, we simply convert the memory operand from EBP to ESP and replace the SignedOffset with the // NormalizedDelta just computed. DefOp->SetReg(MD_STACK_POINTER_REG); DefOp->SetByteWidth(OldOp->GetByteWidth()); // undo possible width change in SetReg() this->SetFPNormalizedToSP(); // Add the stack pointer to the USE set for the instruction. this->MDAddRegUse(MD_STACK_POINTER_REG, false); } else { assert(DefOp->GetReg() == MD_STACK_POINTER_REG); // We only need to adjust the offset to reflect the change in the stack pointer since the function // was entered, e.g. [esp+4] is normalized to [esp-28] if the current esp value is 32 less than it // was upon function entry. We get the value "-32" in that case from a member variable. NormalizedDelta = this->GetStackPtrOffset() + (STARS_sval_t) SignedOffset; } DefOp->SetAddr((STARS_ea_t) NormalizedDelta); // common to frame and stack pointer cases this->GetBlock()->GetFunc()->UpdateMaxDirectStackAccessOffset(NormalizedDelta); // maintain record of maximum if (NormalizedDelta == 0) { // [esp+0] is the return address location. Reading or writing the return address makes // the function unsafe for the Strata fast return mechanism. if (this->HasDestMemoryOperand()) { this->GetBlock()->GetFunc()->SetUnsafeForFastReturns(true, RETURN_ADDRESS_WRITE); SMP_msg("INFO: Return address overwritten in instruction at %llx\n", (unsigned long long) this->GetAddr()); } else { this->GetBlock()->GetFunc()->SetUnsafeForFastReturns(true, RETURN_ADDRESS_READ); SMP_msg("INFO: Return address read in instruction at %llx\n", (unsigned long long) this->GetAddr()); } } // Clean up unnecessary SIB byte, make sure offset matches operand type, etc. DefOp->CleanOpndEncoding(); this->GetBlock()->GetFunc()->AddNormalizedStackOperand(OldOp, this->GetAddr(), DefOp); return true; } else { return false; } } // end of SMPInstr::MDComputeNormalizedDataFlowOp() // Normalize stack operands in all DEFs and USEs to have stack deltas relative to the function entry stack pointer. // Return true if any stack DEFs or USEs were normalized. bool SMPInstr::MDNormalizeStackOps(bool UseFP, STARS_sval_t FPDelta, bool Recomputing, STARS_sval_t DeltaIncrement) { if (!this->IsAnalyzeable()) return false; bool StackOpFound = false; bool OpNormalized; bool UniqueDEFMemOp = true; // Does DEFMemOp not match any DEFs? bool UniqueUSEMemOp = true; // Does USEMemOp not match any USEs? bool UniqueLeaUSEMemOp = true; // Does LeaUSEMemOp not match any USEs? bool UniqueMoveSource = true; // Does MoveSource not match any USEs? bool HasDEFMemOp = (nullptr != this->DEFMemOp); set<DefOrUse, LessDefUse>::iterator DefIter, UseIter; list<pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> > DefWorkList, UseWorkList; list<pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> >::iterator WorkIter; STARSOpndTypePtr OldOp = nullptr, NewOp = nullptr; // Find all the DEFs that need changing, and put their iterators into a list. // Normalizing stack ops could change their sort order, hence we could skip over // a DEF in the set by erasing a DEF and reinserting a normalized DEF, so we // make all the changes after we iterate through the DEFS set. for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { OldOp = DefIter->GetOp(); if ((! OldOp->IsRegOp()) && (! OldOp->IsImmedOp())) { NewOp = OldOp->clone(); if (Recomputing) { OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, true, NewOp); } else { OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, NewOp); } if (OpNormalized) { StackOpFound = true; if (HasDEFMemOp && IsEqOp(OldOp, this->DEFMemOp)) { UniqueDEFMemOp = false; this->DEFMemOp = NewOp; } else { assert(!HasDEFMemOp); } pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> DefItem(DefIter, NewOp); DefWorkList.push_back(DefItem); } } } // Now go through the DEF worklist and change stack operands to normalized stack operands. for (WorkIter = DefWorkList.begin(); WorkIter != DefWorkList.end(); ++WorkIter) { DefIter = WorkIter->first; #if 0 if (!Recomputing) { // Just replace DefOp at DefIter with normalized op if not recomputing DefIter = this->Defs.SetOp(DefIter, WorkIter->second); } else { // Keep both old and new forms of DefOp in the Def set if recomputing this->AddDef(WorkIter->second, DefIter->GetType(), DefIter->GetSSANum()); } #else DefIter = this->Defs.SetOp(DefIter, WorkIter->second); #endif } // Normalize STARSOpndTypePtr private data member DEFs. if (HasDEFMemOp && UniqueDEFMemOp) { // DefOp and this->DEFMemOp could be shared_ptr to same object; don't duplicate work if so if (Recomputing) { OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueDEFMemOp, this->DEFMemOp); } else { OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, this->DEFMemOp); } } bool HasUSEMemOp = ((nullptr != this->USEMemOp) && (!this->USEMemOp->IsVoidOp())); bool HasLeaMemUseOp = (nullptr != this->GetLeaMemUseOp()); bool HasMoveSourceMemOp = this->GetMoveSource()->IsMemOp(); #if 0 // pop instructions have none of these flags true if (HasUSEMemOp || HasLeaMemUseOp || HasMoveSourceMemOp) { #endif // Find all USEs that need changing, and build a second work list. for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { OldOp = UseIter->GetOp(); if ((!OldOp->IsRegOp()) && (!OldOp->IsImmedOp())) { NewOp = OldOp->clone(); if (Recomputing) { OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, true, NewOp); } else { OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, NewOp); } if (OpNormalized) { StackOpFound = true; if (HasUSEMemOp) { if (IsEqOp(OldOp, this->USEMemOp)) { UniqueUSEMemOp = false; this->USEMemOp = NewOp; } else { SMP_msg("\nFATAL ERROR in MDNormalizeStackOps: Stack operand is not the USEMemOp. Inst dump follows.\n"); SMP_msg("Recomputing: %d DeltaIncrement: %d\n", Recomputing, DeltaIncrement); SMP_msg("Stack Op: "); PrintOperand(OldOp); SMP_msg("\nUSEMemOp: "); PrintOperand(this->USEMemOp); SMP_msg(" \n"); this->Dump(); assert(false); } } if (HasLeaMemUseOp && IsEqOp(OldOp, this->GetLeaMemUseOp())) { UniqueLeaUSEMemOp = false; this->SetLeaMemUseOp(NewOp); } if (HasMoveSourceMemOp && IsEqOp(OldOp, this->GetMoveSource())) { UniqueMoveSource = false; this->MoveSource = NewOp; } pair<set<DefOrUse, LessDefUse>::iterator, STARSOpndTypePtr> UseItem(UseIter, NewOp); UseWorkList.push_back(UseItem); } } } // Now go through the USE worklist and change stack operands to normalized stack operands. for (WorkIter = UseWorkList.begin(); WorkIter != UseWorkList.end(); ++WorkIter) { UseIter = WorkIter->first; #if 0 if (!Recomputing) { // Just replace UseOp at UseIter with normalized op if not recomputing UseIter = this->Uses.SetOp(UseIter, WorkIter->second); } else { // Keep both old and new forms of UseOp in the Use set if recomputing this->AddUse(WorkIter->second, UseIter->GetType(), UseIter->GetSSANum()); } #else UseIter = this->Uses.SetOp(UseIter, WorkIter->second); #endif } // Normalize STARSOpndTypePtr private data member USEs. if (Recomputing) { if (HasUSEMemOp && UniqueUSEMemOp) { OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueUSEMemOp, this->USEMemOp); } if (this->MDIsLoadEffectiveAddressInstr()) { STARSOpndTypePtr TempLeaMemOp = nullptr; if (HasLeaMemUseOp) TempLeaMemOp = this->GetLeaMemUseOp()->clone(); OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueLeaUSEMemOp, TempLeaMemOp); if (OpNormalized) this->SetLeaMemUseOp(TempLeaMemOp); } if (HasMoveSourceMemOp && UniqueMoveSource) { OpNormalized = this->MDRecomputeNormalizedDataFlowOp(DeltaIncrement, UniqueMoveSource, this->MoveSource); } } else { if (HasUSEMemOp && UniqueUSEMemOp) // avoid shared_ptr duplicate normalization OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, this->USEMemOp); if (HasLeaMemUseOp && UniqueLeaUSEMemOp && this->MDIsLoadEffectiveAddressInstr()) { // avoid shared_ptr duplicate normalization STARSOpndTypePtr TempLeaMemOp = this->GetLeaMemUseOp()->clone(); OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, TempLeaMemOp); if (OpNormalized) this->SetLeaMemUseOp(TempLeaMemOp); } if (HasMoveSourceMemOp && UniqueMoveSource) // avoid shared_ptr duplicate normalization OpNormalized = this->MDComputeNormalizedDataFlowOp(UseFP, FPDelta, this->MoveSource); } #if 0 } // end if we have some mem USE to normalize #endif // Declare victory. this->SetDefsNormalized(); return StackOpFound; } // end of SMPInstr::MDNormalizeStackOps() // Renormalize SP-relative stack operands in functions that call alloca() by adding DeltaIncrement to their stack displacements. // DefOp comes in with the operand to be renormalized, and contains the normalized operand upon return. // Return true if operand is a register or stack location, false otherwise (true => include in data flow analysis sets and SSA.) bool SMPInstr::MDRecomputeNormalizedDataFlowOp(STARS_sval_t DeltaIncrement, bool UpdateMaps, STARSOpndTypePtr &DefOp) { if ((nullptr == DefOp) || (DeltaIncrement == 0)) return false; if (DefOp->IsRegOp()) { return true; } else if (MDIsStackAccessOpnd(DefOp, this->GetBlock()->GetFunc()->UsesFramePointer())) { if (this->HasFPNormalizedToSP()) { // FP-relative operands do not change in alloca() functions when the alloca() // causes the SP to change. return true; } // The remaining cases are simple. The ESP-relative displacement is incremented by // DeltaIncrement, regardless of the presence of a SIB byte. int SignedOffset = (int) DefOp->GetAddr(); STARS_sval_t NormalizedDelta = DeltaIncrement + (STARS_sval_t) SignedOffset; STARSOpndTypePtr OldOp = DefOp->clone(); DefOp->SetAddr((STARS_ea_t) NormalizedDelta); if (DefOp->IsMemNoDisplacementOp() && (0 != NormalizedDelta)) { // mov [esp],eax has an [esp] operand of type o_phrase, because there is no // displacement field. After normalization, it will have a displacement field, so // it has become an operand like [esp-32] and is now type o_displ. DefOp->SetTypeToMemDisplacement(); } if (UpdateMaps) { // We don't update maps for duplicate entries, e.g. USEMemOp, DEFMemOp, MoveSource this->GetBlock()->GetFunc()->AddNormalizedStackOperand(OldOp, this->GetAddr(), DefOp); } return true; } else { return false; } } // end of SMPInstr::MDRecomputeNormalizedDataFlowOp() // If NormOp is a normalized stack memory operand, unnormalize it. void SMPInstr::MDGetUnnormalizedOp(STARSOpndTypePtr &NormOp) { STARS_sval_t SignedOffset; bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if (this->AreDefsNormalized() && (0 != this->GetStackPtrOffset()) && MDIsStackAccessOpnd(NormOp, UseFP)) { if (this->HasFPNormalizedToSP()) { size_t NormOpByteWidth = NormOp->GetByteWidth(); // Need to convert NormOp back to frame-pointer-relative address. if (NormOp->HasSIBByte()) { // Convert base register from stack pointer back to frame pointer. char OldSIB = NormOp->GetSIB(); NormOp->SetSIB(OldSIB | 0x01); } else { NormOp->SetReg(MD_FRAME_POINTER_REG); NormOp->SetByteWidth(NormOpByteWidth); // undo possible width change in SetReg() } SignedOffset = (STARS_sval_t) NormOp->GetAddr(); SignedOffset -= this->GetBlock()->GetFunc()->GetFramePtrStackDelta(); } else { // NormOp should remain stack-pointer-relative address, but it // should be a positive offset from the current stack pointer instead // of a negative offset from the entry point of the function. SignedOffset = (STARS_sval_t) NormOp->GetAddr(); SignedOffset -= this->GetStackPtrOffset(); assert((0 <= SignedOffset) || this->GetBlock()->GetFunc()->DoesStackFrameExtendPastStackTop()); } NormOp->SetAddr((STARS_ea_t) SignedOffset); } return; } // end of SMPInstr::MDGetUnnormalizedOp() // Find USE-not-DEF operand that is not the flags register. STARSOpndTypePtr SMPInstr::GetSourceOnlyOperand(void) const { std::size_t OpNum; // loop through all operands for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { // if operand[OpNum]->IsDefOperand() /* is it written? */ if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF ; } // if operand[OpNum]->IsUseOperand() /* is it read? */ else if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE STARSOpndTypePtr CurrOp = this->STARSInstPtr->GetOpnd(OpNum); if (!(CurrOp->MatchesReg(X86_FLAGS_REG))) { return CurrOp; } } } // It is expected that increment, decrement, and floating point stores // will not have a USE-only operand. Increment and decrement have an // operand that is both USEd and DEFed, while the floating point stack // registers are implicit in most floating point opcodes. Also, exchange // and exchange-and-add instructions have multiple DEF-and-USE operands. int TypeGroup = SMPTypeCategory[this->GetIDAOpcode()]; if ((TypeGroup != 2) && (TypeGroup != 4) && (TypeGroup != 9) && (TypeGroup != 12) && (TypeGroup != 13)) { SMP_msg("ERROR: Could not find source only operand at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } return nullptr; } // end of SMPInstr::GetSourceOnlyOperand() // Should apparent memory operands be ignored? e.g. lea opcode on x86 bool SMPInstr::MDIgnoreMemOps(void) { return this->MDIsLoadEffectiveAddressInstr(); } // Find memory DEFs and USEs, store in DEFMemOp and USEMemOp void SMPInstr::FindMemOps(void) { if (!(this->MDIgnoreMemOps())) { for (size_t OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { STARSOpndTypePtr TempOp = this->GetOperand(OpNum); if ((nullptr != TempOp) && TempOp->IsMemOp()) { if (this->STARSInstPtr->IsDefOpnd(OpNum)) { if ((nullptr == this->DEFMemOp) || this->DEFMemOp->IsVoidOp()) { // only save first mem DEF this->DEFMemOp = TempOp; } } if (this->STARSInstPtr->IsUseOpnd(OpNum)) { if ((nullptr == this->USEMemOp) || this->USEMemOp->IsVoidOp()) { // only save first mem DEF this->USEMemOp = TempOp; } } } } // end for each operand } this->SetMemOpsFound(); return; } // end of SMPInstr::FindMemOps() // Fix problems with the operands list in SMPcmd. void SMPInstr::MDFixupIDAProOperandList(void) { // IDA Pro often takes the instruction imul eax,0x80 and creates the following operands and features bits: // Opnd[0] = EAX, both DEF and USE // Opnd[1] = EAX, just USE // Opnd[2] = immediate, neither DEF nor USE // Our RTL building keys in on the DEF/USE bits in features, so this looks like imul eax,eax to us. // We want it to look like: // Opnd[0] = EAX, both DEF and USE // Opnd[1] = immediate, just USE if (STARS_NN_imul == this->GetIDAOpcode()) { STARSOpndTypePtr Opnd2 = this->STARSInstPtr->GetOpnd(2); if ((!(this->STARSInstPtr->IsDefOpnd(2))) && (!(this->STARSInstPtr->IsUseOpnd(2)))) { if ((nullptr != Opnd2) && (!Opnd2->IsVoidOp())) { // We have a third operand that is neither DEF nor USE. SMP_msg("INFO: Fixing IMUL operand list at %llx\n", (unsigned long long) this->GetAddr()); // this->Dump(); // Two cases: Operands[0] == Operands[1], e.g. imul eax,Opnd2 // or else three-operand form: e.g. imul eax,ecx,Opnd2 // For the three-operand form, make sure Opnd0 is DEF only, others // are USE only. For the two-operand form, make sure Opnd0 is DEF and USE, // Opnd1 is current Opnd2 and is USE only. STARSOpndTypePtr Opnd0 = this->STARSInstPtr->GetOpnd(0); STARSOpndTypePtr Opnd1 = this->STARSInstPtr->GetOpnd(1); if (IsEqOp(Opnd0, Opnd1)) { // No need for three-operand form. this->STARSInstPtr->SetOpDefed(0); this->STARSInstPtr->SetOpUsed(0); this->STARSInstPtr->RemoveIDAOp1ForIMUL(); } else { // Must have three-operand form. this->STARSInstPtr->SetOpUsed(2); // set missing USE bit. this->STARSInstPtr->SetOpNotUsed(0); // Ensure no USE of Opnd0. } this->Dump(); } } } return; } // SMPInstr::MDFixupIDAProOperandList() // Fill the Defs and Uses private data members. void SMPInstr::BuildSMPDefUseLists(void) { std::size_t OpNum; bool DebugFlag = (0x8049b00 == this->GetAddr()); bool WidthDoubler = this->MDDoublesWidth(); this->Defs.clear(); this->Uses.clear(); if (this->IsNop()) return; // Start with the Defs. for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF STARSOpndTypePtr TempOp = nullptr; if (WidthDoubler) { // Opcodes that sign-extend a byte to a word, or a word to a dword, // have only one operand. It is implicit, and it is the shorter USE. // That means the DEF will have the same width as the USE, e.g. if // we are sign-extending AX to EAX, the USE and DEF will both be AX without // a special fix. We fix this problem with the DEF operand now. TempOp = this->STARSInstPtr->GetOpnd(OpNum)->clone(); // Prepare to double the width uint16_t CurrByteWidth = TempOp->GetByteWidth(); if ((1 == CurrByteWidth) || (2 == CurrByteWidth) || (4 == CurrByteWidth)) { TempOp->DoubleRegWidth(); } else { SMP_msg("ERROR: Instruction operand %zu not 1,2, or 4 bytes at %llx ; Width : %u\n", OpNum, (unsigned long long) this->GetAddr(), TempOp->GetByteWidth()); } } else { // no need to clone, as we are not doubling the width TempOp = this->STARSInstPtr->GetOpnd(OpNum); } if (MDKnownOperandType(TempOp)) { if (DebugFlag) { SMP_msg("DEBUG: Setting DEF for: "); PrintOperand(TempOp); SMP_msg("\n"); } this->Defs.SetRef(TempOp); } } } // end for (OpNum = 0; ...) SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if ((NULL != CurrRT) && CurrRT->IsSubregMove()) { // we built a subreg := imm or subreg := subreg RT // Upper bits of full reg are USEd, unchanged. this->Uses.SetRef(CurrRT->GetLeftOperand(), NUMERIC); // GetLeftOperand() normalizes to full reg } if (this->IsRegClearIdiom()) { // Something like xor eax,eax clears eax but does not really // use eax. It is the same as mov eax,0 and we don't want to // extend the prior def-use chain for eax to this instruction // by treating the instruction as xor eax,eax. Instead, we // build the DEF and USE lists and RTL as if it were mov eax,0. // The exception is something like xor al,al where the upper bits // are carried over, hence we do USE the full RAX/EAX register. // That is a special case of subreg := immediate. See code above. STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); this->Uses.SetRef(ZeroOp, NUMERIC); return; } // Now, do the Uses. Uses have special case operations, because // any memory operand could have register uses in the addressing // expression, and we must create Uses for those registers. For // example: mov eax,[ebx + esi*2 + 044Ch] // This is a two-operand instruction with one def: eax. But // there are three uses: [ebx + esi*2 + 044Ch], ebx, and esi. // The first use is an op_t of type o_phrase (memory phrase), // which can be copied from cmd.Operands[1]. Likewise, we just // copy cmd.Operands[0] into the defs list. However, we must create // op_t types for register ebx and register esi and append them // to the Uses list. This is handled by the machine dependent // method MDFixupDefUseLists(). for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (MDKnownOperandType(TempOp)) { if (DebugFlag) { SMP_msg("DEBUG: Setting USE for: "); PrintOperand(TempOp); SMP_msg("\n"); } this->Uses.SetRef(TempOp); } } } // end for (OpNum = 0; ...) if (this->MDIsConditionalMoveInstr()) { // We need to represent the possibility that the DEF operand will not // be set because the move is conditional. We will add the DEF operand // into the USE set and special case our type inferences so that the // USE and the pseudo-USE (prior SSA value of the DEF operand) must // agree in type before we can be sure of the result type. assert(this->Defs.GetSize() == 1); this->Uses.SetRef(this->Defs.GetFirstRef()->GetOp()); } return; } // end of SMPInstr::BuildSMPDefUseLists() // Declare a branch/jump to be a tail call, clean up def/use lists. void SMPInstr::SetTailCall(void) { this->booleans1 |= INSTR_SET_TAIL_CALL; if (this->type == COND_BRANCH) { this->SetCondTailCall(); } else { this->ResetCondTailCall(); } this->CallTarget = this->GetJumpTarget(); if (!this->MDIsSystemCall()) { if (INDIR_JUMP == this->GetDataFlowType()) { this->GetBlock()->GetFunc()->SetHasIndirectCalls(); if (STARS_BADADDR == this->CallTarget) { // Already recorded as unresolved jump. ; #if 0 this->GetBlock()->GetFunc()->SetHasUnresolvedIndirectCalls(); #endif } else { (void) this->GetBlock()->GetFunc()->AddIndirectCallTarget(this->CallTarget); } } else { // direct jump if (STARS_BADADDR == this->CallTarget) { SMP_msg("ERROR: SMPInstr::SetTailCall() has STARS_BADADDR as call target at %llx\n", (unsigned long long) this->GetAddr()); } else { (void) this->GetBlock()->GetFunc()->AddDirectCallTarget(this->CallTarget); } } } this->type = RETURN; this->GetBlock()->SetReturns(true); // We want to add the caller-saved registers to the USEs and DEFs lists this->MDAddRegDef(STARS_x86_R_ax, false); this->MDAddRegDef(STARS_x86_R_cx, false); this->MDAddRegDef(STARS_x86_R_dx, false); this->MDAddRegUse(STARS_x86_R_ax, false); this->MDAddRegUse(STARS_x86_R_cx, false); this->MDAddRegUse(STARS_x86_R_dx, false); } // end of SMPInstr::SetTailCall() // record original Lea instruction [pseudo-]memory operand. void SMPInstr::SetLeaMemUseOp(STARSOpndTypePtr NewLeaOperand) { if (NULL != this->BasicBlock) { this->GetBlock()->GetFunc()->AddLeaOperand(this->GetAddr(), NewLeaOperand); } return; } // Reset a jump instruction to be a pseudo-call because it was obtained by transforming // a call to a "push retaddr/jump calltarget" pair. void SMPInstr::SetFixedCallJump(void) { this->booleans5 |= INSTR_SET_FIXED_CALL_JUMP; this->CallTarget = this->GetJumpTarget(); this->RTL.GetRT(0)->SetOperator(SMP_CALL); this->RTL.GetRT(0)->SetLeftOperand(this->STARSInstPtr->MakeVoidOpnd()); if (this->type == JUMP) { this->type = CALL; // Important: Change type to CALL only after calling GetJumpTarget() } else { assert(this->type == INDIR_JUMP); this->type = INDIR_CALL; } return; } // end of SMPInstr::SetFixedCallJump() // If DefReg is not already in the DEF list, add a DEF for it. void SMPInstr::MDAddRegDef(STARS_regnum_t DefReg, bool Shown, SMPOperandType Type) { STARSOpndTypePtr TempDef = this->STARSInstPtr->MakeRegOpnd(DefReg); CanonicalizeOpnd(TempDef); if (!Shown) TempDef->SetNotVisible(); this->Defs.SetRef(TempDef, Type); return; } // end of SMPInstr::MDAddRegDef() // If UseReg is not already in the USE list, add a USE for it. void SMPInstr::MDAddRegUse(STARS_regnum_t UseReg, bool Shown, SMPOperandType Type) { STARSOpndTypePtr TempUse = this->STARSInstPtr->MakeRegOpnd(UseReg); if (!Shown) TempUse->SetNotVisible(); this->Uses.SetRef(TempUse, Type); return; } // end of SMPInstr::MDAddRegUse() // Perform machine dependent ad hoc fixes to the def and use lists. // For example, some multiply and divide instructions in x86 implicitly // use and/or define register EDX. For memory phrase examples, see comment // in BuildSMPDefUseLists(). void SMPInstr::MDFixupDefUseLists(void) { // First, handle the uses hidden in memory addressing modes. Note that we do not // care whether we are dealing with a memory destination operand or source // operand, because register USEs, not DEFs, happen within the addressing expressions. std::size_t OpNum; SMPOperandType RefType; unsigned short opcode = this->GetIDAOpcode(); int BaseReg; int IndexReg; uint16_t ScaleFactor; STARS_ea_t displacement; bool UseFP = true; bool HasIndexReg = false; bool SingleAddressReg = false; bool leaInst = this->MDIsLoadEffectiveAddressInstr(); bool DebugFlag = (this->GetAddr() == 0xac6e0); if (DebugFlag) { SMP_msg("DEBUG: Fixing up DEF-USE lists for debug location\n"); this->Dump(); } #if SMP_BASEREG_POINTER_TYPE // Some instructions are analyzed outside of any function or block when fixing up // the IDB, so we have to assume the block and func pointers might be NULL. if ((NULL != this->BasicBlock) && (NULL != this->BasicBlock->GetFunc())) UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); #endif if (DebugFlag) { SMP_msg("DEBUG: UseFP = %d\n", UseFP); } for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == Opnd) // finished processing operands break; if (Opnd->IsMemOp()) { MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement); SingleAddressReg = ((0 == displacement) && ((STARS_x86_R_none == BaseReg) || (STARS_x86_R_none == IndexReg))); if (STARS_x86_R_none != IndexReg) { STARSOpndTypePtr IndexOpnd = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg); if (0 == ScaleFactor) this->Uses.SetRef(IndexOpnd); else { // scaling == shift ==> NUMERIC HasIndexReg = true; this->Uses.SetRef(IndexOpnd, NUMERIC); } } if (STARS_x86_R_none != BaseReg) { STARSOpndTypePtr BaseOpnd = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg); RefType = UNINIT; #if SMP_BASEREG_POINTER_TYPE // STARS_x86_R_sp and STARS_x86_R_bp will get type STACKPTR in SMPInstr::SetImmedTypes(). // Other registers used as base registers should get their USEs as // base registers typed as POINTER, which might get refined later // to STACKPTR, GLOBALPTR, HEAPPTR, etc. // NOTE: the STARS_NN_lea opcode is often used without a true base register. // E.g. lea eax,[eax+eax+5] is an x86 idiom for eax:=eax*2+5, which // could not be done in one instruction without using the addressing // modes of the machine to do the arithmetic. We don't want to set the // USE of EAX to POINTER in this case, so we will conservatively skip // all lea instructions here. // We cannot be sure that a register is truly a base register unless // there is also an index register. E.g. with reg+displacement, we // could have memaddr+indexreg or basereg+offset, depending on what // the displacement is. The exception is if there is no offset and only // one addressing register, e.g. mov eax,[ebx]. if (BaseOpnd->MatchesReg(MD_STACK_POINTER_REG) || (UseFP && BaseOpnd->MatchesReg(MD_FRAME_POINTER_REG)) || leaInst || (!HasIndexReg && !SingleAddressReg)) { ; } else { RefType = POINTER; } #endif this->Uses.SetRef(BaseOpnd, RefType); } // end if STARS_x86_R_none != BaseReg } // end if (o_phrase or o_displ operand) } // end for (all operands) // The lea (load effective address) instruction looks as if it has // a memory USE: lea ebx,[edx+esi] // However, this instruction is really just: ebx := edx+esi // Now that the above code has inserted the "addressing" registers // into the USE list, we should remove the "memory USE". if (leaInst) { set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { STARSOpndTypePtr UseOp = CurrUse->GetOp(); if (UseOp->IsMemOp()) { this->SetLeaMemUseOp(UseOp); this->EraseUse(CurrUse); this->USEMemOp = nullptr; break; } } } // Next, handle repeat prefices in the instructions. The Intel REPE/REPZ prefix // is just the text printed for SCAS/CMPS instructions that have a REP prefix. // Only two distinct prefix codes are actually defined: REP and REPNE/REPNZ, and // REPNE/REPNZ only applies to SCAS and CMPS instructions. bool HasRepPrefix = this->STARSInstPtr->HasRepeatIfEqualPrefix(); bool HasRepnePrefix = this->STARSInstPtr->HasRepeatIfNotEqualPrefix(); if (HasRepPrefix && HasRepnePrefix) SMP_msg("ERROR: REP and REPNE both present at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); if (HasRepPrefix || HasRepnePrefix) { // All repeating instructions use ECX as the countdown register. STARSOpndTypePtr BaseOpnd = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); BaseOpnd->SetNotVisible(); this->Defs.SetRef(BaseOpnd, NUMERIC); this->Uses.SetRef(BaseOpnd, NUMERIC); } if ((opcode == STARS_NN_cmps) || (opcode == STARS_NN_scas) || (opcode == STARS_NN_movs) || (opcode == STARS_NN_stos)) { // ESI and EDI are USEd and DEFed to point to source and dest strings for CMPS/MOVS. // Only EDI is involved with SCAS/STOS. if ((opcode == STARS_NN_cmps) || (opcode == STARS_NN_movs)) { STARSOpndTypePtr BaseOpnd = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si); BaseOpnd->SetNotVisible(); this->Defs.SetRef(BaseOpnd, POINTER); this->Uses.SetRef(BaseOpnd, POINTER); } STARSOpndTypePtr BaseOpnd2 = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di); BaseOpnd2->SetNotVisible(); this->Defs.SetRef(BaseOpnd2, POINTER); this->Uses.SetRef(BaseOpnd2, POINTER); } else if ((STARS_NN_loopw <= opcode) && (STARS_NN_loopqne >= opcode)) { STARSOpndTypePtr LoopCounterOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); this->Defs.SetRef(LoopCounterOp, NUMERIC); this->Uses.SetRef(LoopCounterOp, NUMERIC); } // Now, handle special instruction categories that have implicit operands. bool BranchOutsideFunc = this->IsBranchToOtherFunc(); if (STARS_NN_cmpxchg == opcode) { // x86 Compare and Exchange conditionally sets EAX. We must keep data flow analysis // sound by declaring that EAX is always a DEF. this->MDAddRegDef(STARS_x86_R_ax, false); } // end if STARS_NN_cmpxchg else if ((this->type == CALL) || (this->type == INDIR_CALL) || this->IsTailCall() || BranchOutsideFunc) { // NOTE: Phase ordering issue with IsTailCall(), so we check if branch to other func. // We want to add the caller-saved registers to the USEs and DEFs lists for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCallerSavedReg(); RegIter != global_STARS_program->GetLastCallerSavedReg(); ++RegIter) { STARS_regnum_t RegNum = (*RegIter); this->MDAddRegDef(RegNum, false); this->MDAddRegUse(RegNum, false); } // Because we don't know what is going on with callees in external modules, we have to be conservative and // assume that callee-saved registers might be LiveIn to them. if (NULL != this->GetBlock()) { STARS_ea_t CalledFuncAddr = this->GetCallTarget(); if ((STARS_BADADDR == CalledFuncAddr) && BranchOutsideFunc) { CalledFuncAddr = this->GetJumpTarget(); } SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr); bool UnAnalyzedCalleeCase = ((nullptr == CalleeFunc) || (this->type == INDIR_CALL) || CalleeFunc->IsLinkerStub()); #if !STARS_CONSERVATIVE_DEADREGS if (UnAnalyzedCalleeCase) { #endif for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCalleeSavedReg(); RegIter != global_STARS_program->GetLastCalleeSavedReg(); ++RegIter) { STARS_regnum_t RegNum = (*RegIter); this->MDAddRegUse(RegNum, false); } #if !STARS_CONSERVATIVE_DEADREGS } #endif } #if 1 // Optimize: Need to check if these regs were ever referenced in current func if (this->IsInterruptCall() || BranchOutsideFunc) { #endif this->MDAddRegUse(STARS_x86_R_bx, false); this->MDAddRegUse(STARS_x86_R_si, false); if (this->IsInterruptCall()) { this->MDAddRegDef(STARS_x86_R_bx, false); this->MDAddRegDef(STARS_x86_R_si, false); } #if 1 } #endif } else if (this->MDIsPopInstr() || this->MDIsPushInstr() || this->HasReturnOpcode()) { // IDA does not include the stack pointer in the DEFs or USEs. this->MDAddRegDef(MD_STACK_POINTER_REG, false); this->MDAddRegUse(MD_STACK_POINTER_REG, false); #if 0 if (!this->HasReturnOpcode()) { // We always reference [esp+0] or [esp-4 or 8], so add it to the DEF or USE list. if (this->MDIsPopInstr()) { STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 0); // [ESP+0] this->Uses.SetRef(StackOp); // USE } else { STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, (-((STARS_ea_t) global_STARS_program->GetSTARS_ISA_Bytewidth()))); // [ESP-4] or [ESP-8] this->Defs.SetRef(StackOp); // DEF } } #endif } else if (this->MDIsEnterInstr() || this->MDIsLeaveInstr()) { // Entire function prologue or epilogue microcoded. this->MDAddRegDef(MD_STACK_POINTER_REG, false); this->MDAddRegUse(MD_STACK_POINTER_REG, false); this->MDAddRegDef(MD_FRAME_POINTER_REG, false); this->MDAddRegUse(MD_FRAME_POINTER_REG, false); } else if ((opcode == STARS_NN_maskmovq) || (opcode == STARS_NN_maskmovdqu)) { this->MDAddRegUse(STARS_x86_R_di, false, POINTER); } else if (8 == this->GetOptType()) { // This category implicitly writes to EDX:EAX. this->MDAddRegDef(STARS_x86_R_dx, false); this->MDAddRegDef(STARS_x86_R_ax, false); } // end else if (8 == GetOptType) else if (7 == this->GetOptType()) { // Category 7 instructions sometimes write implicitly to EDX:EAX or DX:AX. // DX is the same reg # as EDX to IDA Pro (and SMP); ditto for EAX and AX. // DIV, IDIV, and MUL all have hidden EAX or AX operands (hidden in the IDA Pro // sense, because they are not displayed in the disassembly text). For example: // mul ebx means EDX:EAX <-- EAX*EBX, and mul bx means DX:AX <-- AX*BX. If the // source operand is only 8 bits wide, there is room to hold the result in AX // without using DX: mul bl means AX <-- AL*BL. // IMUL has forms with a hidden EAX or AX operand and forms with no implicit // operands: imul ebx means EDX:EAX <-- EAX*EBX, but imul ebx,edx means that // EBX*EDX gets truncated and the result placed in EBX (no hidden operands). for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { STARSOpndTypePtr TempUse = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempUse) // finished processing operands break; if (!TempUse->IsVisible()) { // hidden operand if (TempUse->MatchesReg(STARS_x86_R_ax)) { // not STARS_x86_R_al, so it is not 8 bits if ((STARS_NN_div == opcode) || (STARS_NN_idiv == opcode)) { this->MDAddRegUse(STARS_x86_R_dx, false); } this->MDAddRegDef(STARS_x86_R_ax, false); this->MDAddRegDef(STARS_x86_R_dx, false); } } } } // end else if (7 == OptType) #if 0 // The floating point instructions in type categories 14 and 15 often USE and DEF // the floating point register stack, e.g. pushing a value onto that stack is a // massive copy downward of stack locations. We don't really care about the USE of // the stack if the value being pushed came from elsewhere than the stack. For example, // an "fld" opcode pushes its source onto the stack. We build RTLs with a simple // move structure, but the RTL building can be fooled by seeing two "source" operands // in the USE list. if ((14 == SMPTypeCategory[opcode]) || (15 == SMPTypeCategory[opcode])) { } #endif #if 0 // Not true for LOOP instructions that use only the ECX counter register. if (this->type == COND_BRANCH) { assert(SMPUsesFlags[opcode]); } #endif // The return value register EAX is not quite like a caller-save or callee-save // register (technically, it is caller-save). Within a callee, it might appear // that EAX has become dead by the time a return instruction is reached, but // the USE that would make it not dead is in the caller. To prevent type inference // from mistakenly thinking that all USEs of EAX have been seen in the callee, // we add EAX to the USE list for all return instructions, as well as for all // tail calls, which are essentially returns in terms of data flow analysis. // This USE of EAX will always be of type UNINIT unless its DEF has a known type // that propagates to it. Thus, it will prevent an invalid back inference of the // DEF type from "all" USE types that are visible in the callee; even if they // were all NUMERIC, this return USE will be UNINIT and inhibit the invalid // type inference. EAX could be loaded with a pointer from memory, for example, // and USEd only in a comparison instruction, making it falsely appear to be // a NUMERIC, without this extra USE at the return instruction. // Because some of the library functions pass values around in EBX, EDI, etc., // we will add these general purpose registers to the USE list for returns // in order to prevent erroneous analyses of dead registers or unused // metadata. if ((this->type == RETURN) || this->IsTailCall()) { // We want to add the caller-saved registers to the USEs list for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCallerSavedReg(); RegIter != global_STARS_program->GetLastCallerSavedReg(); ++RegIter) { STARS_regnum_t RegNum = (*RegIter); this->MDAddRegUse(RegNum, false); } this->MDAddRegUse(STARS_x86_R_bx, false); if (!UseFP) this->MDAddRegUse(MD_FRAME_POINTER_REG, false); size_t BitWidth = global_STARS_program->GetSTARS_ISA_Bitwidth(); if (BitWidth == 32) { // already caller-saved in x86-64 this->MDAddRegUse(STARS_x86_R_si, false); this->MDAddRegUse(STARS_x86_R_di, false); } else if (BitWidth == 64) { // Add callee-saved regs R12 through R15. We can optimize these away with later analysis, // after we have GlobalNames and LocalNames defined. this->MDAddRegUse(STARS_x86_R_r12, false); this->MDAddRegUse(STARS_x86_R_r13, false); this->MDAddRegUse(STARS_x86_R_r14, false); this->MDAddRegUse(STARS_x86_R_r15, false); } } // Next, add the flags register to the DEFs and USEs for those instructions that // are marked as defining or using flags. if (!this->IsDefsFlags() && SMPDefsFlags[opcode]) { this->MDAddRegDef(X86_FLAGS_REG, false); this->SetDefsFlags(); } if (!this->IsUsesFlags() && SMPUsesFlags[opcode]) { this->MDAddRegUse(X86_FLAGS_REG, false); this->SetUsesFlags(); } #if 1 if (this->IsNop()) { // Clear the DEFs and USEs for no-ops. // These include machine idioms for no-ops, e.g. mov esi,esi // or xchg ax,ax or lea esi,[esi]. this->Defs.clear(); this->Uses.clear(); this->MoveSource = nullptr; this->DEFMemOp = nullptr; this->USEMemOp = nullptr; this->SetLeaMemUseOp(nullptr); // this->OptType = 1; } #endif if (DebugFlag) { SMP_msg("DEBUG after MDFixupDefUseLists:\n"); this->Dump(); } return; } // end of SMPInstr::MDFixupDefUseLists() // Erase DEFs and USEs of callee-preserved registers in call instructions. bool SMPInstr::MDFixupCallDefUseLists(void) { bool InstChanged = false; #if STARS_CONSERVATIVE_DEADREGS return InstChanged; #endif if ((this->type == CALL) || (this->type == INDIR_CALL) || this->IsTailCall()) { // We want to add the caller-saved registers to the USEs and DEFs lists if ((NULL != this->GetBlock()) && (!this->IsInterruptCall())) { STARS_ea_t CalledFuncAddr = this->GetCallTarget(); SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalledFuncAddr); if ((nullptr != CalleeFunc) && (!CalleeFunc->IsLinkerStub())) { // If CalleeFunc has preserved registers by saving them on entry and restoring them before // all return points, then there is no need to conservatively consider these registers to // be USEs or DEFs. They essentially are untouched by the callee. set<DefOrUse, LessDefUse>::iterator DefIter, UseIter; bool CalleeAnalyzed = (CalleeFunc->HasSTARSStackPtrAnalysisCompleted() && CalleeFunc->StackPtrAnalysisSucceeded() && (!CalleeFunc->HasUnresolvedIndirectJumps())); #if 0 // get more conservative for now int IndirCallRegNum = STARS_x86_R_none; if (CalleeAnalyzed && (INDIR_CALL == this->type)) { // We want to avoid removing the register USE for indirect calls, e.g. eax in call eax SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(!CurrRT->HasRightSubTree()); IndirCallRegNum = (int) CurrRT->GetRightOperand()->GetReg(); } #endif for (list<STARS_regnum_t>::iterator RegIter = global_STARS_program->GetFirstCallerSavedReg(); RegIter != global_STARS_program->GetLastCallerSavedReg(); ++RegIter) { STARS_regnum_t RegNum = (*RegIter); STARSOpndTypePtr SearchOp = this->STARSInstPtr->MakeRegOpnd(RegNum); bool ErasedDEF = false; if ((RegNum != MD_RETURN_VALUE_REG) && CalleeFunc->IsRegPreserved(RegNum)) { DefIter = this->FindDef(SearchOp); // assert(DefIter != this->GetLastDef()); // not true for some reason? if (DefIter != this->GetLastDef()) { this->EraseDef(DefIter); ErasedDEF = true; UseIter = this->FindUse(SearchOp); assert(UseIter != this->GetLastUse()); this->EraseUse(UseIter); InstChanged = true; } } #if 0 // get conservative on indirect calls, which can have reg or memory or address reg USEs else if (CalleeAnalyzed && (RegNum != IndirCallRegNum) && (!CalleeFunc->IsLiveIn(SearchOp))) { #else else if (CalleeAnalyzed && (this->type != INDIR_CALL) && (!CalleeFunc->IsLiveIn(SearchOp))) { #endif // Callee stack analysis was successful, so function LiveIn set was computed, // but this register is not LiveIn. We should remove it from the USE list of the call. UseIter = this->FindUse(SearchOp); if (UseIter == this->GetLastUse()) { // Might happen if IDA Pro has chunked a function incorrectly and created what // looks like a tail call as a result. Also, now that we iterate, the USE could have // been removed on a previous iteration. ; } else { this->EraseUse(UseIter); InstChanged = true; } } if ((!ErasedDEF) && CalleeAnalyzed && (RegNum != MD_RETURN_VALUE_REG) && (!CalleeFunc->IsVarKill(SearchOp))) { // Callee has been analyzed, and register is not killed. We should remove it from the DEFs. DefIter = this->FindDef(SearchOp); if (DefIter == this->GetLastDef()) { // Might happen if IDA Pro has chunked a function incorrectly and created what // looks like a tail call as a result. Also, now that we iterate, the USE could have // been removed on a previous iteration. ; } else { this->EraseDef(DefIter); InstChanged = true; } } } } } } return InstChanged; } // end of SMPInstr::MDFixupCallDefUseLists() // If we can definitely identify which part of the addressing expression // used in MemOp is the POINTER type, and it is not a STACKPTR or GLOBALPTR // immediate, set the USE type for that register to POINTER and return true. // If we can find definite NUMERIC addressing registers that are not already // typed as NUMERIC, set their USE types to NUMERIC and return true. bool SMPInstr::MDFindPointerUse(const STARSOpndTypePtr &MemOp, bool UseFP) { bool changed = false; int BaseReg; int IndexReg; SMPOperandType BaseType = UNKNOWN; SMPOperandType IndexType = UNKNOWN; uint16_t ScaleFactor; STARS_ea_t offset; set<DefOrUse, LessDefUse>::iterator BaseIter; set<DefOrUse, LessDefUse>::iterator IndexIter; if (this->MDIsLoadEffectiveAddressInstr()) return false; // lea instruction really has no memory operands if (STARS_NN_fnop == this->GetIDAOpcode()) return false; // SSA marker instruction STARSOpndTypePtr BaseOp = nullptr; STARSOpndTypePtr IndexOp = nullptr; MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, offset); if (STARS_x86_R_none != IndexReg) { IndexOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg)); IndexIter = this->FindUse(IndexOp); assert(IndexIter != this->GetLastUse()); IndexType = IndexIter->GetType(); } if (STARS_x86_R_none != BaseReg) { BaseOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg)); BaseIter = this->FindUse(BaseOp); assert(BaseIter != this->GetLastUse()); BaseType = BaseIter->GetType(); } if (MDIsStackPtrReg(BaseReg, UseFP)) { if ((STARS_x86_R_none != IndexReg) && (!IsNumeric(IndexType))) { // We have an indexed access into the stack frame. // Set IndexReg USE type to NUMERIC. changed = true; IndexIter = this->SetUseType(IndexOp, NUMERIC); assert(IndexIter != this->GetLastUse()); } return changed; // stack accesses will get STACKPTR type in SetImmedTypes() } if (MDIsStackPtrReg(IndexReg, UseFP)) { if ((STARS_x86_R_none != BaseReg) && (!IsNumeric(BaseType))) { // We have an indexed access into the stack frame. // Set BaseReg USE type to NUMERIC. // Note that BaseReg is really an IndexReg and vice versa. changed = true; BaseIter = this->SetUseType(BaseOp, NUMERIC); assert(BaseIter != this->GetLastUse()); SMP_msg("WARNING: BaseReg is index, IndexReg is base: %s\n", DisAsmText.GetDisAsm(this->GetAddr())); } return changed; // stack accesses will get STACKPTR type in SetImmedTypes() } if (IsImmedGlobalAddress(offset)) { if ((STARS_x86_R_none != IndexReg) && (!IsNumeric(IndexType))) { // We have an indexed access into a global. // Set IndexReg USE type to NUMERIC. changed = true; IndexIter = this->SetUseType(IndexOp, NUMERIC); assert(IndexIter != this->GetLastUse()); } if ((STARS_x86_R_none != BaseReg) && (!IsNumeric(BaseType))) { // We have an indexed access into a global. // Set BaseReg USE type to NUMERIC. // Note that BaseReg is really an index register. changed = true; BaseIter = this->SetUseType(BaseOp, NUMERIC); assert(BaseIter != this->GetLastUse()); #if SMP_VERBOSE_FIND_POINTERS SMP_msg("WARNING: BaseReg used as index: %s\n", DisAsmText.GetDisAsm(this->GetAddr())); #endif } return changed; // global immediate is handled in SetImmedTypes() } // At this point, we must have a base address in a register, not used // to directly address the stack or a global. if ((0 < ScaleFactor) || (STARS_x86_R_none == IndexReg)) { // IndexReg is scaled, meaning it is NUMERIC, so BaseReg must // be a POINTER; or IndexReg is not present, so BaseReg is the // only possible holder of an address. if (STARS_x86_R_none != BaseReg) { if (UNINIT == BaseIter->GetType()) { changed = true; BaseIter = this->SetUseType(BaseOp, POINTER); assert(BaseIter != this->GetLastUse()); } } } else if (STARS_x86_R_none == BaseReg) { // We have an unscaled IndexReg and no BaseReg and offset was // not a global offset, so IndexReg must be a POINTER. if (STARS_x86_R_none != IndexReg) { if (UNINIT == IndexType) { changed = true; IndexIter = this->SetUseType(IndexOp, POINTER); assert(IndexIter != this->GetLastUse()); } } } else { // We have BaseReg and an unscaled IndexReg. // The only hope for typing something like [ebx+edx] is for // one register to already be typed NUMERIC, in which case // the other one must be a POINTER, or if one register is // already POINTER, then the other one must be NUMERIC. if (IsNumeric(BaseType)) { if (UNINIT == IndexType) { // Set to POINTER or PROF_POINTER changed = true; IndexIter = this->SetUseType(IndexOp, POINTER); assert(IndexIter != this->GetLastUse()); } else if (IsNumeric(IndexType)) { SMP_msg("ERROR: BaseReg and IndexReg both NUMERIC at %llx: %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } } else { // BaseReg was not NUMERIC if (UNINIT == BaseType) { // BaseReg is UNINIT if (IsNumeric(IndexType)) { changed = true; BaseIter = this->SetUseType(BaseOp, POINTER); assert(BaseIter != this->GetLastUse()); } else if (IsDataPtr(IndexType)) { // IndexReg is POINTER, so make BaseReg NUMERIC. changed = true; BaseIter = this->SetUseType(BaseOp, NUMERIC); assert(BaseIter != this->GetLastUse()); } } else if (IsDataPtr(BaseType)) { // BaseReg was a pointer type. IndexReg must be NUMERIC. if (UNINIT == IndexType) { changed = true; IndexIter = this->SetUseType(IndexOp, NUMERIC); assert(IndexIter != this->GetLastUse()); } else if (IsDataPtr(IndexType)) { SMP_msg("ERROR: BaseReg and IndexReg both POINTER at %llx: %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } } } } return changed; } // end of SMPInstr::MDFindPointerUse() // Are all DEFs typed to something besides UNINIT? bool SMPInstr::AllDEFsTyped(void) { if (this->AreDEFsTyped()) { return true; } bool FoundUNINIT = false; set<DefOrUse, LessDefUse>::iterator DefIter; for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { if (IsEqType(UNINIT, DefIter->GetType())) { FoundUNINIT = true; break; } } if (!FoundUNINIT) { this->SetDEFsTyped(); } return (!FoundUNINIT); } // end of SMPInstr::AllDEFsTyped() // Are all USEs typed to something besides UNINIT? bool SMPInstr::AllUSEsTyped(void) { if (this->AreUSEsTyped()) { return true; } bool FoundUNINIT = false; set<DefOrUse, LessDefUse>::iterator UseIter; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { if (IsEqType(UNINIT, UseIter->GetType())) { FoundUNINIT = true; break; } } if (!FoundUNINIT) { this->SetUSEsTyped(); } return (!FoundUNINIT); } // end of SMPInstr::AllUSEsTyped() // Return true if UseOp is a USE reg, not just an address reg in a memory USE bool SMPInstr::IsNonAddressReg(const STARSOpndTypePtr &UseOp) const { bool FoundUse = false; STARS_regnum_t SearchReg = MDCanonicalizeSubReg(UseOp->GetReg()); for (std::size_t OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(OpNum); if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (Opnd->IsRegOp()) { STARS_regnum_t TestReg = MDCanonicalizeSubReg(Opnd->GetReg()); if (TestReg == SearchReg) { FoundUse = true; break; } } } } return FoundUse; } // end of SMPInstr::IsNonAddressReg() STARS_uval_t SMPInstr::MDGetShiftCount(void) const { STARS_uval_t ShiftCount = 0; if (this->MDIsShiftOrRotate()) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); if (this->MDIsDoubleRegShift()) { // RTL has extra level of depth. assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); } STARSOpndTypePtr ShiftCountOp = CurrRT->GetRightOperand(); assert(nullptr != ShiftCountOp); if (ShiftCountOp->IsImmedOp()) { ShiftCount = ShiftCountOp->GetImmedValue(); } } return ShiftCount; } // end of SMPInstr::MDGetShiftCount() // RTL shows DEF operand is subreg. bool SMPInstr::IsReducedWidthDef(void) const { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); STARSOpndTypePtr DefOp = CurrRT->GetLeftOperand(); return ((nullptr != DefOp) && (! DefOp->IsVoidOp()) && (DefOp->GetByteWidth() < 4)); } // Is a sub-register of UseOp used as a shift counter in the RTL? // For example, UseOp could be ECX on an x86 machine, and CL // could be used as a shift or rotate counter. bool SMPInstr::IsSubRegUsedAsShiftCount(const STARSOpndTypePtr &UseOp) { bool ShiftCounter = false; if ((UseOp->IsRegOp()) && this->MDIsShiftOrRotate()) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); if (this->MDIsDoubleRegShift()) { // RTL has extra level of depth. assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); } STARSOpndTypePtr ShiftCountOp = CurrRT->GetRightOperand(); assert(nullptr != ShiftCountOp); if (ShiftCountOp->IsRegOp()) { STARS_regnum_t UseReg = UseOp->GetReg(); STARS_regnum_t ShiftCountReg = ShiftCountOp->GetReg(); STARS_regnum_t WideUseReg = MDCanonicalizeSubReg(UseReg); STARS_regnum_t WideShiftCountReg = MDCanonicalizeSubReg(ShiftCountReg); if ((UseReg != ShiftCountReg) && (WideUseReg == WideShiftCountReg)) { // Registers were not equal, but their canonical enclosing // registers are equal. Because shift counters that are not // immediate are the 8-bit subregister in x86 (MD here !!!!!!) // it must be that the ShiftCountReg is a subreg of UseReg. // This is the condition we are looking for. ShiftCounter = true; } } } return ShiftCounter; } // end of SMPInstr::IsSubRegUsedAsShiftCount() // Does UseOp ultimately come from a small positive constant? bool SMPInstr::IsOpSourceSmallPositiveConstant(const STARSOpndTypePtr &UseOp, int UseSSANum) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundSmallConst = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundSmallConst = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from small constants // but we only need one of the Phi USEs to come from // a small constant to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a small constant. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceSmallPositiveConstant(UseOp, PhiUseSSANum)) { FoundSmallConst = true; // only one success on all Phi USEs is needed break; } } } } else { bool ValueFound; STARS_uval_t ConstValue; SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); if (DefInst->MDIsSimpleAssignment(ValueFound, ConstValue)) { FoundSmallConst = (ValueFound && (ConstValue <= 2)); if (!FoundSmallConst && !ValueFound && DefInst->MDIsMoveInstr()) { // We have a non-immediate move. Trace back through move source to find small const. STARSOpndTypePtr CopyUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); CanonicalizeOpnd(CopyUseOp); set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(CopyUseOp); assert(UseIter != DefInst->GetLastUse()); int CopyUseSSANum = UseIter->GetSSANum(); FoundSmallConst = DefInst->IsOpSourceSmallPositiveConstant(CopyUseOp, CopyUseSSANum); } } } return FoundSmallConst; } // end of SMPInstr::IsOpSourceSmallPositiveConstant() // Does UseOp ultimately come from a bitwise not instruction? bool SMPInstr::IsOpSourceBitwiseNot(const STARSOpndTypePtr &UseOp, int UseSSANum) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundBitwiseNotInst = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if (STARS_IsSSAMarkerPseudoID(UseDefAddr) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundBitwiseNotInst = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from bitwise nots // but we only need one of the Phi USEs to come from // a bitwise not to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a bitwise not. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceBitwiseNot(UseOp, PhiUseSSANum)) { FoundBitwiseNotInst = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); if (DefInst->MDIsBitwiseNotOpcode()) { FoundBitwiseNotInst = true; } else if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory CanonicalizeOpnd(MoveUseOp); set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); assert(MoveUseIter != DefInst->GetLastUse()); int MoveUseSSANum = MoveUseIter->GetSSANum(); FoundBitwiseNotInst = DefInst->IsOpSourceBitwiseNot(MoveUseOp, MoveUseSSANum); // recurse } } else { // Not a move, not a bitwise not. We must return false. FoundBitwiseNotInst = false; } } return FoundBitwiseNotInst; } // end of SMPInstr::IsOpSourceBitwiseNot() // Does UseOp ultimately come from a set-condition-code instruction? bool SMPInstr::IsOpSourceConditionCode(const STARSOpndTypePtr &UseOp, int UseSSANum) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundConditionalSetInst = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundConditionalSetInst = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from condition codes // but we only need one of the Phi USEs to come from // a condition code to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a condition code. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceConditionCode(UseOp, PhiUseSSANum)) { FoundConditionalSetInst = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); if (DefInst->MDIsAnySetValue()) { FoundConditionalSetInst = true; } else if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory CanonicalizeOpnd(MoveUseOp); set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); assert(MoveUseIter != DefInst->GetLastUse()); int MoveUseSSANum = MoveUseIter->GetSSANum(); FoundConditionalSetInst = DefInst->IsOpSourceConditionCode(MoveUseOp, MoveUseSSANum); // recurse } } else { // Not a move, not a condition code transfer. We must return false. FoundConditionalSetInst = false; } } return FoundConditionalSetInst; } // end of SMPInstr::IsOpSourceConditionCode() // Does UseOp ultimately come from a shift left instruction? bool SMPInstr::IsOpSourceLeftShift(const STARSOpndTypePtr &UseOp, int UseSSANum, STARSOpndTypePtr &ShiftCounterOp, STARSOpndTypePtr &ShiftedOp, STARS_ea_t &ShiftInstAddr) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundLeftShiftInst = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundLeftShiftInst = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from condition codes // but we only need one of the Phi USEs to come from // a condition code to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a condition code. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceLeftShift(UseOp, PhiUseSSANum, ShiftCounterOp, ShiftedOp, ShiftInstAddr)) { FoundLeftShiftInst = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); if (DefInst->MDIsLeftShift()) { FoundLeftShiftInst = true; ShiftInstAddr = UseDefAddr; DefInst->GetShiftOperands(ShiftedOp, ShiftCounterOp); } else if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory CanonicalizeOpnd(MoveUseOp); set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); assert(MoveUseIter != DefInst->GetLastUse()); int MoveUseSSANum = MoveUseIter->GetSSANum(); FoundLeftShiftInst = DefInst->IsOpSourceLeftShift(MoveUseOp, MoveUseSSANum, ShiftCounterOp, ShiftedOp, ShiftInstAddr); // recurse } } else { // Not a move, not a condition code transfer. We must return false. FoundLeftShiftInst = false; } } return FoundLeftShiftInst; } // end of SMPInstr::IsOpSourceLeftShift() // Does UseOp ultimately come from a move-with-zero-extension instruction? bool SMPInstr::IsOpSourceZeroExtendedMove(const STARSOpndTypePtr &UseOp, int UseSSANum, bool TruncationCheck) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundMoveZX = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundMoveZX = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from zero-extended // moves into the UseOp register, but we only need one of the Phi USEs to come from // a zero-extended move to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a zero-extended move. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceZeroExtendedMove(UseOp, PhiUseSSANum, TruncationCheck)) { FoundMoveZX = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); unsigned short SignMask; if (DefInst->MDIsSignedLoad(SignMask)) { FoundMoveZX = (FG_MASK_UNSIGNED == SignMask); } else if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory CanonicalizeOpnd(MoveUseOp); set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); assert(MoveUseIter != DefInst->GetLastUse()); int MoveUseSSANum = MoveUseIter->GetSSANum(); FoundMoveZX = DefInst->IsOpSourceZeroExtendedMove(MoveUseOp, MoveUseSSANum, TruncationCheck); // recurse } } else if (TruncationCheck && DefInst->MDIsNonOverflowingBitManipulation()) { // Not a move, not a zero-extended move. We must return false for the non-truncation case, // but we allow non-overflowing bit manipulation instructions in the chain for truncation checks. // This is because of a benign code pattern: // reg: = zero-extended move // reg := reg AND bit pattern // reg := reg OR bit pattern // store lower bits of reg // Compilers like to do 32-bit arithmetic. There was never any good reason otherwise to zero-extend the // value in the first instruction in the pattern. The lower bits that are stored at the end of the code // sequence are the only bits that ever mattered, so this is not really a truncation. set<DefOrUse, LessDefUse>::iterator BitUseIter = DefInst->FindUse(UseOp); if (BitUseIter != DefInst->GetLastUse()) { int BitUseSSANum = BitUseIter->GetSSANum(); FoundMoveZX = DefInst->IsOpSourceZeroExtendedMove(UseOp, BitUseSSANum, true); // recurse up the chain } } else { FoundMoveZX = false; } } return FoundMoveZX; } // end of SMPInstr::IsOpSourceZeroExtendedMove() // Does UseOp ultimately come from a move-with-zero-extension instruction OR from a condition code OR from a right shift? bool SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(const STARSOpndTypePtr &UseOp, int UseSSANum, bool TruncationCheck) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundMoveZXCC = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarkerID signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundMoveZXCC = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from zero-extended // moves into the UseOp register, but we only need one of the Phi USEs to come from // a zero-extended move to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a zero-extended move. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(UseOp, PhiUseSSANum, TruncationCheck)) { FoundMoveZXCC = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); unsigned short SignMask; if (DefInst->MDIsSignedLoad(SignMask)) { FoundMoveZXCC = (FG_MASK_UNSIGNED == SignMask); } else if (DefInst->MDIsAnySetValue() || DefInst->MDIsShiftRight()) { FoundMoveZXCC = true; } else if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory CanonicalizeOpnd(MoveUseOp); set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); assert(MoveUseIter != DefInst->GetLastUse()); int MoveUseSSANum = MoveUseIter->GetSSANum(); FoundMoveZXCC = DefInst->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(MoveUseOp, MoveUseSSANum, TruncationCheck); // recurse } } else if (TruncationCheck && (DefInst->MDIsNonOverflowingBitManipulation() || DefInst->MDIsSmallAdditionOrSubtraction())) { // Not a move, not a zero-extended move. We must return false for the non-truncation case, // but we allow non-overflowing bit manipulation instructions in the chain for truncation checks. // This is because of a benign code pattern: // reg: = zero-extended move // reg := reg AND bit pattern // reg := reg OR bit pattern // store lower bits of reg // Compilers like to do 32-bit arithmetic. There was never any good reason otherwise to zero-extend the // value in the first instruction in the pattern. The lower bits that are stored at the end of the code // sequence are the only bits that ever mattered, so this is not really a truncation. // NOTE: We combine into this case additions or subtractions of small values, as they only operate on the // lower bits of the register. set<DefOrUse, LessDefUse>::iterator BitUseIter = DefInst->FindUse(UseOp); if (BitUseIter != DefInst->GetLastUse()) { int BitUseSSANum = BitUseIter->GetSSANum(); FoundMoveZXCC = DefInst->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(UseOp, BitUseSSANum, true); // recurse up the chain } } else { FoundMoveZXCC = false; } } return FoundMoveZXCC; } // end of SMPInstr::IsOpSourceZeroExtendedMoveShiftRightOrConditionCode() // Trace through moves to any of the above cases, return source inst bool SMPInstr::IsOpSourceSpecial(const STARSOpndTypePtr &UseOp, int UseSSANum, bool TruncationCheck, STARS_ea_t &SourceInstAddr) { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool FoundMoveNotZXCCSubreg = false; bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. FoundMoveNotZXCCSubreg = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from zero-extended // moves into the UseOp register, but we only need one of the Phi USEs to come from // a zero-extended move to potentially lead to a false positive numeric error. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a zero-extended move. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceSpecial(UseOp, PhiUseSSANum, TruncationCheck, SourceInstAddr)) { FoundMoveNotZXCCSubreg = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); unsigned short SignMask; if (DefInst->MDIsSignedLoad(SignMask)) { FoundMoveNotZXCCSubreg = ((FG_MASK_UNSIGNED == SignMask) || TruncationCheck); // Truncation chain cares if source was reduced width. if (FoundMoveNotZXCCSubreg) { SourceInstAddr = DefInst->GetAddr(); } } else if (DefInst->MDIsAnySetValue() || DefInst->MDIsShiftRight() || DefInst->MDIsBitwiseNotOpcode()) { FoundMoveNotZXCCSubreg = true; SourceInstAddr = DefInst->GetAddr(); } else if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); if (MDIsDataFlowOpnd(MoveUseOp, UseFP)) { // pattern is simple; don't try to follow through non-stack memory CanonicalizeOpnd(MoveUseOp); set<DefOrUse, LessDefUse>::iterator MoveUseIter = DefInst->FindUse(MoveUseOp); assert(MoveUseIter != DefInst->GetLastUse()); int MoveUseSSANum = MoveUseIter->GetSSANum(); FoundMoveNotZXCCSubreg = DefInst->IsOpSourceSpecial(MoveUseOp, MoveUseSSANum, TruncationCheck, SourceInstAddr); // recurse } } else if (TruncationCheck && (DefInst->MDIsNonOverflowingBitManipulation() || DefInst->MDIsSmallAdditionOrSubtraction())) { // Not a move, not a zero-extended move. We must return false for the non-truncation case, // but we allow non-overflowing bit manipulation instructions in the chain for truncation checks. // This is because of a benign code pattern: // reg: = zero-extended move // reg := reg AND bit pattern // reg := reg OR bit pattern // store lower bits of reg // Compilers like to do 32-bit arithmetic. There was never any good reason otherwise to zero-extend the // value in the first instruction in the pattern. The lower bits that are stored at the end of the code // sequence are the only bits that ever mattered, so this is not really a truncation. // NOTE: We combine into this case additions or subtractions of small values, as they only operate on the // lower bits of the register. set<DefOrUse, LessDefUse>::iterator BitUseIter = DefInst->FindUse(UseOp); if (BitUseIter != DefInst->GetLastUse()) { int BitUseSSANum = BitUseIter->GetSSANum(); FoundMoveNotZXCCSubreg = DefInst->IsOpSourceSpecial(UseOp, BitUseSSANum, true, SourceInstAddr); // recurse up the chain } } else if (TruncationCheck) { // Check for reduced-width arithmetic. if (DefInst->IsReducedWidthDef()) { // chain like sub cl,3; mov eax,ecx; then "truncating" move of al FoundMoveNotZXCCSubreg = true; SourceInstAddr = DefInst->GetAddr(); } } } return FoundMoveNotZXCCSubreg; } // end of SMPInstr::IsOpSourceSpecial() // Does UseOp ultimately come from a byte swap? bool SMPInstr::IsOpSourceByteSwap(const STARSOpndTypePtr &UseOp, int UseSSANum, STARS_ea_t &ByteSwapAddr) { // Byte swap operations typically look like: // byte move memloc into reg1, zero-extended // byte mov memloc+1 into reg2, zero-extended // shift reg1 left 8 bits // OR reg2 into reg1 // reg1 is now a byte-swap of the two bytes at memloc+1:memloc bool ByteSwapFound = false; bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if ((UseSSANum == -1) || (!MDIsDataFlowOpnd(UseOp, UseFP))) { return false; } bool RegDef = (UseOp->IsRegOp()); bool LocalName = this->GetBlock()->IsLocalName(UseOp); bool IndirectMemAccess = MDIsIndirectMemoryOpnd(UseOp, UseFP); bool AboveStackFrame = (!RegDef && !IndirectMemAccess && (this->GetBlock()->GetFunc()->AccessAboveLocalFrame(UseOp, this->AreDefsNormalized(), this->GetAddr(), false))); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t FirstFuncAddr = this->GetBlock()->GetFunc()->GetFirstFuncAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); bool UpExposedUse = STARS_IsLiveInPseudoID(UseDefAddr); if (!LocalName && !AboveStackFrame && !IndirectMemAccess && ((UseDefAddr == STARS_BADADDR) || UpExposedUse)) { // Try to find in the function level. UseDefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(UseOp, UseSSANum); } if ((STARS_IsSSAMarkerPseudoID(UseDefAddr)) || AboveStackFrame || (UseDefAddr == STARS_BADADDR) || IndirectMemAccess) { // Cannot search for general memory DEFs for non-local names; must be stack or register. // SSAMarker signifies the pseudo-inst to hold DEFs of regs // that are LiveIn to the function; pseudo-inst is not a bitwise not. // First block addr - 1 is pseudo-location that indicates live-in, UpExposed, // and LocalName means we will not find a DEF anywhere besides this block. // AboveStackFrame means an incoming arg, whose DEF will not be seen. ByteSwapFound = false; } else if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from byte-swap // moves into the UseOp register, but we only need one of the Phi USEs to come from // a byte-swap to potentially lead to a user tainting of the critical argument. We // will recurse on all Phi USEs, declaring success if we find a single one of them // to come from a byte swap. std::size_t BlockNum = STARS_GetBlockNumFromPseudoID(UseDefAddr); assert(!LocalName); SMPBasicBlock *PhiDefBlock = this->GetBlock()->GetFunc()->GetBlockByNum(BlockNum); assert(NULL != PhiDefBlock); if (!PhiDefBlock->IsProcessed()) { // Prevent infinite recursion set<SMPPhiFunction, LessPhi>::iterator DefPhiIter = PhiDefBlock->FindPhi(UseOp); assert(DefPhiIter != PhiDefBlock->GetLastPhi()); std::size_t PhiListSize = DefPhiIter->GetPhiListSize(); PhiDefBlock->SetProcessed(true); // Prevent infinite recursion for (std::size_t UseIndex = 0; UseIndex < PhiListSize; ++UseIndex) { int PhiUseSSANum = DefPhiIter->GetUseSSANum(UseIndex); if (this->IsOpSourceByteSwap(UseOp, PhiUseSSANum, ByteSwapAddr)) { ByteSwapFound = true; // only one success on all Phi USEs is needed break; } } } } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); if (DefInst->MDIsBitwiseOrOpcode()) { // Found the OR operation. Find zero-extended byte loads of each operand of the OR. SMPRegTransfer *CurrRT = DefInst->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); if (!CurrRT->HasRightSubTree()) { assert(SMP_BITWISE_OR == CurrRT->GetOperator()); STARSOpndTypePtr LeftOp = CloneIfSubwordReg(CurrRT->GetLeftOperand()); STARSOpndTypePtr RightOp = CloneIfSubwordReg(CurrRT->GetRightOperand()); if (! RightOp->IsImmedOp()) { bool LeftSuccess = true; // Trace OR DEF/USE LeftOp back to shift left within its same block. CanonicalizeOpnd(LeftOp); set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(LeftOp); assert(UseIter != DefInst->GetLastUse()); int LeftUseSSANum = UseIter->GetSSANum(); bool LocalName2 = DefInst->GetBlock()->IsLocalName(LeftOp); STARS_ea_t ShiftAddr = DefInst->GetBlock()->GetDefAddrFromUseAddr(LeftOp, UseDefAddr, LeftUseSSANum, LocalName2); SMPInstr *ShiftInst; bool UseDefAddrIsPseudoID = (STARS_PSEUDO_ID_MIN <= UseDefAddr); // Limit to case where shift left is in same block as OR. if (!UseDefAddrIsPseudoID && (ShiftAddr >= DefInst->GetBlock()->GetFirstAddr()) && (ShiftAddr < UseDefAddr)) { ShiftInst = DefInst->GetBlock()->FindInstr(ShiftAddr); if (ShiftInst->MDIsLeftShift()) { STARSOpndTypePtr ShiftedOp, ShiftCounterOp; ShiftInst->GetShiftOperands(ShiftedOp, ShiftCounterOp); if ((ShiftCounterOp->IsImmedOp()) && (8 == ShiftCounterOp->GetImmedValue())) { ; } else { LeftSuccess = false; // failure } } else { LeftSuccess = false; // failure } } else { LeftSuccess = false; // failure } STARSOpndTypePtr LeftMemOp = nullptr; STARSOpndTypePtr RightMemOp = nullptr; // Trace LeftOp and RightOp back to zero-extended byte memory loads. if (LeftSuccess && IsMemOperand(LeftOp) && (1 == LeftOp->GetByteWidth())) { // We are using OR on a byte memory location; already found the ultimate memory source. LeftMemOp = LeftOp; } else if (LeftSuccess && LeftOp->IsRegOp()) { // Trace reg back to zero-extended load. set<DefOrUse, LessDefUse>::iterator UseIter = ShiftInst->FindUse(LeftOp); assert(UseIter != ShiftInst->GetLastUse()); int LeftUseSSANum = UseIter->GetSSANum(); STARS_ea_t LeftMemAddr; if (ShiftInst->IsOpSourceSpecial(LeftOp, LeftUseSSANum, false, LeftMemAddr)) { SMPInstr *LeftDefInst = ShiftInst->GetBlock()->GetFunc()->GetInstFromAddr(LeftMemAddr); unsigned short SignMask; if (LeftDefInst->MDIsSignedLoad(SignMask)) { if (SignMask == FG_MASK_UNSIGNED) { // zero-extended load LeftMemOp = LeftDefInst->GetMoveSource(); } } } } if (IsMemOperand(RightOp) && (1 == RightOp->GetByteWidth())) { // We are using OR on a byte memory location; already found the ultimate memory source. RightMemOp = RightOp; } else if (LeftSuccess && IsMemOperand(LeftMemOp) && RightOp->IsRegOp()) { // Trace reg back to zero-extended load. CanonicalizeOpnd(RightOp); set<DefOrUse, LessDefUse>::iterator UseIter = DefInst->FindUse(RightOp); assert(UseIter != DefInst->GetLastUse()); int RightUseSSANum = UseIter->GetSSANum(); STARS_ea_t RightMemAddr; if (DefInst->IsOpSourceSpecial(RightOp, RightUseSSANum, false, RightMemAddr)) { SMPInstr *RightDefInst = DefInst->GetBlock()->GetFunc()->GetInstFromAddr(RightMemAddr); unsigned short SignMask; if (RightDefInst->MDIsSignedLoad(SignMask)) { if (SignMask == FG_MASK_UNSIGNED) { // zero-extended load RightMemOp = RightDefInst->GetMoveSource(); } } } } if (LeftSuccess && IsMemOperand(LeftMemOp) && IsMemOperand(RightMemOp) && (1 == LeftMemOp->GetByteWidth()) && (1 == RightMemOp->GetByteWidth())) { // Is RightMemOp equal to LeftMemOp plus one in the address space? STARS_ea_t LeftAddr = LeftMemOp->GetAddr(); if (RightMemOp->GetAddr() == (LeftAddr + 1)) { LeftMemOp->SetAddr(LeftAddr + 1); // increment before comparing all fields if (IsEqOp(LeftMemOp, RightMemOp)) { ByteSwapFound = true; ByteSwapAddr = UseDefAddr; // record address of the OR instruction } } } } } } } return ByteSwapFound; } // end of SMPInstr::IsOpSourceByteSwap() bool IsOpSourceInArg(const STARSOpndTypePtr &UseOp, int UseSSANum, STARSOpndTypePtr &InArgOp); // Does UseOp trace back to InArgOp in SSA marker inst? bool SMPInstr::MDIsDivision(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_div == opcode) || (STARS_NN_idiv == opcode)); } // Is opcode a shift or rotate? // NOTE: We omit MMX/SSE unit shifts that do not use a general purpose // register as a shift counter, because right now this method is only // used as a helper for IsSubRegUsedAsShiftCount(). bool SMPInstr::MDIsShiftOrRotate(void) const { unsigned short opcode = this->GetIDAOpcode(); return (((STARS_NN_rcl <= opcode) && (STARS_NN_ror >= opcode)) || ((STARS_NN_sal <= opcode) && (STARS_NN_shr >= opcode)) || (STARS_NN_shld == opcode) || (STARS_NN_shrd == opcode)); } // end of SMPInstr::MDIsShiftOrRotate() // Is opcode a shift to the right? bool SMPInstr::MDIsShiftRight(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_sar == opcode) || (STARS_NN_shr == opcode)); } // Shift of two regs concatenated together? bool SMPInstr::MDIsDoubleRegShift(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_shld == opcode) || (STARS_NN_shrd == opcode)); } // Does the shift or rotate RTL move the upper HalfBitWidth bits // into the lower half of the register? Or, if MustBeHalfRegWidth is false, // do we shift right by HalfBitWidth bits? bool SMPInstr::ShiftMakesUpperBitsLower(std::size_t HalfBitWidth, bool MustBeHalfRegWidth) { bool FullCircle = false; if (!MustBeHalfRegWidth || (MD_NORMAL_MACHINE_BITWIDTH == (HalfBitWidth * 2))) { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if ((NULL != CurrRT) && (CurrRT->HasRightSubTree())) { CurrRT = CurrRT->GetRightTree(); SMPoperator CurrOper = CurrRT->GetOperator(); bool LeftRotate = (SMP_ROTATE_LEFT == CurrOper); if ((SMP_U_RIGHT_SHIFT == CurrOper) || (SMP_S_RIGHT_SHIFT == CurrOper) || LeftRotate || (SMP_ROTATE_RIGHT == CurrOper)) { if (CurrRT->HasRightSubTree()) { // double-word shift CurrRT = CurrRT->GetRightTree(); } assert(!(CurrRT->HasRightSubTree())); STARSOpndTypePtr ShiftCount = CurrRT->GetRightOperand(); if (ShiftCount->IsImmedOp()) { STARS_uval_t ImmVal = ShiftCount->GetImmedValue(); // If we rotate left by e.g. 32-HalfBitWidth bits, then we are processing // bytes or halfregs one at a time; if we rotate or shift right by HalfBitWidth, // we are processing the register one HalfBitWidth at a time. We also a if (MustBeHalfRegWidth || (!LeftRotate)) { FullCircle = (HalfBitWidth == ImmVal); } else { // Left rotate amount plus HalfBitWidth must add up to full register width FullCircle = (MD_NORMAL_MACHINE_BITWIDTH == (ImmVal + HalfBitWidth)); } } } } } return FullCircle; } // SMPInstr::ShiftMakesUpperBitsLower() #if 0 // Find SearchDelta in StackDeltaSet, inserting it if not found. Return whether it was initially found. bool SMPInstr::FindStackPtrDelta(STARS_sval_t SearchDelta) const { bool found = (this->StackDeltaSet.find(SearchDelta) != this->StackDeltaSet.end()); if (!found) { this->StackDeltaSet.insert(SearchDelta); if (SearchDelta < this->StackPtrOffset) { // Mimic IDA Pro, which seems to keep the biggest stack frame possible. // With negative stack deltas, this means the smallest stack delta is kept. this->SetStackPtrOffset(SearchDelta); } } return found; } // end of SMPInstr::FindStackPtrDelta() #endif // Set the type of all immediate operands found in the USE set. // Set all flags and floating point register USEs and DEFs to NUMERIC also, // along with easily determined types for special cases. void SMPInstr::SetImmedTypes(bool UseFP) { set<DefOrUse, LessDefUse>::iterator CurrUse; set<DefOrUse, LessDefUse>::iterator CurrDef; STARSOpndTypePtr UseOp = nullptr; STARSOpndTypePtr DefOp = nullptr; STARS_uval_t ImmVal; bool DebugFlag = false; #if SMP_VERBOSE_DEBUG_BUILD_RTL DebugFlag = DebugFlag || (this->GetAddr() == 0x805cd52) || (this->GetAddr() == 0x805cd56); DebugFlag |= (0 == strncmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName(), 15)); #endif CurrUse = this->GetFirstUse(); while (CurrUse != this->GetLastUse()) { UseOp = CurrUse->GetOp(); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) { SMP_msg("SetImmedTypes USE: "); PrintOperand(UseOp); SMP_msg("\n"); } #endif if (UseOp->IsImmedOp()) { ImmVal = UseOp->GetImmedValue(); bool NonZero = (0 != ImmVal); if (IsImmedGlobalAddress((STARS_ea_t) ImmVal)) { // NOTE: Const could fall in this range by chance. !!!!****!!!!**** #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting to GLOBALPTR\n"); #endif CurrUse = this->SetUseType(UseOp, GLOBALPTR); } #if 1 else if (global_STARS_program->IsImmedDataAddress((STARS_ea_t) ImmVal)) { // NOTE: We must have a deeper analysis before we call IsImmedCodeAddress() // to catch the data addresses within the code address range. #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting to POINTER\n"); #endif CurrUse = this->SetUseType(UseOp, POINTER); } #endif else if (this->IsInterruptCall() || (NonZero && global_STARS_program->IsImmedCodeAddress((STARS_ea_t) ImmVal))) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting to CODEPTR\n"); #endif CurrUse = this->SetUseType(UseOp, CODEPTR); } else { // NUMERIC #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting to NUMERIC\n"); #endif CurrUse = this->SetUseType(UseOp, NUMERIC); } } else if (UseOp->IsRegOp()) { if (UseOp->MatchesReg(MD_FLAGS_REG)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting flags reg to NUMERIC\n"); #endif CurrUse = this->SetUseType(UseOp, NUMERIC); } else if (UseOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting program counter reg to CODEPTR\n"); #endif CurrUse = this->SetUseType(UseOp, CODEPTR); } #if 1 else if (MDIsStackOrFramePointerReg(UseOp, UseFP)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting reg to STACKPTR\n"); #endif CurrUse = this->SetUseType(UseOp, STACKPTR); } #endif } #if 0 // could these registers have pointers in them? else if (UseOp->IsTestRegOp() || UseOp->IsDebugRegOp() || UseOp->IsControlRegOp()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting special reg to NUMERIC\n"); #endif CurrUse = this->SetUseType(UseOp, NUMERIC); } #endif else if (UseOp->IsFloatingPointRegOp() || UseOp->IsMMXRegOp() || UseOp->IsXMMRegOp() || UseOp->IsYMMRegOp()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting floating point reg to NUMERIC\n"); #endif CurrUse = this->SetUseType(UseOp, NUMERIC); } else if (UseOp->IsMemOp()) { // For memory operands, we need to identify the POINTER value that // is used in the addressing mode, if possible. (void) this->MDFindPointerUse(UseOp, UseFP); } ++CurrUse; } // end while all USEs via CurrUse CurrDef = this->GetFirstDef(); while (CurrDef != this->GetLastDef()) { DefOp = CurrDef->GetOp(); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) { SMP_msg("SetImmedTypes DEF: "); PrintOperand(DefOp); SMP_msg("\n"); SMP_msg("FuncName: %s\n", this->BasicBlock->GetFunc()->GetFuncName()); } #endif if (DefOp->IsRegOp()) { if (DefOp->MatchesReg(X86_FLAGS_REG)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting flags reg DEF to NUMERIC\n"); #endif CurrDef = this->SetDefType(DefOp, NUMERIC); // No need to propagate this DEF type, as all flags will become NUMERIC. } #if 1 else if (MDIsStackOrFramePointerReg(DefOp, UseFP)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting reg DEF to STACKPTR\n"); #endif CurrDef = this->SetDefType(DefOp, STACKPTR); assert(CurrDef != this->Defs.GetLastRef()); // No need to propagate; all stack and frame pointers will become STACKPTR. } #endif } else if (DefOp->IsFloatingPointRegOp() || DefOp->IsMMXRegOp() || DefOp->IsXMMRegOp() || DefOp->IsYMMRegOp()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting floating point reg DEF to NUMERIC\n"); #endif CurrDef = this->SetDefType(DefOp, NUMERIC); // No need to propagate; all FP reg uses will become NUMERIC anyway. } #if 0 // could these registers have pointers in them? else if (DefOp->IsTestRegOp() || DefOp->IsDebugRegOp() || DefOp->IsControlRegOp()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) SMP_msg("Setting special reg DEF to NUMERIC\n"); #endif CurrDef = this->SetDefType(DefOp, NUMERIC); } #endif else if (DefOp->IsMemOp()) { // For memory operands, we need to identify the POINTER value that // is used in the addressing mode, if possible. (void) this->MDFindPointerUse(DefOp, UseFP); } ++CurrDef; } // end while all DEFs via CurrDef return; } // end of SMPInstr::SetImmedTypes() // Is the instruction a load from the stack? void SMPInstr::MDFindLoadFromStack(bool UseFP) { set<DefOrUse, LessDefUse>::iterator UseIter; if ((3 == this->GetOptType()) && (this->HasSourceMemoryOperand())) { // Loads and stores are OptCategory 3. We want only loads from the stack. for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { STARSOpndTypePtr UseOp = UseIter->GetOp(); if (MDIsStackAccessOpnd(UseOp, UseFP)) { this->SetLoadFromStack(); break; } } } return; } // end of SMPInstr::MDFindLoadFromStack() // return true if instruction is a system call bool SMPInstr::MDIsSystemCall(void) { unsigned short opcode = this->GetIDAOpcode(); bool SystemCall = ((STARS_NN_syscall == opcode) || (STARS_NN_sysenter == opcode)); if (!SystemCall && this->IsInterruptCall()) { // If interrupt call is int 0x80 then it is a system call SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(NULL != CurrRT); if (!CurrRT->HasRightSubTree()) { if (CurrRT->GetConstRightOperandNoNorm()->IsImmedOp()) { SystemCall = (0x80 == CurrRT->GetConstRightOperandNoNorm()->GetImmedValue()); } } } if (SystemCall) SMP_msg("INFO: System call found at %llx\n", (unsigned long long) this->GetAddr()); return SystemCall; } // end of SMPInstr::MDIsSystemCall() // Determine if instr is inherently signed load instruction. // True if sign or zero-extended; pass out mask bits if true. bool SMPInstr::MDIsSignedLoad(unsigned short &SignMask) const { unsigned short opcode = this->GetIDAOpcode(); if (STARS_NN_movzx == opcode) { SignMask = FG_MASK_UNSIGNED; } else if ((STARS_NN_movsx == opcode) || (STARS_NN_movsxd == opcode)) { SignMask = FG_MASK_SIGNED; } else { return false; } return true; } // e.g. add-with-carry or subtract-with-borrow bool SMPInstr::MDIsArithmeticUsingCarryFlag(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((opcode == STARS_NN_adc) || (opcode == STARS_NN_sbb)); } // true if increment or addition of small positive immediate value #define STARS_SMALL_POS_VALUE_LIMIT 255 bool SMPInstr::MDIsSmallPositiveAddition(void) { unsigned short opcode = this->GetIDAOpcode(); bool found = (STARS_NN_inc == opcode); STARS_uval_t ImmVal; if (!found && ((STARS_NN_add == opcode) || (STARS_NN_adc == opcode))) { set<DefOrUse, LessDefUse>::iterator UseIter; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { STARSOpndTypePtr UseOp = UseIter->GetOp(); if (UseOp->IsImmedOp()) { ImmVal = UseOp->GetImmedValue(); if ((ImmVal <= STARS_SMALL_POS_VALUE_LIMIT) && (0 < ImmVal)) { found = true; break; } } } } else if (this->MDIsLoadEffectiveAddressInstr()) { // See if we have the form: lea reg1,[reg2+const] SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if (CurrRT->HasRightSubTree()) { CurrRT = CurrRT->GetRightTree(); SMPoperator CurrOp = CurrRT->GetOperator(); if ((SMP_ADD == CurrOp) && (!CurrRT->HasRightSubTree())) { STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { ImmVal = RightOp->GetImmedValue(); if ((ImmVal <= STARS_SMALL_POS_VALUE_LIMIT) && (0 < ImmVal)) { found = true; } } } } } return found; } // end of SMPInstr::MDIsSmallPositiveAddition() // true if increment, decrement, or addition or subtraction of small immediate value bool SMPInstr::MDIsSmallAdditionOrSubtraction(void) { unsigned short opcode = this->GetIDAOpcode(); bool found = ((STARS_NN_inc == opcode) || (STARS_NN_dec == opcode)); if ((STARS_NN_add == opcode) || (STARS_NN_adc == opcode) || (STARS_NN_sub == opcode) || (STARS_NN_sbb == opcode)) { set<DefOrUse, LessDefUse>::iterator UseIter; for (UseIter = this->GetFirstUse(); !found && (UseIter != this->GetLastUse()); ++UseIter) { STARSOpndTypePtr UseOp = UseIter->GetOp(); if (UseOp->IsImmedOp()) { STARS_uval_t ImmVal = UseOp->GetImmedValue(); int SignedImmVal = (int) ImmVal; found = ((SignedImmVal >= (-STARS_SMALL_POS_VALUE_LIMIT)) && (SignedImmVal <= STARS_SMALL_POS_VALUE_LIMIT)); } } } return found; } // end of SMPInstr::MDIsSmallAdditionOrSubtraction() // Inst is move or register clear. bool SMPInstr::MDIsSimpleAssignment(bool &ValueFound, STARS_uval_t &ConstValue) { bool Simple = false; ValueFound = false; if (this->IsRegClearIdiom()) { Simple = true; ValueFound = true; ConstValue = 0; } else if (this->MDIsMoveInstr()) { Simple = true; if (this->GetMoveSource()->IsImmedOp()) { ValueFound = true; ConstValue = this->GetMoveSource()->GetImmedValue(); } } return Simple; } // end of SMPInstr::MDIsSimpleAssignment() // RTL is just x := y; bool SMPInstr::IsSimpleCopy(STARSOpndTypePtr &rhs) const { bool SimpleCopyRTL = false; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if ((NULL != CurrRT) && (this->RTL.GetCount() == 1) && (NULL == CurrRT->GetGuard())) { // skip conditional moves bool Simple = ((!CurrRT->HasRightSubTree()) || this->IsRegUpperBitsClearIdiom()); if (Simple && (SMP_ASSIGN == CurrRT->GetOperator())) { SimpleCopyRTL = (DEFAULT == this->GetDataFlowType()); if (SimpleCopyRTL) { if (this->IsRegUpperBitsClearIdiom()) { rhs = this->GetFirstRightOperandNoNorm(); if (this->AreDefsNormalized() && MDIsStackAccessOpnd(rhs, this->GetBlock()->GetFunc()->UsesFramePointer())) { rhs = this->GetBlock()->GetFunc()->GetNormalizedOperand(this->GetAddr(), rhs); } } else { rhs = CurrRT->GetRightOperand(); } } } } return SimpleCopyRTL; } // SMPInstr::IsSimpleCopy() // RTL is just x := y; don't normalize rhs operand bool SMPInstr::IsSimpleCopyNoNorm(STARSOpndTypePtr &rhs) const { bool SimpleCopyRTL = false; SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if ((NULL != CurrRT) && (this->RTL.GetCount() == 1) && (NULL == CurrRT->GetGuard())) { // skip conditional moves if (!CurrRT->HasRightSubTree() && (SMP_ASSIGN == CurrRT->GetOperator())) { SimpleCopyRTL = (DEFAULT == this->GetDataFlowType()); if (SimpleCopyRTL) rhs = CurrRT->GetRightOperandNoNorm(); } } return SimpleCopyRTL; } // SMPInstr::IsSimpleCopyNoNorm() // Inst clears register or adds or subtracts small immediate value, as is done with counter variables. bool SMPInstr::IsCounterOperation(void) { bool CounterOperation = false; if (this->IsAnalyzeable()) { bool ImmedValueFound = false; STARS_uval_t ConstValue = 1; if (this->MDIsSimpleAssignment(ImmedValueFound, ConstValue)) { CounterOperation = (ImmedValueFound && (0 == ConstValue)); } else { CounterOperation = this->MDIsSmallAdditionOrSubtraction(); } } return CounterOperation; } // end of SMPInstr::IsCounterOperation() // Inst does an AND, OR, XOR operation; does not do add, subtract, etc. bool SMPInstr::MDIsNonOverflowingBitManipulation(void) const { unsigned short opcode = this->GetIDAOpcode(); return ((STARS_NN_and == opcode) || (STARS_NN_not == opcode) || (STARS_NN_or == opcode) || (STARS_NN_shl == opcode) || ((STARS_NN_xor == opcode) && !this->IsRegClearIdiom())); } // end of SMPInstr::MDIsNonOverflowingBitManipulation() // return true if traced USE to a constant value bool SMPInstr::FindConstantValue(set<DefOrUse, LessDefUse>::iterator UseIter, STARS_uval_t &ConstValue) { bool FoundConst = false; assert(UseIter != this->GetLastUse()); STARSOpndTypePtr UseOp = UseIter->GetOp(); if (UseOp->IsImmedOp()) { ConstValue = UseOp->GetImmedValue(); FoundConst = true; } else { bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if (MDIsDataFlowOpnd(UseOp, UseFP)) { // We can trace registers and stack locations through SSA chains, if the stack location is directly accessed. int UseSSANum = UseIter->GetSSANum(); bool LocalName = this->GetBlock()->IsLocalName(UseOp); STARS_ea_t UseAddr = this->GetAddr(); STARS_ea_t UseDefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, UseAddr, UseSSANum, LocalName); if (STARS_IsBlockNumPseudoID(UseDefAddr)) { // A block number was returned. That means the DEF is in a Phi Function. // We could trace all Phi USEs and see if all of them come from a single // constant value, but this is highly unlikely. Terminate search. ; } else if (STARS_IsLiveInPseudoID(UseDefAddr) || (STARS_BADADDR == UseDefAddr)) { // The DEF is in a Phi function in the current block, or is STARS_BADADDR. Terminate search. ; } else { SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(UseDefAddr); bool ValueFound = false; if (DefInst->MDIsSimpleAssignment(ValueFound, ConstValue)) { if (ValueFound) { FoundConst = true; // ConstValue holds the value that was found. } else { set<DefOrUse, LessDefUse>::iterator NewUseIter = DefInst->GetFirstUse(); // A simple assignment should have only one USE. Recurse on that USE. FoundConst = DefInst->FindConstantValue(NewUseIter, ConstValue); } } } } } return FoundConst; } // end of SMPInstr::FindConstantValue() // Infer sign, bit width, other type info for simple cases where all the info needed is // within the instruction or can be read from the FineGrainedStackTable in the SMPFunction. // NOTE: Must be called after SSA analysis is complete. void SMPInstr::MDSetWidthSignInfo(bool UseFP) { if (! this->IsAnalyzeable()) return; set<DefOrUse, LessDefUse>::iterator UseIter; set<DefOrUse, LessDefUse>::iterator DefIter; STARSOpndTypePtr UseOp = nullptr, DefOp = nullptr; struct FineGrainedInfo FGEntry; unsigned short SignMask=0, TempSign=0, WidthMask=0; int DefHashValue=0, UseHashValue=0; STARS_ea_t DefAddr=0; // for flags USE in conditional set int SSANum=0; // for flags USE in conditional set bool LocalFlags=0; // is flags register a local name? bool case1=0, case2=0, case3=0, case4=0, case5=0, case6=0, case7=0, case8=0; bool SignedSetOpcode = this->MDIsSignedSetValue(); bool UnsignedSetOpcode = this->MDIsUnsignedSetValue(); case1 = this->IsLoadFromStack(); case2 = this->MDIsSignedLoad(SignMask); // sets value of SignMask if it returns true case3 = (7 == this->GetOptType()); // Multiplies and divides case4 = ((CALL == this->GetDataFlowType()) || (INDIR_CALL == this->GetDataFlowType())); case5 = (SignedSetOpcode || UnsignedSetOpcode); // set boolean based on flag condition case6 = this->MDDoublesWidth(); // convert byte to word, word to dword, etc. case7 = this->MDAlwaysUnsignedDEF(); case8 = this->MDAlwaysSignedDEF(); // Case 1: Load from stack location. if (case1) { bool success = false; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { UseOp = UseIter->GetOp(); if (MDIsStackAccessOpnd(UseOp, UseFP)) { // Found the stack location being loaded into a register. Now we need // to get the sign and width info from the fine grained stack frame // analysis. success = this->GetBlock()->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), UseOp, FGEntry); assert(success); // Now we have signedness info in FGEntry. We need to OR it into the register target of the load. if (FGEntry.SignMiscInfo == 0) break; // nothing to OR in; save time for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { DefOp = DefIter->GetOp(); if (DefOp->IsRegOp()) { TempSign = FGEntry.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS; // Get both sign bit flags DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum()); if (this->BasicBlock->IsLocalName(DefOp)) { this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, TempSign); } else { this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, TempSign); } break; // Should be only one register target for stack load, and no flags are set. } } break; // Only concerned with the stack operand } } assert(success); } // end if this->IsLoadFromStack() // Case 2: Loads that are sign-extended or zero-extended imply signed and unsigned, respectively. // NOTE: If from the stack, they were handled in Case 1, and the signedness of the stack location // was recorded a long time ago in SMPFunction::FindOutgoingArgsSize(); else if (case2) { DefIter = this->GetFirstDef(); while (DefIter != this->GetLastDef()) { // All non-memory DEFs besides the flags register should get the new SignMask ORed in. // On x86, there should only be one DEF for this move, and no flags, but we will generalize // in case other architectures are odd. DefOp = DefIter->GetOp(); if (!(IsMemOperand(DefOp) || MDIsFlagsReg(DefOp))) { DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum()); if (this->BasicBlock->IsLocalName(DefOp)) { this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, SignMask); } else { this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask); } } ++DefIter; } // If the signed load is from memory, the only USEs are the memory // operand and addressing registers. We do not want to claim that // EBX is signed in the instruction movsx eax,[ebx]. Only the DEF // register EAX and the memory location [EBX] are signed, and we // have no idea where [EBX] is, so we punt on all USEs if we have // a memory source operand. if (!(this->HasSourceMemoryOperand())) { UseIter = this->GetFirstUse(); while (UseIter != this->GetLastUse()) { // All non-memory USEs besides the flags register should get the new SignMask ORed in. UseOp = UseIter->GetOp(); if (!(IsMemOperand(UseOp) || MDIsFlagsReg(UseOp))) { UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum()); if (this->BasicBlock->IsLocalName(UseOp)) { this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, SignMask); } else { this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask); } } ++UseIter; } } } // end of case 2 // Case 3: multiplies and divides can be signed or unsigned. else if (case3) { // Multiplies and divides are type 7. if (this->MDIsSignedArithmetic()) { SignMask = FG_MASK_SIGNED; } else if (this->MDIsUnsignedArithmetic()) { SignMask = FG_MASK_UNSIGNED; } else { SignMask = 0; // unknown, uninitialized } if (0 != SignMask) { DefIter = this->GetFirstDef(); while (DefIter != this->GetLastDef()) { // All DEFs besides the flags register should get the new SignMask ORed in. DefOp = DefIter->GetOp(); if ((DefOp->IsRegOp()) && (!(DefOp->MatchesReg(X86_FLAGS_REG)))) { DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum()); if (this->BasicBlock->IsLocalName(DefOp)) { this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, SignMask); } else { this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask); } } ++DefIter; } UseIter = this->GetFirstUse(); while (UseIter != this->GetLastUse()) { // All USEs besides the flags register should get the new SignMask ORed in. UseOp = UseIter->GetOp(); if ((UseOp->IsRegOp()) && (!(UseOp->MatchesReg(X86_FLAGS_REG)))) { UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum()); if (this->BasicBlock->IsLocalName(UseOp)) { this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, SignMask); } else { this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask); } } ++UseIter; } } // end if (0 != SignMask) } // end of case 3 (multiplies and divides) // Case 4: Calls to library functions can reveal the type of the return register. else if (case4) { STARS_ea_t InstAddr = this->GetAddr(); // Get name of function called. string FuncName = this->GetTrimmedCalledFunctionName(); // See if we are throwing an exception. if (0 == strcmp("cxa_throw", FuncName.c_str()) && (NULL != this->GetBlock())) { this->GetBlock()->GetFunc()->GetProg()->SetProgramThrowsExceptions(); } // Get FG info, if any, for the return value of the called function. GetLibFuncFGInfo(FuncName, FGEntry); // See if anything was returned in FGEntry. if ((FGEntry.SignMiscInfo != 0) || (FGEntry.SizeInfo != 0)) { // Need to update the FG info for the DEF of the return register. // Also can infer POINTER or NUMERIC and propagate. DefOp = this->STARSInstPtr->MakeRegOpnd(MD_RETURN_VALUE_REG); DefIter = this->FindDef(DefOp); assert(DefIter != this->GetLastDef()); int DefSSANum = DefIter->GetSSANum(); DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum); SMPOperandType DefType = DefIter->GetType(); SMPOperandType NewDefType = UNINIT; if (FGEntry.SizeInfo & FG_MASK_INTEGER) { NewDefType = NUMERIC; } else if (FGEntry.SizeInfo & FG_MASK_DATAPOINTER) { NewDefType = POINTER; } bool TypeErrorFlag = false; NewDefType = SMPTypeMeet(DefType, NewDefType, TypeErrorFlag); if (TypeErrorFlag) { SMP_msg("ERROR: TypeMeet error in MDSetWidthSignInfo() at %llx\n", (uint64_t) this->GetAddr()); } bool UpdateType = ((NewDefType != DefType) && (DefType == UNINIT)); if (UpdateType) { DefIter = this->SetDefType(DefOp, NewDefType); } if (this->BasicBlock->IsLocalName(DefOp)) { this->BasicBlock->UpdateDefFGInfo(DefHashValue, FGEntry); if (UpdateType) { this->GetBlock()->PropagateLocalDefType(DefOp, NewDefType, InstAddr, DefSSANum, false, false); } } else { this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, FGEntry); if (UpdateType) { this->GetBlock()->GetFunc()->ResetProcessedBlocks(); this->GetBlock()->PropagateGlobalDefType(DefOp, NewDefType, DefSSANum, false, false); } } } // See if we make a call to a library function that needs signedness checks on // unsigned incoming args. unsigned int ArgPosBits = 0; GetUnsignedArgPositionsForCallName(FuncName, ArgPosBits); if (0 < ArgPosBits) { // Mark our basic block as containing this type of call, so signedness checks // can be done later. this->GetBlock()->SetCallsUnsignedArgFunc(); bool IsMallocCall = (0 == FuncName.compare("malloc")); // Find the argument assignments and mark them, to trigger later signedness checks. this->GetBlock()->MarkUnsignedArgs(InstAddr, ArgPosBits, IsMallocCall); } // See if we make a call to a library function that has POINTER args. ArgPosBits = 0; GetPointerArgPositionsForCallName(FuncName, ArgPosBits); if (0 < ArgPosBits) { bool IsBufferLibFunc = IsBufferArgFuncName(FuncName); // Find the argument assignments and mark them, to trigger later signedness checks. this->GetBlock()->MarkPointerArgs(InstAddr, ArgPosBits, IsBufferLibFunc); } } // end of case4 (function calls) else if (case5) { // signed or unsigned conditional set opcode if (UnsignedSetOpcode) { SignMask = FG_MASK_UNSIGNED; } else { assert(SignedSetOpcode); SignMask = FG_MASK_SIGNED; } // Find the flags USE. UseOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); // set up a dummy op for searching UseIter = this->FindUse(UseOp); assert(UseIter != this->GetLastUse()); UseOp = UseIter->GetOp(); // get full info in all fields of UseOp SSANum = UseIter->GetSSANum(); LocalFlags = this->GetBlock()->IsLocalName(UseOp); DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, this->GetAddr(), SSANum, LocalFlags); // Pass DefAddr to recursive helper function to propagate signedness of the set opcode. this->GetBlock()->PropagateBranchSignedness(DefAddr, UseOp, SignMask); } else if (case6) { // sign extend to double the width of USE operand into DEF operand DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); DefOp = DefIter->GetOp(); assert(DefOp->IsRegOp()); SSANum = DefIter->GetSSANum(); DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum); UseIter = this->GetFirstUse(); assert(UseIter != this->GetLastUse()); UseOp = UseIter->GetOp(); assert(UseOp->IsRegOp()); assert(UseOp->GetReg() == DefOp->GetReg()); UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum()); SignMask = FG_MASK_SIGNED; // opcodes do sign extension => signed // Mark DEF and USE as signed. if (this->GetBlock()->IsLocalName(DefOp)) { this->GetBlock()->UpdateDefSignMiscInfo(DefHashValue, SignMask); this->GetBlock()->UpdateUseSignMiscInfo(UseHashValue, SignMask); } else { this->GetBlock()->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask); this->GetBlock()->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, SignMask); } } else if (case7 || case8) { // always unsigned DEF or always signed DEF. DefIter = this->GetFirstNonFlagsDef(); if (DefIter != this->GetLastDef()) { DefOp = DefIter->GetOp(); if (DefOp->IsRegOp()) { SSANum = DefIter->GetSSANum(); DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum); if (case7) SignMask = FG_MASK_UNSIGNED; else SignMask = FG_MASK_SIGNED; // Mark DEF as signed or unsigned. if (this->GetBlock()->IsLocalName(DefOp)) { this->GetBlock()->UpdateDefSignMiscInfo(DefHashValue, SignMask); } else { this->GetBlock()->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, SignMask); } } } } // For all register DEFs and USEs, we should get the obvious register width info // updated. Need to use the RTL operands to get accurate widths. SMPRegTransfer *CurrRT; for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) { CurrRT = this->RTL.GetRT(index); STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); if ((nullptr != LeftOp) && (!case2)) DefOp = CloneIfSubwordReg(LeftOp); else DefOp = nullptr; // Avoid setting def width for case 2; we leave it as zero so that // later uses can determine whether the zero-extension or sign-extension // bits ever got used. See more discussion in EmitIntegerErrorAnnotations() // for the CHECK TRUNCATION case. // NOTE: case2 can be set to true even in the case1/case2 overlap case that // only passes through the case1 code above. This is intentional. We want // to leave the DEF width set to 0 for all of case2 including the case1 overlap. if (!case2) { if (MDIsGeneralPurposeReg(DefOp)) { WidthMask = ComputeOperandBitWidthMask(DefOp, 0); CanonicalizeOpnd(DefOp); DefIter = this->FindDef(DefOp); assert(DefIter != this->GetLastDef()); DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum()); if (this->BasicBlock->IsLocalName(DefOp)) { this->BasicBlock->UpdateDefWidthTypeInfo(DefHashValue, WidthMask); } else { this->BasicBlock->GetFunc()->UpdateDefWidthTypeInfo(DefHashValue, WidthMask); } } } if (CurrRT->HasRightSubTree()) { this->MDSetRTLRegWidthInfo(CurrRT->GetRightTree()); } else { UseOp = CurrRT->GetRightOperand(); this->SetRTLUseOpRegWidthInfo(UseOp); } } // end for all RTLs return; } // end of SMPInstr::MDSetWidthSignInfo() // Infer sign from the SMP types for USEs and DEFs. void SMPInstr::InferSignednessFromSMPTypes(bool UseFP) { // Start with registers only, infer that all kids of pointers are UNSIGNED. set<DefOrUse, LessDefUse>::iterator DefIter, UseIter; int SSANum; int DefHashValue, UseHashValue; SMPOperandType DefType, UseType; unsigned short DefSignMiscInfo = FG_MASK_UNSIGNED, UseSignMiscInfo = FG_MASK_UNSIGNED; bool GlobalName; for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { STARSOpndTypePtr DefOp = DefIter->GetOp(); if (MDIsGeneralPurposeReg(DefOp)) { DefType = DefIter->GetType(); if (IsDataPtr(DefType) || (CODEPTR == DefType)) { GlobalName = this->BasicBlock->GetFunc()->IsGlobalName(DefOp); SSANum = DefIter->GetSSANum(); DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum); if (GlobalName) { this->BasicBlock->GetFunc()->UpdateDefSignMiscInfo(DefHashValue, DefSignMiscInfo); } else { this->BasicBlock->UpdateDefSignMiscInfo(DefHashValue, DefSignMiscInfo); } } } } for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { STARSOpndTypePtr UseOp = UseIter->GetOp(); if (MDIsGeneralPurposeReg(UseOp)) { UseType = UseIter->GetType(); if (IsDataPtr(UseType) || (CODEPTR == UseType)) { GlobalName = this->BasicBlock->GetFunc()->IsGlobalName(UseOp); SSANum = UseIter->GetSSANum(); UseHashValue = HashGlobalNameAndSSA(UseOp, SSANum); if (GlobalName) { this->BasicBlock->GetFunc()->UpdateUseSignMiscInfo(UseHashValue, UseSignMiscInfo); } else { this->BasicBlock->UpdateUseSignMiscInfo(UseHashValue, UseSignMiscInfo); } } } } return; } // end of SMPInstr::InferSignednessFromSMPTypes() // Helper to set width info for a UseOp from an RTL void SMPInstr::SetRTLUseOpRegWidthInfo(const STARSOpndTypePtr &UseOp) { unsigned short WidthMask; set<DefOrUse, LessDefUse>::iterator UseIter; unsigned int UseHashValue; if (MDIsGeneralPurposeReg(UseOp)) { WidthMask = ComputeOperandBitWidthMask(UseOp, 0); STARSOpndTypePtr UseOpClone = CloneIfSubwordReg(UseOp); CanonicalizeOpnd(UseOpClone); UseIter = this->FindUse(UseOpClone); assert(UseIter != this->GetLastUse()); UseHashValue = HashGlobalNameAndSSA(UseOpClone, UseIter->GetSSANum()); if (this->BasicBlock->IsLocalName(UseOpClone)) { this->BasicBlock->UpdateUseWidthTypeInfo(UseHashValue, WidthMask); } else { this->BasicBlock->GetFunc()->UpdateUseWidthTypeInfo(UseHashValue, WidthMask); } } return; } // end of SMPInstr::SetRTLUseOpRegWidthInfo() // Walk the RTL and update the register USE operands' width info. void SMPInstr::MDSetRTLRegWidthInfo(SMPRegTransfer *CurrRT) { STARSOpndTypePtr UseOp = CurrRT->GetLeftOperand(); this->SetRTLUseOpRegWidthInfo(UseOp); if (CurrRT->HasRightSubTree()) { this->MDSetRTLRegWidthInfo(CurrRT->GetRightTree()); } else { UseOp = CurrRT->GetRightOperand(); this->SetRTLUseOpRegWidthInfo(UseOp); } return; } // end of SMPInstr::MDSetRTLRegWidthInfo() // Do we not consider truncation on this type of instruction to be an error? bool SMPInstr::IsBenignTruncation(int &IdiomCode) { bool benign = false; unsigned short SignMask; STARSOpndTypePtr UseOp = nullptr, SearchOp = nullptr; if (3 == this->GetOptType()) { // Move instruction bool ExtendedLoad = this->MDIsSignedLoad(SignMask); if (ExtendedLoad && (SignMask & FG_MASK_UNSIGNED)) { // We have a zero-extended load. Compilers zero-extend both // signed (unfortunately) and unsigned sub-regs when they know // from the source language types that only the lower bits matter, // e.g. when a char has been stored in the lower bits and regardless // of whether that char was sign-extended or zero-extended previously, // only the char itself is useful info. Otherwise, the compiler could // move the whole register, e.g. instead of edi := zero-extend(cx), the // compiler could have generated edi := ecx. The zero-extension loads // are therefore not good candidates for truncation checks, as they lead // to lots of false positives. benign = true; IdiomCode = 5; #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++BenignTruncationCount; #endif } else { // Move, and not extended load, which was handled above. // Next case: A move instruction whose USE falsely appears to be a truncation, // but in fact the apparently unused portion of the register is used later, e.g.: // mov [ebp-12],ax ; looks like EAX is being truncated to AX and stored // shr eax,16 ; gets upper 16 bits into lower 16 bits // mov [ebp-14],ax ; store what used to be the upper 16 bits of EAX // The first instruction will trigger a CHECK TRUNCATION annotation that // causes false positives. We need to analyze the context of the instruction // to see that the whole register EAX was used, so no truncation occurred. // The context analysis in the basic block will mark the second move as // a "truncation" that should be ignored, so we check the flag here to short // circuit redundant analysis. UseOp = CloneIfSubwordReg(this->GetMoveSource()); assert((nullptr != UseOp) && (!UseOp->IsVoidOp())); SearchOp = UseOp; if (UseOp->IsRegOp()) { CanonicalizeOpnd(SearchOp); } set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp); assert(UseIter != this->GetLastUse()); SMPOperandType UseType = UseIter->GetType(); if (UseIter->DoesNotTruncate()) { benign = true; IdiomCode = 2; #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++SuppressTruncationRegPiecesAllUsed; #endif } else if (IsDataPtr(UseType)) { benign = true; IdiomCode = 30; } else { set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); int DefSSANum = DefIter->GetSSANum(); SMPOperandType DefType = DefIter->GetType(); if (IsDataPtr(DefType)) { benign = true; IdiomCode = 30; } else { benign = this->GetBlock()->IsBenignTruncationDEF(DefIter->GetOp(), DefSSANum, this->GetAddr(), IdiomCode); } if (!benign) { // Third case: value gets zero-extended, AND/OR instructions manipulate it, then // the lower bits get written. No adds, subtracts, etc. in the chain of operations. // This is just the typical unwillingness of compiler to do less than 32-bit arithmetic, // not an actual truncation. int UseSSANum = UseIter->GetSSANum(); // Prepare for possible recursive traversals through the function blocks. this->GetBlock()->GetFunc()->ResetProcessedBlocks(); if (this->IsOpSourceZeroExtendedMoveShiftRightOrConditionCode(SearchOp, UseSSANum, true)) { IdiomCode = 14; benign = true; } } if (!benign) { // Fourth case: bits within a byte are copied and shifted (some left, some right) and written // out to different byte addresses. The left and right shifts of two copies of the same byte // are the kind of bit-twiddling done when disassembling some network packets. int UseSSANum = UseIter->GetSSANum(); // Prepare for possible recursive traversals through the function blocks. this->GetBlock()->GetFunc()->ResetProcessedBlocks(); STARS_ea_t ShiftInstAddr; STARSOpndTypePtr ShiftedOperand; STARSOpndTypePtr ShiftCounterOperand; if (this->IsOpSourceLeftShift(SearchOp, UseSSANum, ShiftCounterOperand, ShiftedOperand, ShiftInstAddr)) { if (ShiftCounterOperand->IsImmedOp() && (8 > ShiftCounterOperand->GetImmedValue())) { SMPInstr *ShiftInst = this->GetBlock()->GetFunc()->GetInstFromAddr(ShiftInstAddr); if (ShiftInst->GetBlock()->IsUseCopiedAndShiftedRight(ShiftedOperand, ShiftInstAddr)) { IdiomCode = 25; benign = true; } } } } } } } return benign; } // end of SMPInstr::IsBenignTruncation() // Do we not consider overflow or underflow on this type of instruction to be an error? bool SMPInstr::IsBenignOverflow(int &IdiomCode) { bool benign = false; set<DefOrUse, LessDefUse>::iterator DefIter, UseIter; SMPOperandType DefType, UseType; int DefSSANum; STARS_ea_t DefAddr; STARSOpndTypePtr DefOp = nullptr; if (this->MDIsDefiniteBenignUnderflowOpcode(IdiomCode)) { // No further analysis at block or function scope is needed. benign = true; } else if (this->MDIsMaybeBenignUnderflowOpcode()) { // might have the subtract instruction in tricky sequence // We are looking to suppress overflow and underflow warnings on the following // code sequence: PTR1-PTR2+1 gets a loop invariant code motion optimization // that pulls temp := 1-PTR2 out of the loop, and leaves temp2 := PTR1+temp // inside the loop. The hoisted subtraction could underflow, and the addition // that is not hoisted could overflow. The net effect of these two instructions // is benign, however, so we want to suppress underflow and overflow checks on // both of them, but only if we can match the pair of instructions. DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); if (DefIter->DoesNotOverflow()) { benign = true; // short circuit; already analyzed } else { DefType = DefIter->GetType(); if (IsEqType(DefType, NEGATEDPTR)) { // We have candidate subtract instruction DefOp = DefIter->GetOp(); DefSSANum = DefIter->GetSSANum(); DefAddr = this->GetAddr(); benign = this->GetBlock()->GetFunc()->IsBenignUnderflowDEF(DefOp, DefSSANum, DefAddr, IdiomCode); if (!benign) { // If we did not find the complicated sequence, we still don't want to have a false positive // on any instruction that is producing a NEGATEDPTR. benign = true; IdiomCode = 13; } } } } else if (this->MDIsMaybeBenignOverflowOpcode()) { // might have the add instruction in tricky sequence DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); if (DefIter->DoesNotOverflow()) { benign = true; // short circuit; already analyzed IdiomCode = 6; } else { // Bad luck to encounter addition first. See what types tell us. if (this->HasNegatedPtrUSE()) { // We have candidate for addition. DefType = DefIter->GetType(); if (IsEqType(DefType, PTROFFSET)) { // Current instruction is definitely the addition instruction of some // benignly underflowing and overflowing pair of instructions. It does // not really matter that we have not found the subtraction yet; we will // get to it eventually. We should suppress overflow checks on this inst. DefOp = DefIter->GetOp(); DefIter = this->Defs.SetNoOverflow(DefOp, true); benign = true; IdiomCode = 6; } else { // A bit of a quandary. Ideally, we would have successful SMP type inference // and always have PTROFFSET := POINTER + NEGATEDPTR. However, sometimes we // might have ?? := ?? + NEGATEDPTR. The instruction could be of the type // NEGATEDPTR := NUMERIC + NEGATEDPTR, so we cannot just assume here that // we have detected the benign case. However, these instructions are likely // to cause false positives and unlikely to be a source of false negatives, // so we will err on the side of false positive suppression based on experience // (even though we usually do the opposite). benign = true; IdiomCode = 13; } } } } if (!benign) { // Any overflow or underflow producing a PTROFFSET type should be suppressed. for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { DefType = DefIter->GetType(); if (IsEqType(DefType, PTROFFSET)) { benign = true; IdiomCode = 19; } } } if (!benign) { // Any overflow or underflow using a PTROFFSET type should be suppressed. for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { UseType = UseIter->GetType(); if (IsEqType(UseType, PTROFFSET)) { benign = true; IdiomCode = 19; } } } return benign; } // end of SMPInstr::IsBenignOverflow() // Do we detect a situation in which it is safe to check for signedness errors on // the stack write (return false), or not (return true to be safe). bool SMPInstr::SkipSignednessCheckOnStackWrite(int DefSSANum, bool SourceIsSigned) { bool SkipCheck = (!(this->IsUnsignedArg())); STARSOpndTypePtr StackDefOp = this->DEFMemOp; std::size_t DefBitWidth = 8 * StackDefOp->GetByteWidth(); if (DefBitWidth < MD_NORMAL_MACHINE_BITWIDTH) { // If we are not dealing with a shortened bit width, then // the next load from the stack will not be sign-extended // or zero-extended. if (this->GetBlock()->IsStackOpNextUsedWithSignedness(StackDefOp, this->GetAddr(), DefSSANum)) { SkipCheck = false; } } if (SkipCheck) { this->GetBlock()->GetFunc()->ResetProcessedBlocks(); bool Signed; if (this->GetBlock()->IsDefUsedInLoopCompareAndBranch(this->GetAddr(), StackDefOp, DefSSANum, Signed)) { if (Signed != SourceIsSigned) { // signedness of source copied into StackDefOp is not the same as branch signedness SkipCheck = false; } } } return SkipCheck; } // end of SMPInstr::SkipSignednessCheckOnStackWrite() // Does inst pass an outgoing argument? If so, pass back argument position #, starting at zero for [esp], 1 for [esp+4], etc. bool SMPInstr::MDIsArgumentPass(std::size_t &ArgumentNumber) { bool OutArgPass = false; // NOTE: More precise would be to guarantee that the DEF reaches the next call inst. !!!!****!!!! if (!STARS_IsSSAMarkerPseudoID(this->GetAddr())) { if (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64) { // x86-64 passes the first six arguments in registers EDI, ESI, EDX, ECX, R8 and R9, in that order. set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef(); if (DefIter != this->GetLastDef()) { STARSOpndTypePtr DefOp = DefIter->GetOp(); if (DefOp->IsRegOp()) { STARS_regnum_t RegNum = DefOp->GetReg(); std::size_t ArgIndex = 0; if (global_STARS_program->GetArgRegPosition(RegNum, ArgIndex)) { OutArgPass = true; ArgumentNumber = ArgIndex; } } } } else { // 32 bits // Current model is writing outargs to stack. For other compiler targets in the // future, we would also include pushes onto the stack. if (this->HasDestMemoryOperand() && (this->GetOptType() == 3)) { // move to memory if (this->GetBlock()->GetFunc()->OutArgsRegionComputed()) { STARSOpndTypePtr DefOp = this->DEFMemOp; OutArgPass = this->GetBlock()->GetFunc()->IsInOutgoingArgsRegion(DefOp); if (OutArgPass) { STARSOpndTypePtr UnnormalizedDefOp = CloneIfNecessary(DefOp, this->GetBlock()->GetFunc()->UsesFramePointer()); this->MDGetUnnormalizedOp(UnnormalizedDefOp); std::size_t StandardByteSize = (MD_NORMAL_MACHINE_BITWIDTH / 8); ArgumentNumber = (UnnormalizedDefOp->GetAddr() / StandardByteSize); } } } } } return OutArgPass; } // end of SMPInstr::MDIsArgumentPass() // Get comparison expr; valid only for signed or unsigned comparison insts void SMPInstr::GetCompareOrTestExpr(struct LoopComparison &LoopExpr) { assert(this->MDIsCompareOrTest()); SMPRegTransfer *CurrRT = this->RTL.GetRT(0); assert(CurrRT->HasRightSubTree()); CurrRT = CurrRT->GetRightTree(); LoopExpr.CompareOperator = CurrRT->GetOperator(); STARSOpndTypePtr LeftOp = CurrRT->GetLeftOperand(); if (LeftOp->IsImmedOp()) { DefOrUse LeftImmedUse(LeftOp); LoopExpr.Operand1 = LeftImmedUse; } else { STARSDefUseIter LeftUseIter = this->FindUse(LeftOp); if (LeftUseIter == this->GetLastUse()) { // Not a reg or stack operand? LoopExpr.CompareOperator = SMP_NULL_OPERATOR; // signal an analysis failure return; } LoopExpr.Operand1 = (*LeftUseIter); } assert(!CurrRT->HasRightSubTree()); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { DefOrUse RightImmedUse(RightOp); LoopExpr.Operand2 = RightImmedUse; } else { STARSDefUseIter RightUseIter = this->FindUse(RightOp); if (RightUseIter == this->GetLastUse()) { // Not a reg or stack operand? LoopExpr.CompareOperator = SMP_NULL_OPERATOR; // signal an analysis failure return; } LoopExpr.Operand2 = (*RightUseIter); } return; } // end of SMPInstr::GetCompareOrTestExpr() // create Expr for DefOp from right-hand-side of first RT. // DefOp is used when this inst is an SSA Marker inst. STARSExpression* SMPInstr::CreateDefExpr(const STARSOpndTypePtr &DefOp) { if (this->IsMarkerInst()) { // There will probably be lots of DEFs. Just create a DefExpr for the DefOp argument. STARSExpression *DefExpr = new STARSExpression(); DefExpr->SetOperator(SMP_ASSIGN); DefExpr->SetParentInst(this); DefExpr->SetOriginalParentInst(this); DefExpr->SetParentFunc(this->GetBlock()->GetFunc()); DefExpr->SetLeftOperand(DefOp); DefExpr->SetLeftUseAddr(this->GetAddr()); DefExpr->SetLeftSSANum(0); return DefExpr; } else { SMPRegTransfer *CurrRT = this->RTL.GetRT(0); if (CurrRT->HasRightSubTree()) { CurrRT = CurrRT->GetRightTree(); STARSExpression *DefExpr = new STARSExpression(CurrRT); return DefExpr; } else { STARSExpression *DefExpr = new STARSExpression(); DefExpr->SetOperator(SMP_ASSIGN); DefExpr->SetParentInst(this); DefExpr->SetOriginalParentInst(this); DefExpr->SetParentFunc(this->GetBlock()->GetFunc()); STARSOpndTypePtr RightOp = CurrRT->GetRightOperand(); DefExpr->SetLeftOperand(RightOp); DefExpr->SetLeftUseAddr(this->GetAddr()); if (MDIsDataFlowOpnd(RightOp, DefExpr->GetParentFunc()->UsesFramePointer())) { STARSDefUseIter UseIter = this->FindUse(RightOp); assert(UseIter != this->GetLastUse()); DefExpr->SetLeftSSANum(UseIter->GetSSANum()); } DefExpr->SetRightOperand(this->MakeVoidOpnd()); return DefExpr; } } } // end of SMPInstr::CreateDefExpr() // create Expr from left-hand-side of first RT, e.g. [RAX+8] => SMP_ADD(RAX, 8) STARSExpression* SMPInstr::CreateMemDefAddrExpr(void) { int BaseReg, IndexReg; uint16_t ScaleFactor; STARS_ea_t Offset; STARSOpndTypePtr MemDefOp = this->RTL.GetRT(0)->GetLeftOperandNoNorm(); if (((nullptr == MemDefOp) || !MemDefOp->IsMemOp()) && (1 < this->RTL.GetCount())) { MemDefOp = this->RTL.GetRT(1)->GetLeftOperandNoNorm(); } if (nullptr == MemDefOp) return nullptr; assert(MemDefOp->IsMemOp()); MemDefOp->MDExtractAddressFields(BaseReg, IndexReg, ScaleFactor, Offset); STARSExpression *MemAddrExpr = nullptr; if ((ScaleFactor == 0) || (Offset == 0)) { // avoid too much complexity MemAddrExpr = new STARSExpression(); MemAddrExpr->SetParentInst(this); MemAddrExpr->SetOriginalParentInst(this); MemAddrExpr->SetParentFunc(this->GetBlock()->GetFunc()); if (BaseReg != STARS_x86_R_none) { STARSOpndTypePtr BaseOp = this->MakeRegOpnd((STARS_regnum_t) BaseReg); MemAddrExpr->SetLeftOperand(BaseOp); MemAddrExpr->SetLeftUseAddr(this->GetAddr()); } else { assert(IndexReg != STARS_x86_R_none); STARSOpndTypePtr IndexOp = this->MakeRegOpnd((STARS_regnum_t) IndexReg); MemAddrExpr->SetLeftOperand(IndexOp); MemAddrExpr->SetLeftUseAddr(this->GetAddr()); } STARSDefUseIter RegUseIter = this->FindUse(MemAddrExpr->GetConstLeftOperand()); assert(RegUseIter != this->GetLastUse()); MemAddrExpr->SetLeftSSANum(RegUseIter->GetSSANum()); // Set address reg to default bytewidth even if memory write is smaller. size_t DefaultWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); if (MemDefOp->GetByteWidth() < DefaultWidth) { MemAddrExpr->GetLeftOperand()->SetByteWidth(DefaultWidth); } if (Offset != 0) { MemAddrExpr->SetOperator(SMP_ADD); MemAddrExpr->SetRightOperand(this->MakeImmediateOpnd((STARS_uval_t) Offset)); } else if (ScaleFactor != 0) { MemAddrExpr->SetOperator(SMP_U_MULTIPLY); MemAddrExpr->SetRightOperand(this->MakeImmediateOpnd((STARS_uval_t) (1 << ScaleFactor))); } else { // No ScaleFactor, no Offset MemAddrExpr->SetOperator(SMP_ASSIGN); } } return MemAddrExpr; } // end of SMPInstr::CreateMemDefAddrExpr() // Does UseOp arithmetically affect the value of the NonFlagsDef for this inst? bool SMPInstr::OperandTransfersValueToDef(const STARSOpndTypePtr &UseOp) { bool FoundTransfer = false; for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) { SMPRegTransfer *CurrRT = this->RTL.GetRT(index); if (CurrRT->OperandTransfersValueToDef(UseOp)) { FoundTransfer = true; break; } } return FoundTransfer; } // end of SMPInstr::OperandTransfersValueToDef() // Evaluate constants in assignment statement for SCCP algorithm void SMPInstr::SCCPEvaluateAssignment(list<pair<int, int> > &SSAWorkList) { for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) { SMPRegTransfer *CurrRT = this->RTL.GetRT(index); STARS_SCCP_Const_Struct ConstResult = CurrRT->SCCPEvaluateRTLConsts(SSAWorkList); if (ConstResult.ConstType == STARS_CONST_HAS_VALUE) { ++ConstantDEFCount; } } return; } // end of SMPInstr::SCCPEvaluateAssignment() // Evaluate conditional branch using constant values from SCCP void SMPInstr::SCCPEvaluateCondBranch(enum STARSBranchConst &BranchEval) { // The conditional branch RTL is just a jump with a Guard RT. // We evaluate the Guard RT to see if it is always true or always false. SMPRegTransfer *CurrRT = this->RTL.GetRT(0); SMPGuard *BranchCondition = CurrRT->GetGuard(); assert(NULL != BranchCondition); STARSOpndTypePtr LeftOp = CloneIfSubwordReg(BranchCondition->GetConstLeftOperand()); CanonicalizeOpnd(LeftOp); STARSOpndTypePtr RightOp = CloneIfSubwordReg(BranchCondition->GetConstRightOperand()); CanonicalizeOpnd(RightOp); STARS_SCCP_Const_Struct LeftValue, RightValue; this->SCCPFetchConstUseValue(LeftOp, LeftValue); this->SCCPFetchConstUseValue(RightOp, RightValue); if ((LeftValue.ConstType == STARS_CONST_HAS_VALUE) && (RightValue.ConstType == STARS_CONST_HAS_VALUE)) { SMPoperator GuardOper = BranchCondition->GetOperator(); if (GuardOper == SMP_EQUAL) { if (LeftValue.ConstValue == RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_NOT_EQUAL) { if (LeftValue.ConstValue != RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_GREATER_THAN) { if ((STARS_sval_t) LeftValue.ConstValue > (STARS_sval_t) RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_GREATER_EQUAL) { if ((STARS_sval_t) LeftValue.ConstValue >= (STARS_sval_t) RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_LESS_THAN) { if ((STARS_sval_t) LeftValue.ConstValue < (STARS_sval_t) RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_LESS_EQUAL) { if ((STARS_sval_t) LeftValue.ConstValue <= (STARS_sval_t) RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_BELOW) { if (LeftValue.ConstValue < RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_BELOW_EQUAL) { if (LeftValue.ConstValue <= RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_ABOVE) { if (LeftValue.ConstValue > RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else if (GuardOper == SMP_ABOVE_EQUAL) { if (LeftValue.ConstValue >= RightValue.ConstValue) { BranchEval = STARS_BRANCH_ALWAYS_TAKEN; ++AlwaysTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found always taken conditional branch at %x\n", this->GetAddr()); #endif } else { BranchEval = STARS_BRANCH_NEVER_TAKEN; ++NeverTakenBranchCount; #if 0 SMP_msg("INFO: SCCP found never taken conditional branch at %x\n", this->GetAddr()); #endif } } else { SMP_msg("WARNING: SCCP unknown GuardOper %d in conditional branch at %llx\n", GuardOper, (unsigned long long) this->GetAddr()); BranchEval = STARS_BRANCH_UNKNOWN; } } else { BranchEval = STARS_BRANCH_UNKNOWN; } return; } // end of SMPInstr::SCCPEvaluateCondBranch() // Fetch constant value, if any, for a USE operand. void SMPInstr::SCCPFetchConstUseValue(const STARSOpndTypePtr &UseOp, STARS_SCCP_Const_Struct &ConstStruct) { ConstStruct.ConstType = STARS_CONST_TOP; // default if (UseOp->IsImmedOp()) { ConstStruct.ConstType = STARS_CONST_HAS_VALUE; ConstStruct.ConstValue = UseOp->GetImmedValue(); } else if (UseOp->IsRegOp()) { // Look up reg DEF value in local or global map STARSOpndTypePtr SearchOp = CloneIfSubwordReg(UseOp); CanonicalizeOpnd(SearchOp); set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp); if (UseIter != this->GetLastUse()) { int UseSSANum = UseIter->GetSSANum(); int UseHashValue = HashGlobalNameAndSSA(SearchOp, UseSSANum); if (this->GetBlock()->IsLocalName(SearchOp)) { // local name map<int, struct STARS_SCCP_Const_Struct>::iterator ConstValIter = this->GetBlock()->FindLocalConstValue(UseHashValue); if (ConstValIter != this->GetBlock()->GetLastLocalConstValueIter()) { // Has current const val entry ConstStruct = ConstValIter->second; } } else { // global name map<int, struct STARS_SCCP_Const_Struct>::iterator ConstValIter = this->GetBlock()->GetFunc()->FindConstValue(UseHashValue); if (ConstValIter != this->GetBlock()->GetFunc()->GetLastConstValueIter()) { // Has current const val entry ConstStruct = ConstValIter->second; } } } } else if (UseOp->IsStaticMemOp()) { // Fetch read-only data value, if any. STARS_ea_t MemAddr = UseOp->GetAddr(); bool GoodAddr = (STARS_BADADDR != MemAddr); #if 1 #if 1 int BaseReg = STARS_x86_R_none; if (UseOp->HasSIBByte()) { BaseReg = UseOp->MDGetSIBIndexReg(); if (MD_STACK_POINTER_REG == BaseReg) { // ESP IndexReg in SIB byte means no index reg // seg reg without index or base reg, e.g.: FS:0x28 BaseReg = STARS_x86_R_none; GoodAddr = false; // until we track segment register values #if 0 SMP_msg("ERROR: StaticMemOp with SIB byte and no index reg at %llx\n", (unsigned long long) this->GetAddr()); #endif } } #else int BaseReg = (int) UseOp->GetReg(); if (MD_STACK_POINTER_REG == BaseReg) { // ESP BaseReg in means no base reg for StaticMemOp BaseReg = STARS_x86_R_none; } if (UseOp->HasSIBByte()) { BaseReg = UseOp->MDGetSIBBaseReg(); if ((STARS_x86_R_none == BaseReg) || (MD_FRAME_POINTER_REG == BaseReg)) { // EBP BaseReg for StaticMemOp means no base reg BaseReg = UseOp->MDGetSIBIndexReg(); if (MD_STACK_POINTER_REG == BaseReg) { // ESP IndexReg in SIB byte means no index reg BaseReg = STARS_x86_R_none; } } } #endif if (STARS_x86_R_none != BaseReg) { // have an offset reg to add to the static mem addr // TODO: Fetch constant value for general purpose reg, with SSANum from USE set. GoodAddr = false; } #endif if (GoodAddr) { STARS_Segment_t *MemSeg = global_stars_interface->getseg(MemAddr); if (NULL != MemSeg) { if (MemSeg->IsWriteableSegment()) { ConstStruct.ConstType = STARS_CONST_BOTTOM; // cannot know writable memory value without alias analysis, etc. } else { size_t UseOpByteWidth = UseOp->GetByteWidth(); if (UseOpByteWidth == 8) { uint64_t MemValue; if (MemSeg->GetReadOnlyMem64BitValue(MemAddr, MemValue)) { ConstStruct.ConstType = STARS_CONST_HAS_VALUE; ConstStruct.ConstValue = (STARS_uval_t) MemValue; } } else if (UseOpByteWidth == 4) { uint32_t MemValue; if (MemSeg->GetReadOnlyMem32BitValue(MemAddr, MemValue)) { ConstStruct.ConstType = STARS_CONST_HAS_VALUE; ConstStruct.ConstValue = (STARS_uval_t) MemValue; } } else if (UseOpByteWidth == 2) { uint16_t MemValue; if (MemSeg->GetReadOnlyMem16BitValue(MemAddr, MemValue)) { ConstStruct.ConstType = STARS_CONST_HAS_VALUE; ConstStruct.ConstValue = (STARS_uval_t) MemValue; } } else if (UseOpByteWidth == 1) { uint8_t MemValue; if (MemSeg->GetReadOnlyMem8BitValue(MemAddr, MemValue)) { ConstStruct.ConstType = STARS_CONST_HAS_VALUE; ConstStruct.ConstValue = (STARS_uval_t) MemValue; } } } } } else { // not GoodAddr ConstStruct.ConstType = STARS_CONST_BOTTOM; } } else if (UseOp->IsMemOp()) { // Any memory operand that is not a StaticMemOp ConstStruct.ConstType = STARS_CONST_BOTTOM; } return; } // end of SMPInstr::SCCPFetchConstUseValue() // Fetch constant value, if any, for a DEF operand. void SMPInstr::SCCPFetchConstDefValue(const STARSOpndTypePtr &DefOp, STARS_SCCP_Const_Struct &ConstStruct) { ConstStruct.ConstType = STARS_CONST_TOP; // default if (DefOp->IsImmedOp()) { ConstStruct.ConstType = STARS_CONST_HAS_VALUE; ConstStruct.ConstValue = DefOp->GetImmedValue(); } else if (DefOp->IsRegOp()) { // Look up reg DEF value in local or global map STARSOpndTypePtr SearchOp = CloneIfSubwordReg(DefOp); CanonicalizeOpnd(SearchOp); set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp); if (DefIter != this->GetLastDef()) { int DefSSANum = DefIter->GetSSANum(); SMPBasicBlock *CurrBlock = this->GetBlock(); int DefHashValue = HashGlobalNameAndSSA(SearchOp, DefSSANum); bool LocalName = CurrBlock->IsLocalName(SearchOp); STARSSCCPMapIter ConstValIter; if (this->GetBlock()->IsLocalName(SearchOp)) { // local name ConstValIter = this->GetBlock()->FindLocalConstValue(DefHashValue); if (ConstValIter != this->GetBlock()->GetLastLocalConstValueIter()) { // Has current const val entry ConstStruct = ConstValIter->second; } } else { // global name ConstValIter = CurrBlock->GetFunc()->FindConstValue(DefHashValue); if (ConstValIter != CurrBlock->GetFunc()->GetLastConstValueIter()) { // Has current const val entry ConstStruct = ConstValIter->second; } } } } return; } // end of SMPInstr::SCCPFetchConstDefValue() // Trace UseOp through register moves back to its stack location or immediate value source. // Return true if we are passing an immediate or stack location back in UltSource. bool SMPInstr::TraceUltimateMoveSource(const STARSOpndTypePtr &UseOp, int UseSSANum, STARSOpndTypePtr &UltSource, bool &FPRelative) { // If we hit an immediate value or a stack location, we are done. bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); STARSOpndTypePtr DefOp = nullptr, ImmOp = nullptr; int NewUseSSANum; set<DefOrUse,LessDefUse>::iterator UseIter; bool LocalName; STARS_ea_t DefAddr; SMPInstr *DefInst; UltSource = nullptr; bool StackOp = MDIsDirectStackAccessOpnd(UseOp, UseFP); bool RegisterOp = (UseOp->IsRegOp()); if (this->GetOptType() == 3) { // move instruction if (UseOp->IsImmedOp()) { UltSource = UseOp; return true; } else if ((!RegisterOp) && (!StackOp)) { // We only trace the move chain through registers or stack locations to an ultimate // load-effective-address of a stack location, or a move of an immediate value. return false; } } else if (!this->MDIsLoadEffectiveAddressInstr()) { return false; } else { // Load effective address instruction. // If it is a stack location being loaded, trace succeeded, else it failed. if (StackOp) { UltSource = UseOp; FPRelative = this->HasFPNormalizedToSP(); return true; } else { return false; } } // If we reach this point, we have a move instruction but did not return true or false above. // Recursion case. Going back up the move chain has just produced a register or // a stack location, and we still need to find the stack address or immediate value // that was stored in the register or stack location. The stack location could hold // a pointer to a stack object, produced by an earlier LEA instruction, or it // could hold an immediate value (e.g. constant size argument passed to memset() or // similar function). LocalName = this->GetBlock()->IsLocalName(UseOp); DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(UseOp, this->GetAddr(), UseSSANum, LocalName); if ((STARS_BADADDR == DefAddr) || (STARS_IsBlockNumPseudoID(DefAddr))) { // Def was not found, or was found in Phi function (DefAddr was block number, not instruction addr). return false; } if (STARS_IsLiveInPseudoID(DefAddr)) { // If DefAddr is 1 byte less than the first addr in the block, then // it is a pseudo-def in the global DU chains, signifying that the // value was LiveIn and the true DEF is in another block. We could // handle this in the future, but right now we will only deal with // the simpler case in which the move source can be traced // within the basic block. return false; } // Everything is OK so far; time to recurse up the move chain. STARSOpndTypePtr NewUseOp = nullptr; // next UseOp up the move chain DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr); if (DefInst->GetOptType() == 3) { NewUseOp = CloneIfSubwordReg(DefInst->GetMoveSource()); } else if (DefInst->MDIsLoadEffectiveAddressInstr()) { NewUseOp = DefInst->GetLeaMemUseOp(); if (MDIsDirectStackAccessOpnd(NewUseOp, UseFP)) { UltSource = NewUseOp; FPRelative = DefInst->HasFPNormalizedToSP(); return true; } else { return false; } } // We don't have a move instruction or a load effective address instruction, which // can be used to move a stack address into a register. We don't try to trace through // arithmetic except for two easy cases. // Case 1: A register is cleared. Same as assigning immediate value zero to the reg. else if (DefInst->IsRegClearIdiom()) { UltSource = this->STARSInstPtr->MakeImmediateOpnd(0); // why would we memset a zero byte region? return true; } // Easy arithmetic Case 2: we have reg += ImmediateValue, and reg was DEFed by reg := LEA(StackLoc). else if (DefInst->MDIsAddImmediateToReg(DefOp, ImmOp)) { SMPInstr *NewDefInst; UseIter = DefInst->FindUse(DefOp); assert(UseIter != DefInst->GetLastUse()); NewUseSSANum = UseIter->GetSSANum(); LocalName = DefInst->GetBlock()->IsLocalName(DefOp); DefAddr = DefInst->GetBlock()->GetDefAddrFromUseAddr(DefOp, DefInst->GetAddr(), NewUseSSANum, LocalName); if ((STARS_BADADDR == DefAddr) || (STARS_IsBlockNumPseudoID(DefAddr))) { // Def was not found, or was found in Phi function (DefAddr was block number, not instruction addr). return false; } NewDefInst = DefInst->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr); if (NewDefInst->MDIsLoadEffectiveAddressInstr()) { NewUseOp = NewDefInst->GetLeaMemUseOp()->clone(); if (MDIsDirectStackAccessOpnd(NewUseOp, UseFP)) { // We have the code sequence we were searching for when we first saw the // addition of an immediate value to a register, e.g.: // lea ebx,[ebp-2000] // add ebx,1000 // // We are essentially making this sequence into a single instruction: // lea ebx,[ebp-1000] // by adding the immediate value to the address offset. With a stack that grows // downward, it does not matter if we add 1000 to [esp+500] to produce [esp+1500], // or we add 1000 to [ebp-2000] to make [ebp-1000]. Either way, we are simulating the // addition of 1000 as we move up in the stack frame. STARS_ea_t NewAddr = NewUseOp->GetAddr() + ImmOp->GetImmedValue(); NewUseOp->SetAddr(NewAddr); // perform the address arithmetic addition UltSource = NewUseOp; FPRelative = NewDefInst->HasFPNormalizedToSP(); return true; } else { return false; } } else { return false; } } else { // Not the kind of instruction we need; cut short the recursion. return false; } // NewUseOp is the move source operand that we seek. CanonicalizeOpnd(NewUseOp); UseIter = DefInst->FindUse(NewUseOp); assert(UseIter != DefInst->GetLastUse()); NewUseSSANum = UseIter->GetSSANum(); // unused for immediates, used for regs and stack // Recurse return DefInst->TraceUltimateMoveSource(NewUseOp, NewUseSSANum, UltSource, FPRelative); } // end of SMPInstr::TraceUltimateMoveSource() // inst has no code xrefs? bool SMPInstr::HasNoCodeXrefs(void) { return global_stars_interface->InstHasNoCodeXrefs(this->GetInstID()); } // end of SMPInstr::HasNoCodeXrefs() // true => jump is used to exit a loop bool SMPInstr::IsLoopExitStatement(bool &InvertedExit) { bool FoundLoopExit = false; bool SingleBlockLoop = false; // NOTE: We assume that this method will not be called for // functions with irreducible CFGs. // For reducible CFGs, if we jump to a different loop nesting level, // this is a loop exit jump. SMPBasicBlock *SourceBlock = this->GetBlock(); int SourceBlockNum = SourceBlock->GetNumber(); int TargetBlockNum = SMP_BLOCKNUM_UNINIT; if (SourceBlock->GetFunc()->IsBlockInAnyLoop(SourceBlockNum)) { // we are currently in a loop InvertedExit = false; SingleBlockLoop = SourceBlock->IsSelfLoop(); if (!SingleBlockLoop) { int InnerLoopNum = SourceBlock->GetFunc()->GetInnermostLoopNum(SourceBlockNum); STARS_ea_t JumpTargetAddr = this->GetJumpTarget(); if ((STARS_BADADDR != JumpTargetAddr) && (!(this->IsTailCall() || this->IsCondTailCall() || this->IsBranchToOtherFunc()))) { SMPInstr *JumpTargetInst = SourceBlock->GetFunc()->GetInstFromAddr(JumpTargetAddr); TargetBlockNum = JumpTargetInst->GetBlock()->GetNumber(); // If TargetBlockNum is not in the current block's innermost loop num, we are exiting the innermost loop num. FoundLoopExit = (!(SourceBlock->GetFunc()->IsBlockInLoop(TargetBlockNum, InnerLoopNum))); } // Special case: Code layout by compiler puts loop header block at bottom of address range. // If COND_BRANCH is not taken, we fall out of the loop; if taken, we stay in the loop. // This is the INVERTED_LOOP_EXIT case. // Recent addition: Can fall out of any block in loop, not just loop header block. 03-APR-2017 if (!FoundLoopExit) { // We are currently in a loop, and taking the branch keeps us in the same inner loop. // Does not taking the branch cause us to fall out of the loop? list<SMPBasicBlock *>::const_iterator SuccIter = SourceBlock->GetFallThroughSucc(); if (SuccIter != SourceBlock->GetLastConstSucc()) { int FallThroughBlockNum = (*SuccIter)->GetNumber(); bool FallThroughLeavesLoop = (!(SourceBlock->GetFunc()->IsBlockInLoop(FallThroughBlockNum, InnerLoopNum))); if (FallThroughLeavesLoop) { // We found the INVERTED_LOOP_EXIT case. InvertedExit = true; FoundLoopExit = true; if (!SourceBlock->IsLoopHeaderBlock()) { SMP_msg("INFO: Found special case of INVERTED_LOOP_EXIT at %llx in %s\n", (uint64_t) this->GetAddr(), this->GetBlock()->GetFunc()->GetFuncName()); } } } } } } return FoundLoopExit; } // end of SMPInstr::IsLoopExitStatement() // For the SSA Marker instruction at the beginning of a function, see if incoming register types // can be obtained from the union/meet of all call sites. bool SMPInstr::InferMarkerInstTypes(void) { bool changed = false; if (this->IsMarkerInst()) { // SSA marker instruction is a floating nop placed at a pseudo-address. // Go through all USEs that are untyped and see if types can be obtained. set<DefOrUse, LessDefUse>::iterator MarkerDefIter = this->GetFirstDef(); while (MarkerDefIter != this->GetLastDef()) { STARSOpndTypePtr MarkerDefOp = MarkerDefIter->GetOp(); if (MarkerDefOp->IsRegOp() && (UNINIT == MarkerDefIter->GetType())) { // Find type of DEF, obtained from type meet function across all call site USEs. STARS_regnum_t RegNum = MarkerDefOp->GetReg(); SMPOperandType IncomingType = this->GetBlock()->GetFunc()->GetIncomingRegType(RegNum); if (UNINIT != IncomingType) { // Need to update type and propagate. MarkerDefIter = this->SetDefType(MarkerDefOp, IncomingType); changed = true; bool LocalName = this->GetBlock()->IsLocalName(MarkerDefOp); int DefSSANum = MarkerDefIter->GetSSANum(); if (LocalName) { this->GetBlock()->PropagateLocalDefType(MarkerDefOp, IncomingType, this->GetAddr(), DefSSANum, false, false); } else { this->GetBlock()->GetFunc()->ResetProcessedBlocks(); this->GetBlock()->PropagateGlobalDefType(MarkerDefOp, IncomingType, DefSSANum, false, false); } } } ++MarkerDefIter; } } return changed; } // end of SMPInstr::InferMarkerInstTypes() // Infer DEF, USE, and RTL SMPoperator types within the instruction based on the type // of operator, the type category of the instruction, and the previously known types // of the operands. bool SMPInstr::InferTypes(void) { bool changed = false; // return value int SSANum; unsigned short opcode = this->GetIDAOpcode(); int TypeCategory = SMPTypeCategory[opcode]; set<DefOrUse, LessDefUse>::iterator CurrDef; set<DefOrUse, LessDefUse>::iterator CurrUse; STARSOpndTypePtr DefOp = nullptr, UseOp = nullptr; bool DebugFlag = false; bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); bool SafeFunc = this->BasicBlock->GetFunc()->IsSafe(); bool IsMemOp; #if SMP_VERBOSE_DEBUG_INFER_TYPES DebugFlag |= (0 == strcmp("ext_wmatch", this->BasicBlock->GetFunc()->GetFuncName())); #if 1 if (DebugFlag) { SMP_msg("InstAddr: %llx opcode: %d TypeCategory: %d\n", (uint64_t) this->GetAddr(), opcode, TypeCategory); } #endif #endif // If we are already finished with all types, return false. if (this->IsTypeInferenceComplete()) return false; if (this->AllDEFsTyped() && this->AllUSEsTyped()) { this->SetTypeInferenceComplete(); return false; } if (this->HasDestMemoryOperand()) { changed |= this->MDFindPointerUse(this->MDGetMemDefOp(), UseFP); } if (this->HasSourceMemoryOperand()) { changed |= this->MDFindPointerUse(this->MDGetMemUseOp(), UseFP); } // The control flow instructions can be handled simply based on their type // and do not need an RTL walk. SMPitype DFAType = this->GetDataFlowType(); bool CallInst = ((DFAType == CALL) || (DFAType == INDIR_CALL) || this->IsTailCall()); #if SMP_VERBOSE_DEBUG_INFER_TYPES if (DebugFlag) { SMP_msg("%llx DFAType: %d CategoryInferenceComplete: %d\n", (uint64_t) this->GetAddr(), DFAType, this->IsCategoryInferenceComplete()); } #endif STARS_regnum_t IndirCallReg = STARS_x86_R_none; if (DFAType == INDIR_CALL) { STARSOpndTypePtr TargetOp = this->STARSInstPtr->GetOpnd(0); if (TargetOp->IsRegOp()) IndirCallReg = TargetOp->GetReg(); } if (IsBranchOrCall(DFAType) || this->IsTailCall()) { // All USEs are either the flags (NUMERIC) or the target address (CODEPTR). // The exceptions are the USE list for calls, which includes // the caller-saved regs, and indirect calls through a memory // operand, such as call [ebx+esi+20h], where the memory operand // is a CODEPTR but the addressing registers are a BaseReg and // IndexReg as in any other memory addressing. CurrUse = this->GetFirstUse(); while (CurrUse != this->GetLastUse()) { UseOp = CurrUse->GetOp(); bool NotCodePtrType = !IsCodePtr(CurrUse->GetType()); bool AddressReg = (this->HasSourceMemoryOperand() && UseOp->IsRegOp() && (!this->IsNonAddressReg(UseOp))); if (UseOp->MatchesReg(X86_FLAGS_REG)) CurrUse = this->SetUseType(UseOp, NUMERIC); #if 0 else if ((CurrUse->GetType() != CODEPTR) && (!(this->IsInterruptCall() && (UseOp->IsRegOp()))) && (!(CallInst && (UseOp->IsRegOp()))) && (!(this->HasSourceMemoryOperand() && (INDIR_CALL == this->GetDataFlowType()) && (UseOp->IsRegOp()))) ) { #else else if (!UseOp->IsRegOp() && NotCodePtrType) { #endif CurrUse = this->SetUseType(UseOp, CODEPTR); if (CallInst) { // If the call is to malloc(), then the DEF of the return // register is of type HEAPPTR. changed |= this->MDFindMallocCall(UseOp); } } else if (NotCodePtrType && CallInst && UseOp->MatchesReg(IndirCallReg)) { CurrUse = this->SetUseType(UseOp, CODEPTR); } if (CallInst && (CurrUse->GetType() == CODEPTR)) { // See if callee function has a type inferred for registers that it DEFs. // NOTE: We could do this more than once in the future, in case we iterate // over all funcs in the program graph. STARS_ea_t CalleeAddr = UseOp->GetAddr(); SMPFunction *CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalleeAddr); if (nullptr != CalleeFunc) { CurrDef = this->GetFirstDef(); while (CurrDef != this->GetLastDef()) { DefOp = CurrDef->GetOp(); if (DefOp->IsRegOp()) { SMPOperandType RegType = (SMPOperandType) CalleeFunc->GetReturnRegType(DefOp->GetReg()); bool LocalName = this->GetBlock()->IsLocalName(DefOp); if (UNINIT != RegType) { SMPOperandType CurrentRegType = CurrDef->GetType(); if (UNINIT == CurrentRegType) { // Use type from callee. CurrDef = this->SetDefType(DefOp, RegType); bool PtrOverride = IsDataPtr(RegType); // Certain we are getting POINTER from callee, so change NUMERIC USEs to POINTER if (LocalName) { this->GetBlock()->PropagateLocalDefType(DefOp, RegType, this->GetAddr(), CurrDef->GetSSANum(), false, PtrOverride); } else { this->GetBlock()->GetFunc()->ResetProcessedBlocks(); // prepare for recursion this->GetBlock()->PropagateGlobalDefType(DefOp, RegType, CurrDef->GetSSANum(), false, PtrOverride); } } } // Do the same for FGInfo. if (DefOp->GetReg() < (decltype(DefOp->GetReg()))CalleeFunc->GetReturnRegFGInfoSize()) { int DefSSANum = CurrDef->GetSSANum(); int DefHashIndex = HashGlobalNameAndSSA(DefOp, DefSSANum); struct FineGrainedInfo CalleeRegFGInfo = CalleeFunc->GetReturnRegFGInfo(DefOp->GetReg()); if (LocalName) { this->GetBlock()->UpdateDefFGInfo(DefHashIndex, CalleeRegFGInfo); } else { this->GetBlock()->GetFunc()->UpdateDefFGInfo(DefHashIndex, CalleeRegFGInfo); } } } ++CurrDef; } // end while not the last DEF // Get types for USEs of the CALL inst from the MarkerInst types inside CalleeFunc STARSDefUseIter CallUseIter = this->GetFirstUse(); while (CallUseIter != this->GetLastUse()) { SMPOperandType CallUseType = UNINIT; STARSOpndTypePtr CallUseOp = CallUseIter->GetOp(); if (CalleeFunc->GetMarkerInstDefType(CallUseOp, CallUseType)) { // CalleeFunc marker inst DEFed the current use with type CallUseType. bool TypeErrorFlag = false; CallUseType = SMPTypeMeet(CallUseType, CallUseIter->GetType(), TypeErrorFlag); if (TypeErrorFlag) { SMP_msg("ERROR: TypeMeet error at call addr %llx CalleeAddr %llx\n", (uint64_t) this->GetAddr(), (uint64_t) CalleeAddr); } CallUseIter = this->SetUseType(CallUseOp, CallUseType); } ++CallUseIter; } } // end if (NULL != CalleeFunc) } // end if (CallInst and CODEPTR USE) ++CurrUse; } // end while all USEs this->SetTypeInferenceComplete(); return true; } // First, see if we can infer something about DEFs and USEs just from the // type category of the instruction. if (!this->IsCategoryInferenceComplete()) { bool MemPropagate = false; switch (TypeCategory) { case 0: // no inference possible just from type category case 1: // no inference possible just from type category case 3: // MOV instructions; inference will come from source to dest in RTL walk. case 5: // binary arithmetic; inference will come in RTL walk. case 10: // binary arithmetic; inference will come in RTL walk. case 11: // push and pop instructions; inference will come in RTL walk. case 12: // exchange instructions; inference will come in RTL walk. this->SetCategoryInferenceComplete(); break; case 2: // Result type is always NUMERIC. case 7: // Result type is always NUMERIC. case 8: // Result type is always NUMERIC. case 9: // Result type is always NUMERIC. case 13: // Result type is always NUMERIC. case 14: // Result type is always NUMERIC. !!!!****!!!! scas should not be here, or don't reset POINTERs to NUMERICs case 15: // Result type is always NUMERIC. CurrDef = this->GetFirstDef(); while (CurrDef != this->GetLastDef()) { if (!IsEqType(NUMERIC, CurrDef->GetType())) { DefOp = CurrDef->GetOp(); SSANum = CurrDef->GetSSANum(); CurrDef = this->SetDefType(DefOp, NUMERIC); changed = true; // Be conservative and only propagate register DEFs and SAFE stack locs. We // can improve this in the future. **!!** bool IsMemOp = (! DefOp->IsRegOp()); bool MemPropagate = MDIsDirectStackAccessOpnd(DefOp, UseFP); #if SMP_PROPAGATE_MEM_TYPES ; #else // Be conservative and only propagate register DEFs and SAFE stack locs. // We can improve this in the future. **!!** MemPropagate = MemPropagate && SafeFunc; #endif if ((DefOp->IsRegOp()) || MemPropagate) { if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC, this->GetAddr(), SSANum, IsMemOp); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC, SSANum, IsMemOp, false); } } } ++CurrDef; } this->SetCategoryInferenceComplete(); break; case 4: // Unary INC, DEC, etc.: dest=source, so type remains the same assert(1 == this->RTL.GetCount()); assert(this->RTL.GetRT(0)->HasRightSubTree()); UseOp = this->RTL.GetRT(0)->GetLeftOperand(); // USE == DEF CurrUse = this->Uses.FindRef(UseOp); assert(CurrUse != this->GetLastUse()); if (UNINIT != CurrUse->GetType()) { // Only one USE, and it has a type assigned, so assign that type // to the DEF. CurrDef = this->GetFirstDef(); while (CurrDef != this->GetLastDef()) { // Two DEFs: EFLAGS is NUMERIC, dest==source DefOp = CurrDef->GetOp(); SSANum = CurrDef->GetSSANum(); if (DefOp->MatchesReg(X86_FLAGS_REG)) { ; // SetImmedTypes already made it NUMERIC } else { CurrDef = this->SetDefType(DefOp, CurrUse->GetType()); // Be conservative and only propagate register DEFs and SAFE stack locs. We // can improve this in the future. **!!** bool IsMemOp = (! DefOp->IsRegOp()); MemPropagate = MDIsDirectStackAccessOpnd(DefOp, UseFP); #if SMP_PROPAGATE_MEM_TYPES ; #else // Be conservative and only propagate register DEFs and SAFE stack locs. // We can improve this in the future. **!!** MemPropagate = MemPropagate && SafeFunc; #endif if ((DefOp->IsRegOp()) || MemPropagate) { if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, CurrUse->GetType(), this->GetAddr(), SSANum, IsMemOp); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, CurrUse->GetType(), SSANum, IsMemOp, false); } } } ++CurrDef; } this->SetCategoryInferenceComplete(); changed = true; this->SetTypeInferenceComplete(); } break; case 6: // Result is always POINTER DefOp = this->GetFirstDef()->GetOp(); SSANum = this->GetFirstDef()->GetSSANum(); CurrDef = this->SetDefType(DefOp, POINTER); this->SetCategoryInferenceComplete(); changed = true; // Be conservative and only propagate register DEFs and SAFE stack locs. We // can improve this in the future. **!!** IsMemOp = (! DefOp->IsRegOp()); MemPropagate = MDIsDirectStackAccessOpnd(DefOp, UseFP); #if SMP_PROPAGATE_MEM_TYPES ; #else // Be conservative and only propagate register DEFs and SAFE stack locs. // We can improve this in the future. **!!** MemPropagate = MemPropagate && SafeFunc; #endif if ((DefOp->IsRegOp()) || MemPropagate) { if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, POINTER, this->GetAddr(), SSANum, IsMemOp); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, POINTER, SSANum, IsMemOp, false); } } break; default: SMP_msg("ERROR: Unknown type category for %s\n", DisAsmText.GetDisAsm(this->GetAddr())); this->SetCategoryInferenceComplete(); break; } // end switch on TypeCategory } // end if (!CategoryInference) // Walk the RTL and infer types based on operators and operands. #if SMP_VERBOSE_DEBUG_INFER_TYPES if (DebugFlag) { SMP_msg("RTcount: %zu\n", this->RTL.GetCount()); } #endif for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) { SMPRegTransfer *CurrRT = this->RTL.GetRT(index); if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer continue; if (!(CurrRT->IsTypeInferenceComplete())) { changed |= this->InferOperatorType(CurrRT); } #if SMP_VERBOSE_DEBUG_INFER_TYPES if (DebugFlag) { SMP_msg("returned from InferOperatorType\n"); } #endif } // end for all RTs in the RTL return changed; } // end of SMPInstr::InferTypes() // Infer the type of an operator within an RT based on the types of its operands and // based on the operator itself. Recurse down the tree if necessary. // Return true if the operator type of the RT is updated. bool SMPInstr::InferOperatorType(SMPRegTransfer *CurrRT) { bool updated = false; bool LeftNumeric, RightNumeric, OperNumeric; bool LeftPointer, RightPointer, OperPointer; bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); bool SafeFunc = this->BasicBlock->GetFunc()->IsSafe(); set<DefOrUse, LessDefUse>::iterator CurrDef; set<DefOrUse, LessDefUse>::iterator CurrUse; set<DefOrUse, LessDefUse>::iterator LeftUse; set<DefOrUse, LessDefUse>::iterator RightUse; SMPOperandType LeftType = UNINIT; SMPOperandType RightType = UNINIT; SMPOperandType OperType = CurrRT->GetOperatorType(); STARSOpndTypePtr UseOp = nullptr, DefOp = nullptr, LeftOp = nullptr, RightOp = nullptr; SMPoperator CurrOp = CurrRT->GetOperator(); bool TypeInferenceFinished = false; #if SMP_VERBOSE_DEBUG_INFER_TYPES bool DebugFlag = false; #if 1 DebugFlag |= (0 == strcmp("ext_wmatch", this->BasicBlock->GetFunc()->GetFuncName())); #endif DebugFlag = DebugFlag || ((this->GetAddr() == 0x806453b) || (this->GetAddr() == 0x806453e)); #endif #if SMP_VERBOSE_DEBUG_INFER_TYPES if (DebugFlag) { SMP_msg("Entered InferOperatorType for CurrOp: %s at %llx\n", OperatorText[CurrOp], (uint64_t) this->GetAddr()); } #endif if (CurrRT->IsTypeInferenceComplete()) { return updated; } switch (CurrOp) { case SMP_NULL_OPERATOR: case SMP_SIGNAL: // signal or raise exception TypeInferenceFinished = true; break; case SMP_CALL: // CALL instruction if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(CODEPTR, this); updated = true; UseOp = CurrRT->GetRightOperand(); CurrUse = this->Uses.FindRef(UseOp); assert(CurrUse != this->GetLastUse()); if (UNINIT == CurrUse->GetType()) { CurrUse = this->SetUseType(UseOp, CODEPTR); } else if (CODEPTR != CurrUse->GetType()) { SMP_msg("WARNING: call target is type %d, setting to CODEPTR at %llx in %s\n", CurrUse->GetType(), (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); CurrUse = this->SetUseType(UseOp, CODEPTR); } } TypeInferenceFinished = true; break; case SMP_INPUT: // input from port case SMP_OUTPUT: // output to port if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(NUMERIC, this); updated = true; } break; #if 0 case SMP_SIGN_EXTEND: case SMP_ZERO_EXTEND: // Should we infer that all operands are NUMERIC? !!!???!!!! if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(NUMERIC, this); updated = true; } break; #endif case SMP_ADDRESS_OF: // take effective address if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(POINTER, this); // Left operand is having its address taken, but we cannot infer what its // type is. updated = true; } break; case SMP_UNARY_POINTER_OPERATION: // increment or decrement a pointer if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(POINTER, this); updated = true; // Left operand should be NUMERIC if it exists. UseOp = CurrRT->GetLeftOperand(); if ((nullptr != UseOp) && (!UseOp->IsVoidOp())) { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" at %llx in %s\n", (uint64_t) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(UseOp, POINTER, -1); } else if (UNINIT == CurrUse->GetType()) { CurrUse = this->SetUseType(UseOp, NUMERIC); } } } break; #if 0 case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_U_COMPARE: // unsigned compare (AND-based) // not much to do; perhaps propagate LeftType or RightType to the other? LeftOp = CurrRT->GetLeftOperand(); RightOp = CurrRT->GetRightOperand(); assert((nullptr != LeftOp) && (!LeftOp->IsVoidOp())); assert((nullptr != RightOp) && (!RightOp->IsVoidOp())); LeftUse = this->FindUse(LeftOp); RightUse = this->FindUse(RightOp); if ((LeftUse != this->GetLastUse()) && (RightUse != this->GetLastUse())) { LeftType = LeftUse->GetType(); RightType = RightUse->GetType(); if (((UNINIT == LeftType) || (UNINIT == RightType)) && (LeftType != RightType)) { // One type is UNINIT, the other is not. Propagate type to the UNINIT side. if (UNINIT == LeftType) { this->SetUseType(LeftOp, RightType); } else { this->SetUseType(RightOp, LeftType); } updated = true; } if ((LeftType == RightType) && (UNINIT == OperType) && (UNINIT != LeftType)) { CurrRT->SetOperatorType(LeftType, this); updated = true; } } break; #endif case SMP_SIGN_EXTEND: case SMP_ZERO_EXTEND: case SMP_U_LEFT_SHIFT: // unsigned left shift case SMP_S_LEFT_SHIFT: // signed left shift case SMP_U_RIGHT_SHIFT: // unsigned right shift case SMP_S_RIGHT_SHIFT: // signed right shift case SMP_ROTATE_LEFT: case SMP_ROTATE_LEFT_CARRY: // rotate left through carry case SMP_ROTATE_RIGHT: case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry case SMP_U_MULTIPLY: case SMP_S_MULTIPLY: case SMP_U_DIVIDE: case SMP_S_DIVIDE: case SMP_U_REMAINDER: case SMP_BITWISE_XOR: case SMP_BITWISE_AND_NOT: #if 1 case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_U_COMPARE: // unsigned compare (AND-based) #endif case SMP_GENERAL_COMPARE: case SMP_LESS_THAN: // boolean test operators case SMP_GREATER_THAN: case SMP_LESS_EQUAL: case SMP_GREATER_EQUAL: case SMP_EQUAL: case SMP_NOT_EQUAL: case SMP_BELOW: case SMP_BELOW_EQUAL: case SMP_ABOVE: case SMP_ABOVE_EQUAL: case SMP_LOGICAL_AND: case SMP_LOGICAL_OR: case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_FLOATING_ADD: case SMP_FLOATING_SUBTRACT: case SMP_FLOATING_MULTIPLY: // floating-point multiplication of any precision; all NUMERIC case SMP_FLOATING_DIVIDE: // floating-point division of any precision; all NUMERIC case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC case SMP_REVERSE_SHIFT_U: // all the same to our type system; all NUMERIC case SMP_SHUFFLE: // all the same to our type system; all NUMERIC case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's case SMP_COMPARE_NE_AND_SET: // Compare for inequality and set fields to all 1's or all 0's case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision case SMP_AVERAGE_U: // Average of unsigned operands case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate) case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements case SMP_MAX_S: // dest := signed_max(dest, src) case SMP_MAX_U: // dest := unsigned_max(dest, src) case SMP_MIN_S: // dest := signed_min(dest, src) case SMP_MIN_U: // dest := unsigned_min(dest, src) case SMP_ABSOLUTE_VALUE: // take absolute value case SMP_CONVERT_INT_TO_FP: // convert integer to floating point case SMP_CONVERT_FP_TO_INT: // convert floating point to integer case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate case SMP_INTERLEAVE: // interleave fields from two packed operands; NUMERIC case SMP_CONCATENATE: // all the same to our type system; all NUMERIC case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length if ((SMP_ZERO_EXTEND == CurrOp) && this->IsRegUpperBitsClearIdiom()) { // The zero extension is not movzx rbx,al; it is mov r8d,eax where // the upper 32 bits of R8 get zeroed by the move. EAX could have // any type, and we wish to preserve it. UseOp = CurrRT->GetLeftOperand(); assert((nullptr != UseOp) && (!UseOp->IsVoidOp())); CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(UseOp, NUMERIC, -1); updated = true; } else if (UNINIT != CurrUse->GetType()) { CurrRT->SetOperatorType(CurrUse->GetType(), this); updated = true; } } else { if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(NUMERIC, this); updated = true; } // Left operand should be NUMERIC if it exists. UseOp = CurrRT->GetLeftOperand(); if ((nullptr != UseOp) && (!UseOp->IsVoidOp())) { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(UseOp, NUMERIC, -1); updated = true; } else if (UNINIT == CurrUse->GetType()) { CurrUse = this->SetUseType(UseOp, NUMERIC); updated = true; } } // Right operand should be NUMERIC if it exists. if (CurrRT->HasRightSubTree()) { // Recurse into subtree #if SMP_AGGRESSIVE_TYPE_INFERENCE if (UNINIT == CurrRT->GetRightTree()->GetOperatorType()) { CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this); updated = true; } #endif updated |= this->InferOperatorType(CurrRT->GetRightTree()); } else { UseOp = CurrRT->GetRightOperand(); if ((nullptr != UseOp) && (!UseOp->IsVoidOp())) { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(UseOp, NUMERIC, -1); updated = true; } else if (UNINIT == CurrUse->GetType()) { CurrUse = this->SetUseType(UseOp, NUMERIC); updated = true; } } } } break; case SMP_BITWISE_NOT: // unary operator case SMP_NEGATE: // unary negation UseOp = CurrRT->GetLeftOperand(); assert((nullptr != UseOp) && (! UseOp->IsVoidOp())); CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); updated = true; } else { OperType = CurrRT->GetOperatorType(); LeftType = CurrUse->GetType(); // Only tricky cases are the negation of a POINTER or PTROFFSET. // Negation of PTROFFSET could be inefficient code that computed // PTR1 - PTR2 and later corrected it to PTR2 - PTR1 by negation. // The type remains PTROFFSET. Negating a POINTER could be an unusual // case similar to subtracting a POINTER from a NUMERIC. See comments // in the SMP_ADD case below, and also the SMP_SUBTRACT case. if (LeftType == PTROFFSET) { // Override any prior operator type, in case PTROFFSET was inferred late // in our analysis and the operator was set to NUMERIC. CurrRT->SetOperatorType(PTROFFSET, this); updated = true; if (CurrOp == SMP_BITWISE_NOT) SMP_msg("INFO: NOT of PTROFFSET at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else if (IsDataPtr(LeftType)) { // Override any prior operator type, in case POINTER was inferred late // in our analysis and the operator was set to NUMERIC. CurrRT->SetOperatorType(NEGATEDPTR, this); SMP_msg("INFO: Pointer negated at %llx %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); updated = true; } else if (OperType == UNINIT) { // Default to NUMERIC for most negations. CurrRT->SetOperatorType(NUMERIC, this); // But, leave left operand type alone, in case an UNINIT operand // might be determined later to be PTROFFSET or NEGATEDPTR. // Leaving it alone causes us not to set TypeInferenceFinished to true // at the end of this function in the UNINIT case. updated = true; } } break; case SMP_INCREMENT: case SMP_DECREMENT: // The type of the left operand is propagated to the operator, or vice // versa, whichever receives a type first. assert(!CurrRT->HasRightSubTree()); UseOp = CurrRT->GetLeftOperand(); assert((nullptr != UseOp) && (! UseOp->IsVoidOp())); CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(UseOp); updated = true; break; } if (UNINIT == CurrRT->GetOperatorType()) { if (UNINIT != CurrUse->GetType()) { // Propagate operand type up to the operator. CurrRT->SetOperatorType(CurrUse->GetType(), this); updated = true; } } else if (UNINIT == CurrUse->GetType()) { // Propagate operator type to operand. CurrUse = this->SetUseType(UseOp, CurrRT->GetOperatorType()); updated = true; } break; case SMP_ADD: case SMP_ADD_CARRY: // add with carry case SMP_BITWISE_AND: case SMP_BITWISE_OR: // Extract the current types of right and left operands and the operator. OperType = CurrRT->GetOperatorType(); LeftOp = CurrRT->GetLeftOperand(); CurrUse = this->Uses.FindRef(LeftOp); assert(CurrUse != this->GetLastUse()); // found it LeftType = CurrUse->GetType(); if (CurrRT->HasRightSubTree()) { updated |= this->InferOperatorType(CurrRT->GetRightTree()); RightType = CurrRT->GetRightTree()->GetOperatorType(); } else { RightOp = CurrRT->GetRightOperand(); if ((nullptr == RightOp) || RightOp->IsVoidOp()) { SMP_msg("ERROR: void operand at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); return updated; } else { CurrUse = this->Uses.FindRef(RightOp); if (CurrUse == this->GetLastUse()) { SMP_msg("SERIOUS WARNING: Adding missing USE of "); PrintOperand(RightOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(RightOp); updated = true; break; } else { RightType = CurrUse->GetType(); } } } // We have to know both operand types to infer the operator, or know the // operator type and one operand type to infer the other operand type. if ((UNINIT == OperType) && ((UNINIT == LeftType) || (UNINIT == RightType))) break; // If both operands are NUMERIC, operator and result are NUMERIC. // If one operand is NUMERIC and the other is a pointer type, // then the ADD operator and the result will inherit this second type, // while AND and OR operators will remain UNINIT (we don't know what // type "ptr AND 0xfffffff8" has until we see how it is used). LeftNumeric = IsEqType(NUMERIC, LeftType); RightNumeric = IsEqType(NUMERIC, RightType); LeftPointer = IsDataPtr(LeftType); RightPointer = IsDataPtr(RightType); if (UNINIT == OperType) { // Infer operator type from left and right operands. if (LeftNumeric && RightNumeric) { CurrRT->SetOperatorType(NUMERIC, this); updated = true; break; } else if (LeftNumeric || RightNumeric) { // ADD of NUMERIC to non-NUMERIC preserves non-NUMERIC type. // AND and OR operations should leave the operator UNINIT for now. if (LeftNumeric && (UNINIT != RightType) && ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) { CurrRT->SetOperatorType(RightType, this); updated = true; break; } else if (RightNumeric && (UNINIT != LeftType) && ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) { CurrRT->SetOperatorType(LeftType, this); updated = true; break; } } else if (LeftPointer && RightPointer) { // Arithmetic on two pointers if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) { CurrRT->SetOperatorType(UNKNOWN, this); updated = true; } else { // bitwise AND or OR of two pointers SMP_msg("WARNING: hash of two pointers at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); // hash operation? leave operator as UNINIT } break; } else if ((LeftPointer && IsEqType(RightType, PTROFFSET)) || (RightPointer && IsEqType(LeftType, PTROFFSET))) { // Arithmetic on PTR and PTROFFSET if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) { // We assume (A-B) is being added to B or vice versa **!!** CurrRT->SetOperatorType(POINTER, this); updated = true; } else { // bitwise AND or OR of pointer and pointer difference SMP_msg("WARNING: hash of PTROFFSET and POINTER at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); // hash operation? leave operator as UNINIT } break; } else if ((LeftPointer && IsEqType(RightType, NEGATEDPTR)) || (RightPointer && IsEqType(LeftType, NEGATEDPTR))) { // Compiler optimizations can take a ptr expression such as: // PTR1 - PTR2 + 1 // and hoist the loop-invariant subexpression " - PTR2 + 1" // out of the loop as "1 - PTR2", which produces a NEGATEDPTR type. // When PTR1 gets its value determined inside the loop, then the // addition of PTR1 finally happens, producing a PTROFFSET type, // which is what the whole expression is. if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) { CurrRT->SetOperatorType(PTROFFSET, this); updated = true; } else { // bitwise AND or OR of pointer and pointer difference SMP_msg("WARNING: hash of NEGATEDPTR and POINTER at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); // hash operation? leave operator as UNINIT } break; } else if (IsEqType(CODEPTR, LeftType) || IsEqType(CODEPTR, RightType)) { if ((LeftType <= CODEPTR) && (RightType <= CODEPTR)) { // Both types are NUMERIC or UNINIT with one or both of them CODEPTR CurrRT->SetOperatorType(CODEPTR, this); updated = true; } else { SMP_msg("WARNING: add of CODEPTR and odd type %d plus %d at %llx in %s\n", LeftType, RightType, (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } } } // end if UNINIT operator type else { // operator has type other than UNINIT // We make add-with-carry and subtract-with-borrow exceptions // to the type propagation. LeftOp could have POINTER type // inferred later; these instructions can change the type of // the register from POINTER to NUMERIC, unlike regular // add and subtract opcodes. OperNumeric = IsEqType(NUMERIC, OperType); OperPointer = IsDataPtr(OperType); if (OperNumeric) { if ((UNINIT == LeftType) && (SMP_ADD_CARRY != CurrOp)) { CurrUse = this->SetUseType(LeftOp, CurrRT->GetOperatorType()); updated = true; assert(CurrUse != this->GetLastUse()); break; } if (CurrRT->HasRightSubTree()) { // Must need to iterate through the right tree again, as the operator // has been typed. if (UNINIT == RightType) { CurrRT->GetRightTree()->SetOperatorType(CurrRT->GetOperatorType(), this); updated = true; updated |= this->InferOperatorType(CurrRT->GetRightTree()); } break; } else { // right operand; propagate operator type if needed if (UNINIT == RightType) { CurrUse = this->SetUseType(RightOp, CurrRT->GetOperatorType()); updated = true; assert(CurrUse != this->GetLastUse()); break; } } } else if (OperPointer) { // If we add NUMERIC + UNINIT and get POINTER, then the UNINIT is a POINTER. Ditto for AND and OR. if (LeftNumeric && (UNINIT == RightType)) { if (CurrRT->HasRightSubTree()) { CurrRT->GetRightTree()->SetOperatorType(OperType, this); } else { CurrUse = this->SetUseType(RightOp, OperType); updated = true; assert(CurrUse != this->GetLastUse()); } break; } else if (RightNumeric && (UNINIT == LeftType)) { CurrUse = this->SetUseType(LeftOp, OperType); updated = true; assert(CurrUse != this->GetLastUse()); break; } } } break; case SMP_SUBTRACT: case SMP_SUBTRACT_BORROW: // subtract with borrow // Extract the current types of right and left operands and the operator. OperType = CurrRT->GetOperatorType(); LeftOp = CurrRT->GetLeftOperand(); LeftUse = this->Uses.FindRef(LeftOp); assert(LeftUse != this->GetLastUse()); // found it LeftType = LeftUse->GetType(); if (CurrRT->HasRightSubTree()) { updated |= this->InferOperatorType(CurrRT->GetRightTree()); RightType = CurrRT->GetRightTree()->GetOperatorType(); } else { RightOp = CurrRT->GetRightOperand(); if ((nullptr == RightOp) || RightOp->IsVoidOp()) { SMP_msg("ERROR: void operand in %s\n", DisAsmText.GetDisAsm(this->GetAddr())); return false; } else { RightUse = this->Uses.FindRef(RightOp); if (RightUse == this->GetLastUse()) { SMP_msg("WARNING: Adding missing USE of "); PrintOperand(RightOp); SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(RightOp); updated = true; break; } else { RightType = RightUse->GetType(); } } } // If left operand is NUMERIC, operator is NUMERIC. LeftNumeric = IsEqType(NUMERIC, LeftType); RightNumeric = IsEqType(NUMERIC, RightType); LeftPointer = IsDataPtr(LeftType); RightPointer = IsDataPtr(RightType); if (LeftNumeric) { // Subtracting anything from a NUMERIC leaves it NUMERIC or NEGATEDPTR, // in the special case in which a POINTER is subtracted from a NUMERIC. // See NEGATEDPTR comments in the ADD/AND operators case above. if (RightPointer) { CurrRT->SetOperatorType(NEGATEDPTR, this); updated = true; } else if (UNINIT == OperType) { CurrRT->SetOperatorType(NUMERIC, this); updated = true; } else if (IsNotEqType(NUMERIC, OperType) && IsNotEqType(NEGATEDPTR, OperType)) { SMP_msg("ERROR: SMP_SUBTRACT from NUMERIC should be NUMERIC or NEGATEDPTR operator."); SMP_msg(" Operator type is %d in: %s\n", OperType, DisAsmText.GetDisAsm(this->GetAddr())); } #if 0 if (!RightNumeric) { // Right operand is being used as a NUMERIC, so propagate NUMERIC to it. if (CurrRT->HasRightSubTree()) { CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this); } else { RightUse = this->SetUseType(RightOp, NUMERIC); } updated = true; } #endif } // end if LeftNumeric else if (LeftPointer) { if (UNINIT == OperType) { // If we subtract another pointer type, we produce PTROFFSET. if (RightPointer) { CurrRT->SetOperatorType(PTROFFSET, this); updated = true; } else if (RightType == PTROFFSET) { // We assume B - (B - A) == A **!!** CurrRT->SetOperatorType(POINTER, this); SMP_msg("WARNING: PTR - PTROFFSET produces PTR at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); updated = true; } else if (RightNumeric) { // pointer minus NUMERIC keeps same pointer type CurrRT->SetOperatorType(LeftType, this); updated = true; } } else { // we have an operator type for the SMP_SUBTRACT OperNumeric = IsEqType(NUMERIC, OperType); OperPointer = IsDataPtr(OperType); if (CurrRT->HasRightSubTree()) { // Might need to iterate through the right tree again, if its operator // can be typed. if (UNINIT == RightType) { if (OperPointer) { #if 0 // PTR := PTR - ?? ==> ?? is NUMERIC Why? ?? could be PTROFFSET CurrRT->GetRightTree()->SetOperatorType(NUMERIC, this); updated = true; #endif updated |= this->InferOperatorType(CurrRT->GetRightTree()); } else if (OperType == PTROFFSET) { // PTROFFSET := PTR - ?? ==> ?? is PTR CurrRT->GetRightTree()->SetOperatorType(LeftType, this); updated = true; updated |= this->InferOperatorType(CurrRT->GetRightTree()); } else if (OperNumeric) { SMP_msg("WARNING: PTR - ?? produces NUMERIC at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } } break; } else { // right operand; propagate operator type if needed if (UNINIT == RightType) { if (OperPointer) { // PTR := PTR - ?? ==> ?? is NUMERIC Why? ?? could be PTROFFSET RightUse = this->SetUseType(RightOp, NUMERIC); updated = true; assert(RightUse != this->GetLastUse()); } else if (OperType == PTROFFSET) { // PTROFFSET := PTR - ?? ==> ?? is PTR RightUse = this->SetUseType(RightOp, LeftType); updated = true; } else if (OperNumeric) { SMP_msg("WARNING: PTR - ?? produces NUMERIC at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } break; } } } // end if OperType is UNINIT ... else ... } // end if LeftNumeric ... else if LeftPointer ... else if (UNINIT == LeftType) { // We make add-with-carry and subtract-with-borrow exceptions // to the type propagation. LeftOp could have POINTER type // inferred later; these instructions can change the type of // the register from POINTER to NUMERIC, unlike regular // add and subtract opcodes. if ((UNINIT != OperType) && (SMP_SUBTRACT_BORROW != CurrOp)) { LeftUse = this->SetUseType(LeftOp, OperType); assert(LeftUse != this->GetLastUse()); updated = true; } } break; case SMP_ASSIGN: // Extract the current types of right and left operands and SMP_ASSIGN operator. OperType = CurrRT->GetOperatorType(); DefOp = CurrRT->GetLeftOperand(); CurrDef = this->Defs.FindRef(DefOp); assert(CurrDef != this->GetLastDef()); // found it LeftType = CurrDef->GetType(); if (CurrRT->HasRightSubTree()) { updated |= this->InferOperatorType(CurrRT->GetRightTree()); RightType = CurrRT->GetRightTree()->GetOperatorType(); } else { UseOp = CurrRT->GetRightOperand(); if ((nullptr == UseOp) || UseOp->IsVoidOp()) { SMP_msg("ERROR: void operand for SMP_ASSIGN in %s\n", DisAsmText.GetDisAsm(this->GetAddr())); return false; } else { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { SMP_msg("WARNING: Adding missing USE of "); PrintOperand(UseOp); SMP_msg(" in %s\n", DisAsmText.GetDisAsm(this->GetAddr())); this->Uses.SetRef(UseOp); updated = true; break; } else { RightType = CurrUse->GetType(); } } } #if SMP_VERBOSE_DEBUG_INFER_TYPES if (DebugFlag) { SMP_msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->GetAddr(), LeftType, OperType, RightType); } #endif if ((UNINIT == RightType) && (UNINIT == LeftType)) { unsigned short TempSignMask; if (this->MDIsReducedWidthMove() && (!this->MDIsSignedLoad(TempSignMask))) { CurrDef = this->SetDefType(DefOp, NUMERIC); // e.g. mov al,cl cannot be a POINTER updated = true; if (!CurrRT->HasRightSubTree()) { CurrUse = this->SetUseType(UseOp, NUMERIC); } assert(UNINIT == OperType); CurrRT->SetOperatorType(NUMERIC, this); } break; } else if (UNINIT == OperType) { // UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT. bool UpdatedOperType = false; if (UNINIT != RightType) { // We have to special case conditional moves. Only if both operands // (the source and the prior value of the potential destination, // which was added to the USE set by BuildMoveRTL()) agree in type // can we propagate their common type to the operator and ultimately // to the DEF. if ((!this->MDIsConditionalMoveInstr()) || this->Uses.TypesAgreeNoFlags()) { CurrRT->SetOperatorType(RightType, this); updated = true; OperType = RightType; UpdatedOperType = true; } } else { // LeftType must not be UNINIT CurrRT->SetOperatorType(LeftType, this); updated = true; UpdatedOperType = true; OperType = LeftType; } // Speed up type propagation by passing the RightType/OperType to the Def // on this iteration. if (UpdatedOperType) { // Propagate the new DEF type unless it is an indirect memory access. // Future: Propagate until re-DEF of addressing register terminates // the propagation. **!!** CurrDef = this->SetDefType(DefOp, OperType); LeftType = OperType; if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) { bool IsMemOp = (! DefOp->IsRegOp()); bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP); #if SMP_PROPAGATE_MEM_TYPES ; #else // Be conservative and only propagate register DEFs and SAFE stack locs. // We can improve this in the future. **!!** MemPropagate = MemPropagate && SafeFunc; #endif if ((DefOp->IsRegOp()) || MemPropagate) { int SSANum = CurrDef->GetSSANum(); if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType, this->GetAddr(), SSANum, IsMemOp); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType, SSANum, IsMemOp, false); } } } } break; } else if (UNINIT == LeftType) { // SMP_ASSIGN operator has type, so propagate it. CurrDef = this->SetDefType(DefOp, OperType); LeftType = OperType; updated = true; // Propagate the new DEF type unless it is an indirect memory access. // Future: Propagate until re-DEF of addressing register terminates // the propagation. **!!** if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) { bool IsMemOp = (! DefOp->IsRegOp()); bool MemPropagate = MDIsStackAccessOpnd(DefOp, UseFP); #if SMP_PROPAGATE_MEM_TYPES ; #else // Be conservative and only propagate register DEFs and SAFE stack locs. // We can improve this in the future. **!!** MemPropagate = MemPropagate && SafeFunc; #endif if ((DefOp->IsRegOp()) || MemPropagate) { int SSANum = CurrDef->GetSSANum(); if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType, this->GetAddr(), SSANum, IsMemOp); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType, SSANum, IsMemOp, false); } } } break; } else if (UNINIT == RightType) { // SMP_ASSIGN operator has type, so propagate it. if (CurrRT->HasRightSubTree()) { CurrRT->GetRightTree()->SetOperatorType(OperType, this); updated = true; updated |= this->InferOperatorType(CurrRT->GetRightTree()); } else { // For conditional moves, propagate to the pseudo-USE of the // destination register as well as the source operand. if (this->MDIsConditionalMoveInstr()) { CurrUse = this->FindUse(DefOp); assert(CurrUse != this->GetLastUse()); if (UNINIT == CurrUse->GetType()) CurrUse = this->SetUseType(DefOp, OperType); else if (OperType != CurrUse->GetType()) { SMP_msg("WARNING: Avoiding lattice oscillation from type %d to %d at %llx for: ", CurrUse->GetType(), OperType, (unsigned long long) this->GetAddr()); PrintOperand(CurrUse->GetOp()); SMP_msg("\n"); } } CurrUse = this->SetUseType(UseOp, OperType); updated = true; RightType = OperType; } break; } break; default: SMP_msg("ERROR: Unknown operator %d at %llx in %s\n", CurrOp, (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); break; } // end switch on operator // Determine if type inference is finished for this register transfer. if (updated && (!TypeInferenceFinished)) { bool FinishedRight = false; bool FinishedLeft = false; bool FinishedOperator = (CurrRT->GetOperatorType() != UNINIT); if (FinishedOperator) { switch (CurrOp) { case SMP_INPUT: // input from port case SMP_OUTPUT: // output to port case SMP_SIGN_EXTEND: case SMP_ZERO_EXTEND: case SMP_ADDRESS_OF: // take effective address case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC case SMP_BITWISE_NOT: // unary operator case SMP_NEGATE: // unary negation case SMP_DECREMENT: case SMP_INCREMENT: case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_UNARY_POINTER_OPERATION: // Unary operators have no right operand. FinishedRight = true; break; default: // All binary operators come here if (CurrRT->HasRightSubTree()) { FinishedRight = CurrRT->GetRightTree()->IsTypeInferenceComplete(); } else { UseOp = CurrRT->GetRightOperand(); if ((nullptr != UseOp) && (! UseOp->IsVoidOp())) { CurrUse = this->Uses.FindRef(UseOp); assert(CurrUse != this->GetLastUse()); FinishedRight = (CurrUse->GetType() != UNINIT); } else { // if o_void, no further type inference on it is possible. FinishedRight = true; } } break; } // end switch on CurrOp if (FinishedRight) { // no point checking left op if right op is not finished DefOp = CurrRT->GetLeftOperand(); if (! DefOp->IsVoidOp()) { if (SMP_ASSIGN == CurrOp) { CurrDef = this->Defs.FindRef(DefOp); assert(CurrDef != this->GetLastDef()); FinishedLeft = (CurrDef->GetType() != UNINIT); } else { // not ASSIGN, so really a UseOp not DefOp CurrUse = this->Uses.FindRef(DefOp); assert(CurrUse != this->GetLastUse()); FinishedLeft = (CurrUse->GetType() != UNINIT); } } else { // if o_void, no further type inference on it is possible. FinishedLeft = true; } } TypeInferenceFinished = (FinishedLeft && FinishedRight); } // end if (FinishedOperator) } // end if (updated && (!TypeInferenceFinished)) if (TypeInferenceFinished) { CurrRT->SetTypeInferenceComplete(); } #if SMP_VERBOSE_DEBUG_INFER_TYPES if (updated && DebugFlag) { SMP_msg("INFO: Types updated at %llx Left: %d Operator: %d Right: %d\n", (uint64_t) this->GetAddr(), LeftType, OperType, RightType); } #endif return updated; } // end of SMPInstr::InferOperatorType() // Transfer function: Does operator propagate signedness of its operands to its result? bool SMPInstr::DoesOperatorTransferSign(SMPoperator CurrOp) { bool transfer = false; switch (CurrOp) { case SMP_NULL_OPERATOR: case SMP_CALL: // CALL instruction case SMP_INPUT: // input from port case SMP_OUTPUT: // output to port case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC case SMP_SIGNAL: // signal or raise exception // No concept of signedness for some operators break; case SMP_ADDRESS_OF: // take effective address case SMP_U_LEFT_SHIFT: // unsigned left shift case SMP_U_RIGHT_SHIFT: // unsigned right shift case SMP_ROTATE_LEFT: case SMP_ROTATE_LEFT_CARRY: // rotate left through carry case SMP_ROTATE_RIGHT: case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry case SMP_U_MULTIPLY: case SMP_U_DIVIDE: case SMP_U_REMAINDER: case SMP_ZERO_EXTEND: case SMP_BITWISE_NOT: // unary operator case SMP_BITWISE_XOR: case SMP_BITWISE_AND_NOT: case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_U_COMPARE: // unsigned compare (AND-based) case SMP_GENERAL_COMPARE: case SMP_S_LEFT_SHIFT: // signed left shift case SMP_S_RIGHT_SHIFT: // signed right shift case SMP_S_MULTIPLY: case SMP_S_DIVIDE: case SMP_SIGN_EXTEND: case SMP_NEGATE: // unary negation case SMP_LESS_THAN: // boolean test operators case SMP_GREATER_THAN: case SMP_LESS_EQUAL: case SMP_GREATER_EQUAL: case SMP_BELOW: case SMP_BELOW_EQUAL: case SMP_ABOVE: case SMP_ABOVE_EQUAL: case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length case SMP_UNARY_POINTER_OPERATION: // Inherently unsigned and signed operators force the signedness // of their results, rather than propagating the signedness of // their operands. break; case SMP_DECREMENT: case SMP_INCREMENT: case SMP_ADD: case SMP_ADD_CARRY: // add with carry case SMP_SUBTRACT: case SMP_SUBTRACT_BORROW: // subtract with borrow case SMP_ASSIGN: case SMP_BITWISE_AND: case SMP_BITWISE_OR: case SMP_EQUAL: case SMP_NOT_EQUAL: case SMP_LOGICAL_AND: case SMP_LOGICAL_OR: case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result transfer = true; break; case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_FLOATING_ADD: case SMP_FLOATING_SUBTRACT: case SMP_FLOATING_MULTIPLY: // floating-point multiplication of any precision; all NUMERIC case SMP_FLOATING_DIVIDE: // floating-point division of any precision; all NUMERIC case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's case SMP_COMPARE_NE_AND_SET: // Compare for inequality and set fields to all 1's or all 0's case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision case SMP_AVERAGE_U: // Average of unsigned operands case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate) case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements case SMP_MAX_S: // dest := signed_max(dest, src) case SMP_MAX_U: // dest := unsigned_max(dest, src) case SMP_MIN_S: // dest := signed_min(dest, src) case SMP_MIN_U: // dest := unsigned_min(dest, src) case SMP_ABSOLUTE_VALUE: // take absolute value case SMP_CONVERT_INT_TO_FP: // convert integer to floating point case SMP_CONVERT_FP_TO_INT: // convert floating point to integer case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC transfer = true; break; default: SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr())); break; } // end switch on operator return transfer; } // end of SMPInstr::DoesOperatorTransferSign() // Transfer function: Does operator propagate width of its operands to its result? bool SMPInstr::DoesOperatorTransferWidth(SMPoperator CurrOp) { bool transfer = true; if ((CurrOp == SMP_CONVERT_INT_TO_FP) || (CurrOp == SMP_CONVERT_FP_TO_INT)) { transfer = false; } return transfer; } // end of SMPInstr::DoesOperatorTransferWidth() // Adjust signedness based on SSA def-use info. void SMPInstr::MDFixupSignedness(void) { set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef(); set<DefOrUse, LessDefUse>::iterator UseIter; unsigned short SignMask; STARSOpndTypePtr DefOp = nullptr; int DefSSANum = -1; int IdiomCode; bool UnderflowOpcode = this->MDIsUnderflowingOpcode(); bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if (DefIter != this->GetLastDef()) { DefOp = DefIter->GetOp(); DefSSANum = DefIter->GetSSANum(); } int TypeGroup = SMPTypeCategory[this->GetIDAOpcode()]; if (this->IsNop()) TypeGroup = 1; // no-op idioms need their category reset if (5 == TypeGroup) { this->SetAddSubSourceType(); } if (this->MDIsSignedLoad(SignMask)) { assert(nullptr != DefOp); // Compilers can generate zero-extensions just to clear unused bits in a register. // We can wrongly infer UNSIGNED for the DEF as a result. The problem can be detected // by seeing whether the zeroed-out bits are ever used. If all USEs of this register DEF // only use the same number of bits as the source operand for the move, then the // zero-extension bits do not mean anything, so we reset the signedness to unknown. // This will hopefully not conflict with other sources of an UNSIGNED inference that // could also have occurred (e.g. a MEDS type of POINTER is unlikely to occur with a // zero-extended operand). if (SignMask == FG_MASK_UNSIGNED) { STARSOpndTypePtr MoveSource = this->GetMoveSource(); std::size_t SourceBitWidth = 8 * MoveSource->GetByteWidth(); assert(DefIter != this->GetLastDef()); if (!(IsMemOperand(DefOp) || MDIsFlagsReg(DefOp))) { int DefHashValue = HashGlobalNameAndSSA(DefOp, DefSSANum); struct FineGrainedInfo DefUseFGInfo; bool LocalName = this->BasicBlock->IsLocalName(DefOp); if (LocalName) { DefUseFGInfo = this->BasicBlock->GetUseFGInfo(DefHashValue); } else { DefUseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(DefHashValue); } std::size_t DefUseMaxBitWidth = LargestBitWidthFromMask(DefUseFGInfo.SizeInfo); if ((DefUseMaxBitWidth <= SourceBitWidth) && (0 != DefUseMaxBitWidth)) { // We never use more bits than the original source had before it was zero-extended. // We exclude the bitwidth==0 special case that signals that it was only used in // a zero-extension or sign-extension move. if (LocalName) { this->BasicBlock->ClearDefSignedness(DefHashValue); } else { this->BasicBlock->GetFunc()->ClearDefSignedness(DefHashValue); } } } } } // Second case: Subtraction of two values, each of which is just a condition code. // This can happen in optimized code that tests for which of two condition codes // has been set, e.g.: // [arithmetic operation or comparison] // seta al ; if "above" flag then al := 1 else al := 0 // setb bl ; if "below" flag then bl := 1 else bl := 0 // mov ecx,eax ; make copy of eax (including al) into ecx // sub al,bl ; al := al - bl // The resulting value in al will be 1 if the above flag was set, -1 if below, 0 if neither. // We see the seta/setb as implying unsigned values, which is true, but if al becomes -1 // we do not want to consider this to be an underflow. // The same logic applies to overflow opcodes: lea edx,[eax+eax-1] is hard to classify as // potential underflow or overflow. If eax comes from a condition code (seta eax), the values // will be small and no overflow check is needed. int UseSSANum; bool BenignUnderflow = false; if (UnderflowOpcode && MDIsDataFlowOpnd(DefOp, UseFP)) { UseIter = this->FindUse(DefOp); // DEF is also USE in subtraction assert(UseIter != this->GetLastUse()); UseSSANum = UseIter->GetSSANum(); if (this->IsOpSourceConditionCode(DefOp, UseSSANum)) { // If we had a decrement opcode, we are done, and underflow is benign. if (this->IsDecrementRTL()) { BenignUnderflow = true; } else { // For subtraction, need to see if BOTH operands came from condition codes (flags). STARSOpndTypePtr UseOp = CloneIfSubwordReg(this->GetUseOnlyAddSubOp()); if (MDIsDataFlowOpnd(UseOp, UseFP)) { CanonicalizeOpnd(UseOp); UseIter = this->FindUse(UseOp); assert(UseIter != this->GetLastUse()); UseSSANum = UseIter->GetSSANum(); BenignUnderflow = this->IsOpSourceConditionCode(UseOp, UseSSANum); } } } if (BenignUnderflow) { // We detected a subtraction or decrement that is permitted to produce a negative // result. This means that the DEF is really SIGNED. We don't want to emit // any underflow checks on this instruction, and we also want to propagate SIGNED // as the type of DEF. this->SetSuppressNumericAnnotation(); SignMask = FG_MASK_SIGNED; struct FineGrainedInfo NewFG; NewFG.SignMiscInfo = SignMask; NewFG.SizeInfo = 0; // Note that old FG info should be null at this point in FG inference, // so we only have to pass in the SIGNED bits. bool MapsChanged = this->UpdateDefOpFGInfo(DefOp, NewFG); } } // end if Underflow on register if (this->MDIsDefiniteBenignUnderflowOpcode(IdiomCode) || this->MDIsSignBitFill()) { // We have a pattern that changes sign, e.g. sbb edx,edx puts // 0 or -1 in edx; likewise for sar edx,31. This needs no annotation. this->SetSuppressNumericAnnotation(); // Furthermore, if we find add edx,positive_immediate_value // in the SSA chain for this instruction, then we don't want // to get false positives from the addition, which often changes // the temporarily SIGNED value back to its original UNSIGNED: // sbb edx,edx ; if edx is UNSIGNED, false positive when we produce -1. // add edx,2 ; another false positive when we convert (0 or -1) to (1 or 2). this->GetBlock()->SuppressAnnotOnSignChangingAddition(DefOp, DefSSANum, this->GetAddr()); } return; } // end of SMPInstr::MDFixupSignedness() // Initial inferences (if any) about FG info of operand based solely on the RTL operator type above it in RTL. bool SMPInstr::InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG) { bool changed = false; switch (CurrOp) { case SMP_NULL_OPERATOR: break; case SMP_CALL: // CALL instruction InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; // target address is unsigned 32-bit InitFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_CODEPOINTER); changed = true; break; case SMP_INPUT: // input from port case SMP_OUTPUT: // output to port case SMP_ADDRESS_OF: // take effective address case SMP_U_COMPARE: // unsigned compare (AND-based) case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_GENERAL_COMPARE: // NOTE: The AND-based and subtraction-based comparisons are used // on lots of operands of all types, and the conditional jump that // follows determines signedness, not the operator. break; case SMP_U_LEFT_SHIFT: // unsigned left shift #if STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR if (!this->MDIsLoadEffectiveAddressInstr()) { // The left shift in the RTL for lea edx,[ebx+eax*4] // does not imply that EAX is UNSIGNED. For other // unsigned left shift RTLs, UNSIGNED is fine. InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; changed = true; } break; #endif case SMP_U_RIGHT_SHIFT: // unsigned right shift case SMP_ROTATE_LEFT: case SMP_ROTATE_LEFT_CARRY: // rotate left through carry case SMP_ROTATE_RIGHT: case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry case SMP_U_MULTIPLY: case SMP_U_DIVIDE: case SMP_U_REMAINDER: case SMP_ZERO_EXTEND: case SMP_BITWISE_NOT: // unary operator case SMP_BITWISE_XOR: case SMP_BITWISE_AND_NOT: case SMP_BELOW: case SMP_BELOW_EQUAL: case SMP_ABOVE: case SMP_ABOVE_EQUAL: case SMP_UNARY_POINTER_OPERATION: InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; changed = true; break; case SMP_S_LEFT_SHIFT: // signed left shift case SMP_S_RIGHT_SHIFT: // signed right shift case SMP_S_MULTIPLY: case SMP_S_DIVIDE: case SMP_SIGN_EXTEND: case SMP_NEGATE: // unary negation case SMP_LESS_THAN: // boolean test operators case SMP_GREATER_THAN: case SMP_LESS_EQUAL: case SMP_GREATER_EQUAL: // Special case: If signed multiply operator, it might sometimes // be used for unsigned operands when upper bits of the result // are discarded, because there is no difference in the result bits // between unsigned and signed multiplication when only the lower // N bits are retained and the upper N bits are discarded. if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) { break; } InitFG.SignMiscInfo |= FG_MASK_SIGNED; changed = true; break; case SMP_DECREMENT: case SMP_INCREMENT: case SMP_ADD: case SMP_ADD_CARRY: // add with carry case SMP_SUBTRACT: case SMP_SUBTRACT_BORROW: // subtract with borrow case SMP_ASSIGN: case SMP_BITWISE_AND: case SMP_BITWISE_OR: case SMP_EQUAL: case SMP_NOT_EQUAL: case SMP_LOGICAL_AND: case SMP_LOGICAL_OR: case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask case SMP_CREATE_MASK: // Create AND-mask from operand and byte/word/dword position # in immediate case SMP_SIGNAL: // signal or raise exception break; case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC case SMP_FLOATING_ADD: case SMP_FLOATING_SUBTRACT: case SMP_FLOATING_MULTIPLY: // floating-point multiplication of any precision; all NUMERIC case SMP_FLOATING_DIVIDE: // floating-point division of any precision; all NUMERIC case SMP_FLOATING_NEGATE_AND_ADD: // floating negate left operand and add to right, any precision; NUMERIC InitFG.SignMiscInfo |= FG_MASK_SIGNED; InitFG.SizeInfo |= FG_MASK_FLOAT_MMX; changed = true; break; case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's case SMP_COMPARE_NE_AND_SET: // Compare for inequality and set fields to all 1's or all 0's case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision case SMP_MAX_S: // dest := signed_max(dest, src) case SMP_MIN_S: // dest := signed_min(dest, src) case SMP_ABSOLUTE_VALUE: // take absolute value InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128); // Fall through here to next cases case SMP_CONVERT_INT_TO_FP: // convert integer to floating point case SMP_CONVERT_FP_TO_INT: // convert floating point to integer InitFG.SignMiscInfo |= FG_MASK_SIGNED; changed = true; break; case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision case SMP_AVERAGE_U: // Average of unsigned operands case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate) case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements case SMP_MAX_U: // dest := unsigned_max(dest, src) case SMP_MIN_U: // dest := unsigned_min(dest, src) case SMP_ENCRYPTION_OPERATION: // encryption or decryption bit manipulation operation case SMP_EXTRACT_ZERO_EXTEND: // Extract sub-reg and zero-extend to reg length InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128); changed = true; break; case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC InitFG.SignMiscInfo |= FG_MASK_SIGNED; InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128); changed = true; break; default: SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr())); break; } // end switch on operator return changed; } // end of SMPInstr::InitFGInfoFromOperator() // Helper to take USE operand, find its SSANum, and return its UseHashValue. int SMPInstr::GetUseOpHashAndSSA(const STARSOpndTypePtr &UseOp, int &SSANum) { STARSOpndTypePtr SearchOp = CloneIfSubwordReg(UseOp); CanonicalizeOpnd(SearchOp); set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp); assert(UseIter != this->GetLastUse()); SSANum = UseIter->GetSSANum(); int UseHashValue = HashGlobalNameAndSSA(SearchOp, SSANum); return UseHashValue; } // end of SMPInstr::GetUseOpHashAndSSA() // Helper to take DEF operand, find its SSANum, and return its DefHashValue. int SMPInstr::GetDefOpHashAndSSA(const STARSOpndTypePtr &DefOp, int &SSANum) { STARSOpndTypePtr SearchOp = CloneIfSubwordReg(DefOp); CanonicalizeOpnd(SearchOp); set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp); assert(DefIter != this->GetLastDef()); SSANum = DefIter->GetSSANum(); int DefHashValue = HashGlobalNameAndSSA(SearchOp, SSANum); return DefHashValue; } // end of SMPInstr::GetDefOpHashAndSSA() // helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps bool SMPInstr::UpdateDefOpFGInfo(const STARSOpndTypePtr &DefOp, struct FineGrainedInfo NewFG) { bool MapsChanged = false; // Changes to maps of name/SSA to FG info? int SSANum; int DefHashValue; bool LocalName; struct FineGrainedInfo OldFG, UnionFG; if (DefOp->IsRegOp()) { // If operator is inherently signed, then we will have // a sign bit set in NewFG from InitFGInfoFromOperator(). DefHashValue = this->GetDefOpHashAndSSA(DefOp, SSANum); LocalName = this->BasicBlock->IsLocalName(DefOp); if (LocalName) { // Get old FG info from block level. OldFG = this->BasicBlock->GetDefFGInfo(DefHashValue); } else { // global name // Get old FG info from function level. OldFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue); } // Get rid of stack access bits being passed around in InferOperatorFGInfo() // for register operands in RTLs. NewFG.SignMiscInfo &= FG_MASK_SIGNEDNESS_BITS; UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo; UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo; if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) { // The signs they are a-changin' (or the sizes). MapsChanged = true; if (LocalName) this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG); else this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG); } } else if (MDIsDirectStackAccessOpnd(DefOp, this->GetBlock()->GetFunc()->UsesFramePointer())) { STARS_ea_t InstAddr = this->GetAddr(); MapsChanged = this->GetBlock()->GetFunc()->MDUpdateFGStackLocInfo(InstAddr, DefOp, NewFG); } return MapsChanged; } // end of SMPInstr::UpdateDefOpFGInfo() // helper for InferOperatorFGInfo() to update USE maps, return true if changed maps bool SMPInstr::UpdateUseOpFGInfo(const STARSOpndTypePtr &UseOp, struct FineGrainedInfo NewFG) { bool MapsChanged = false; // Changes to maps of name/SSA to FG info? int SSANum; int UseHashValue; bool LocalName; struct FineGrainedInfo OldFG, UnionFG; if (UseOp->IsRegOp()) { // If operator is inherently signed, then we will have // a sign bit set in NewFG from InitFGInfoFromOperator(). UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum); LocalName = this->BasicBlock->IsLocalName(UseOp); if (LocalName) { // Get old FG info from block level. OldFG = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // global name // Get old FG info from function level. OldFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } // Get rid of stack access bits being passed around in InferOperatorFGInfo() // for register operands in RTLs. NewFG.SignMiscInfo &= FG_MASK_SIGNEDNESS_BITS; UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo; UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo; if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) { // The signs they are a-changin'. MapsChanged = true; if (LocalName) this->BasicBlock->UpdateUseFGInfo(UseHashValue, UnionFG); else this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG); } } else if (MDIsDirectStackAccessOpnd(UseOp, this->GetBlock()->GetFunc()->UsesFramePointer())) { STARS_ea_t InstAddr = this->GetAddr(); MapsChanged = this->GetBlock()->GetFunc()->MDUpdateFGStackLocInfo(InstAddr, UseOp, NewFG); } return MapsChanged; } // end of SMPInstr::UpdateUseOpFGInfo() // pass-through to STARS_Instruction_t::MakeRegOpnd() STARSOpndTypePtr SMPInstr::MakeRegOpnd(STARS_regnum_t RegNum) const { return this->STARSInstPtr->MakeRegOpnd(RegNum); } // pass-through to STARS_Instruction_t::MakeFloatingPointRegOpnd() STARSOpndTypePtr SMPInstr::MakeFloatingPointRegOpnd(STARS_regnum_t RegNum) const { return this->STARSInstPtr->MakeFloatingPointRegOpnd(RegNum); } // pass-through to STARS_Instruction_t::MakeVoidOpnd() STARSOpndTypePtr SMPInstr::MakeVoidOpnd(void) const { return this->STARSInstPtr->MakeVoidOpnd(); } // pass-through to STARS_Instruction_t::MakeImmediateOpnd() STARSOpndTypePtr SMPInstr::MakeImmediateOpnd(STARS_uval_t value) const { return this->STARSInstPtr->MakeImmediateOpnd(value); } // Helper to fetch DEF signedness info for UseOp that has none. unsigned short SMPInstr::GetDefSignInfoFromUseOp(const STARSOpndTypePtr &UseOp) { int SSANum, UseHashValue; bool LocalName; UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum); LocalName = this->BasicBlock->IsLocalName(UseOp); if (LocalName) { // Get old sign info from block level. return this->BasicBlock->GetDefSignMiscInfo(UseHashValue); } else { // global name // Get old sign info from function level. return this->BasicBlock->GetFunc()->GetDefSignMiscInfo(UseHashValue); } } // end of SMPInstr::GetDefSignInfoFromUseOp() // infer FG info, + width on FirstIter; pass out FG info for op subtree, return true if change made to any FG info map. bool SMPInstr::InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter, struct FineGrainedInfo &OpFG) { bool MapsChanged = false; // Changes to maps of name/SSA to FG info? bool NewChange = false; // Bit changes from InitFGInfoFromOperator() ? SMPoperator CurrOp = CurrRT->GetOperator(); struct FineGrainedInfo LeftFG; struct FineGrainedInfo RightFG; STARSOpndTypePtr LeftOp = nullptr, RightOp = nullptr; unsigned short WidthMask, SignMask; bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp); bool CurrOpTransfersWidth = this->DoesOperatorTransferWidth(CurrOp); bool SpecialTransferCase = false; bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); bool success; int DefHashValue, UseHashValue, SSANum; #if SMP_AGGRESSIVE_SIGN_TRANSFER // Special case: If signed multiply operator, it might sometimes // be used for unsigned operands when upper bits of the result // are discarded, because there is no difference in the result bits // between unsigned and signed multiplication when only the lower // N bits are retained and the upper N bits are discarded. // As a result, InitFGInfoFromOperator() did not set FG_MASK_SIGNED // for the result of the multiplication. If we now detect that two // unsigned operands are being multiplied together using the "signed" // multiply operator, we need to transfer UNSIGNED to the result. if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) { SpecialTransferCase = true; } #endif // Recurse to the right first, so we can do a depth-first accumulation of FG info. RightFG.SignMiscInfo = 0; RightFG.SizeInfo = 0; if (CurrRT->HasRightSubTree()) { if (FirstIter) { // Get width as well as signedness NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG); } // end if (FirstIter) MapsChanged |= this->InferOperatorFGInfo(CurrRT->GetRightTree(), FirstIter, RightFG); } else { RightOp = CurrRT->GetRightOperand(); if (RightOp->IsImmedOp()) { // If immediate operand is a data address or code address, we can infer that it is unsigned. STARS_uval_t ImmVal = RightOp->GetImmedValue(); if (IsImmedGlobalAddress((STARS_ea_t) ImmVal)) { // NOTE: Can be false. !!!!****!!!! // Data address (type GLOBALPTR) RightFG.SignMiscInfo |= FG_MASK_UNSIGNED; } else if (this->IsInterruptCall() || global_STARS_program->IsImmedCodeAddress((STARS_ea_t) ImmVal)) { // Code address (type CODEPTR) RightFG.SignMiscInfo |= FG_MASK_UNSIGNED; } } else if ((RightOp->IsRegOp()) && !RightOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) { if (FirstIter) { // Get width as well as signedness NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG); WidthMask = ComputeOperandBitWidthMask(RightOp, 0); RightFG.SizeInfo |= WidthMask; } // end if (FirstIter) #if SMP_AGGRESSIVE_SIGN_TRANSFER else { // On all iterations other than 1st, see if USE has FG info. UseHashValue = this->GetUseOpHashAndSSA(RightOp, SSANum); if (this->BasicBlock->IsLocalName(RightOp)) { // Get FG info from block. RightFG = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // Get FG info from function level. RightFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } } #endif // Propagate signedness on all iterations. // If operator is inherently signed, then we will have // a sign bit set in RightFG from InitFGInfoFromOperator(). if ((RightFG.SignMiscInfo == 0) && (CurrOpTransfersSign || SpecialTransferCase)) { // We have a USE with no sign info. See if we // can get sign info from the DEF of this USE so we can // transfer it up the RTL tree. RightFG.SignMiscInfo = (FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(RightOp))); } if ((RightFG.SignMiscInfo != 0) || (RightFG.SizeInfo != 0)) MapsChanged |= this->UpdateUseOpFGInfo(RightOp, RightFG); } // end if (RightOP is reg) else if (MDIsDirectStackAccessOpnd(RightOp, UseFP)) { // We used to assume that all FG info transfers from stack locations to // the target registers of stack loads happened in SMPInstr::MDSetWidthSignInfo(), // in an early pass that needed no iteration. The FG info was loaded from the // StackFGInfo that was computed in SMPFunction::FindOutgoingArgsSize() based solely // on whether the load was sign-extended or zero-extended. Of course, many stack // locations have neither kind of signed/unsigned load. So, if we see a store to // a stack location with no signedness, we transfer the signedness of the RightFG // to the stack location FGInfo in the code below that processes the LeftOp. // As a result, we now have a need to examine regular loads from the stack to // see if there is signedness info for the stack location. success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), RightOp, RightFG); if (success) { SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); RightFG.SizeInfo = 0; // only want to transfer signedness } } } // end if (right subtree) else right operand LeftFG.SignMiscInfo = 0; LeftFG.SizeInfo = 0; LeftOp = CurrRT->GetLeftOperand(); bool OpIsDEF = (SMP_ASSIGN == CurrOp); // Skip control-flow assignments to the instruction pointer register. if ((LeftOp->IsRegOp()) && !LeftOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) { if (FirstIter) { // Get width as well as signedness NewChange = this->InitFGInfoFromOperator(CurrOp, LeftFG); // Special case: For sign-extended and zero-extended loads, // we don't know whether the DEF will always be USEd as // the smaller or larger size. For example, we could // zero-extend a 16-bit stack location into a 32-bit register // just because the compiler always loads unsigned shorts // that way, but we might never use it as a 32-bit value. // So there is no truncation if we store only 16 bits later. // By setting the target of an extended load to zero width, // we signal that we want the maximum USE width to determine // whether the store is truncated (see EmitIntegerErrorAnnotations). WidthMask = ComputeOperandBitWidthMask(LeftOp, 0); if (OpIsDEF) { if (this->MDIsSignedLoad(SignMask)) { WidthMask = 0; } // DEF inherits sign from right hand side. LeftFG.SignMiscInfo |= RightFG.SignMiscInfo; } else if ((LeftFG.SignMiscInfo == 0) && (CurrOpTransfersSign || SpecialTransferCase)) { // We have a USE, not a DEF, with no sign info. See if we // can get sign info from the DEF of this USE so we can // transfer it up the RTL tree. LeftFG.SignMiscInfo = (FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(LeftOp))); } LeftFG.SizeInfo |= WidthMask; if ((LeftFG.SignMiscInfo != 0) || (LeftFG.SizeInfo != 0)) { // Either NewChanged or CurrOpTransfersSign or SpecialTransferCase is true or we set WidthMask above. // See if we would change the FG map entry. if (OpIsDEF) { // Need DEF map info MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG); } else { // need USE map info MapsChanged |= this->UpdateUseOpFGInfo(LeftOp, LeftFG); } } // end if non-zero LeftFG info } // end if (FirstIter) #if SMP_AGGRESSIVE_SIGN_TRANSFER else { // On all iterations other than 1st, see if LeftOp has FG info. if (!OpIsDEF) { // LeftOp is a USE UseHashValue = this->GetUseOpHashAndSSA(LeftOp, SSANum); if (this->BasicBlock->IsLocalName(LeftOp)) { // Get FG info from block. LeftFG = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // Get FG info from function level. LeftFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } } else { // LeftOp is a DEF DefHashValue = this->GetDefOpHashAndSSA(LeftOp, SSANum); if (this->BasicBlock->IsLocalName(LeftOp)) { // Get FG info from block. LeftFG = this->BasicBlock->GetDefFGInfo(DefHashValue); } else { // Get FG info from function level. LeftFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue); } // See if RightFG has sign info to transfer to LeftFG. SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); unsigned short LeftSignMask = (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); bool UpdateLeftSignMask = ((SignMask != 0) && (SignMask != LeftSignMask)); #if 1 if (OpIsDEF && (0 != LeftSignMask)) { // We have a signedness value for the DEF operand. These values are // highly reliable, e.g. MEDS type inference detects that the DEF is // a POINTER and therefore it must be UNSIGNED, or the opcode always // produces a SIGNED result, etc. We do not want to produce a mixed // signedness DEF in these cases, regardless of what happens when // we examine operands in the RTLs, because compiler code generation // can produce screwy results that are less reliable than our early // determinations of DEF signedness (e.g. compilers can zero-extend // bytes even though they are signed, and hand-code assembly authors // can sign-extend bytes that are unsigned and get away with it // because the values are always very small and have a sign bit of zero.) UpdateLeftSignMask = false; } #endif if (UpdateLeftSignMask) { // SignMask from RightFG has bits that will change LeftFG.SignMiscInfo. LeftFG.SignMiscInfo |= SignMask; MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG); } } } #endif } // end of register case for LeftOp else if (OpIsDEF && MDIsDirectStackAccessOpnd(LeftOp, UseFP) && (!this->BasicBlock->GetFunc()->IsInOutgoingArgsRegion(LeftOp))) { // For stores into the stack, if the operand being stored has signedness // and the stack location has no signedness, then we have a case where // none of the loads from the stack location were signed, so it is // safe to infer signedness of the stack location based on what is being // stored into it, as no store signedness will conflict with load signedness. success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), LeftOp, LeftFG); assert(success); if (0 == (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) { // No previous signedness info for the stack location. // Get signedness info from RightFG. SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); if ((0 != SignMask) && (FG_MASK_INCONSISTENT_SIGN != SignMask)) { // Operand being stored has signedness. // Transfer the signedness to the stack location. struct FineGrainedInfo TempFG; TempFG.SignMiscInfo = SignMask; TempFG.SizeInfo = 0; // just update signedness success = this->BasicBlock->GetFunc()->MDUpdateFGStackLocInfo(this->GetAddr(), LeftOp, TempFG); MapsChanged |= success; } } } // Prepare to return FG info for operator. First, OR the left and right FG infos. if (NewChange || MapsChanged || CurrOpTransfersSign || SpecialTransferCase) { OpFG.SignMiscInfo |= LeftFG.SignMiscInfo; OpFG.SignMiscInfo |= RightFG.SignMiscInfo; if (CurrOpTransfersWidth) { OpFG.SizeInfo |= LeftFG.SizeInfo; OpFG.SizeInfo |= RightFG.SizeInfo; } } // An operator could override the width or signedness info of its operands. if (CurrOp == SMP_ADDRESS_OF) { // Result is 32-bit data pointer. OpFG.SizeInfo &= (~FG_MASK_BITWIDTH_FIELDS); // clear all width bits OpFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_DATAPOINTER); OpFG.SignMiscInfo &= (~FG_MASK_SIGNED); OpFG.SignMiscInfo |= FG_MASK_UNSIGNED; } return MapsChanged; } // end of SMPInstr::InferOperatorFGInfo() // infer width on first pass, signedness on all passes bool SMPInstr::InferFGInfo(unsigned short IterCount) { bool MapsChanged = false; // Changes to maps of name/SSA to FG info? struct FineGrainedInfo OpFG; SMPitype DFType = this->GetDataFlowType(); assert(0 < IterCount); // start IterCount at 1, not 0. if (DFType != DEFAULT) { // We have a control flow instruction, e.g. call, return, branch, jump // No data operands unless these instructions are indirect through a register, // and the indirect operand is a memory operand in that case, e.g. [eax]. return MapsChanged; } if (1 == IterCount) { // Fix signedness info now that complete SSA chains have been analyzed. this->MDFixupSignedness(); } for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) { SMPRegTransfer *CurrRT = this->RTL.GetRT(index); if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer continue; OpFG.SignMiscInfo = 0; OpFG.SizeInfo = 0; MapsChanged |= this->InferOperatorFGInfo(CurrRT, (1 == IterCount), OpFG); if (SMP_CALL == CurrRT->GetOperator()) // no LeftOp DEF continue; } // end for all RTs in the RTL return MapsChanged; } // end of SMPInstr::InferFGInfo() // Get the meet of the metadata types of all non-flags DEFs. SMPMetadataType SMPInstr::GetDefMetadataType(void) { SMPMetadataType MeetType = DEF_METADATA_UNANALYZED; set<DefOrUse, LessDefUse>::iterator CurrDef; for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) { SMPMetadataType CurrType; STARSOpndTypePtr DefOp = CurrDef->GetOp(); if (DefOp->MatchesReg(X86_FLAGS_REG)) continue; // flags are always unused metadata; irrelevant CurrType = CurrDef->GetMetadataStatus(); if (MeetType == CurrType) continue; // no meet operation to perform // Any time we find USED metadata, that overrides all other types. if (0 != (CurrType & DEF_METADATA_USED)) return CurrType; bool MeetUsed = ((MeetType >= DEF_METADATA_USED) && (MeetType < DEF_METADATA_REDUNDANT)); bool CurrUsed = ((CurrType >= DEF_METADATA_USED) && (CurrType < DEF_METADATA_REDUNDANT)); if (MeetType == DEF_METADATA_UNANALYZED) MeetType = CurrType; else if (MeetUsed && CurrUsed) { // Two different variations of USED. Union the explanations. int TempInt = (int) MeetType; TempInt |= (int) CurrType; MeetType = (SMPMetadataType) CurrType; } else if (MeetType < DEF_METADATA_REDUNDANT) { // Conflict between types of different DEFs. It could be that // a multiply or divide instruction DEFs EAX and EDX, and one // of them is used in a store and the other is unused. In that // case, the final MeetType is USED and we can return. Or, if // one type is UNUSED and the other is REDUNDANT, we can set // the final type to the REDUNDANT type and return. The USED case // is handled above, so we must have the UNUSED vs. REDUNDANT case. assert(CurrType >= DEF_METADATA_REDUNDANT); MeetType = CurrType; } else { // MeetType REDUNDANT, not equal to CurrType. if (CurrType >= DEF_METADATA_REDUNDANT) { // One type is profile derived, both are REDUNDANT. MeetType = DEF_METADATA_PROF_REDUNDANT; } else { assert(DEF_METADATA_UNUSED == CurrType); // leave MeetType as REDUNDANT } } } // end for all DEFs return MeetType; } // end of SMPInstr::GetDefMetadataType() // last inst in optimized top-testing loop will fall through to relocated loop header block bool SMPInstr::IsLastInstInOptimizedLoop(bool &DoubleTailBlock) { bool SpecialLastInst = false; if ((this->GetBlock()->GetLastAddr() == this->GetAddr()) && this->GetBlock()->IsLoopTailBlock()) { int LoopHeaderBlockNum = this->GetBlock()->GetLoopHeaderNumber(); assert(0 <= LoopHeaderBlockNum); SMPBasicBlock *HeaderBlock = this->GetBlock()->GetFunc()->GetBlockByNum((size_t) LoopHeaderBlockNum); SpecialLastInst = HeaderBlock->IsOptimizedTopLoopTest(); if (SpecialLastInst) DoubleTailBlock = this->GetBlock()->IsDoubleLoopTailBlock(); } return SpecialLastInst; } // end of SMPInstr::IsLastInstInOptimizedLoop() // Are numeric values from a system call trusted input, so that all numeric errors // derived from the returned values should be treated as benign? bool SMPInstr::IsNumericTrustedSystemCall(void) { bool TrustedCall = false; if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) { // We have a resolved call target address, either via direct or indirect call. string FuncName = this->GetTrimmedCalledFunctionName(); TrustedCall = global_STARS_program->IsNumericSafeSystemCall(FuncName); } return TrustedCall; } // end of SMPInstr::IsNumericTrustedSystemCall() // Is register RegNum dead coming into this function, based on the DeadRegsBitmap? bool SMPInstr::IsIncomingRegDead(int RegNum) { bool RegDead = true; if ((0 <= RegNum) && (RegNum < ((int) this->DeadRegsBitmap.size()))) { RegDead = this->DeadRegsBitmap[(std::size_t) RegNum]; } return RegDead; } // end of SMPInstr::IsIncomingRegDead() // Handle x86 opcode SIB byte annotations. void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, const STARSOpndTypePtr &Opnd, STARS_ea_t offset, bool UseFP) { int BaseReg; int IndexReg; STARS_ea_t displacement; uint16_t ScaleFactor; char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); int SignedOffset = (int) offset; MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement); if (BaseReg == MD_STACK_POINTER_REG) { // ESP cannot be IndexReg // ESP-relative constant offset SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDESP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm); } else if (UseFP && ((IndexReg == MD_FRAME_POINTER_REG) || (BaseReg == MD_FRAME_POINTER_REG))) { // EBP-relative constant offset SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDEBP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm); } return; } // end of MDAnnotateSIBStackConstants // Emit annotations for constants used as ptr offsets from EBP or // ESP into the stack frame. Only pay attention to EBP-relative // offsets if EBP is being used as a frame pointer (UseFP == true). void SMPInstr::AnnotateStackConstants(bool UseFP, FILE *AnnotFile) { STARS_ea_t offset; int BaseReg; int IndexReg; uint16_t ScaleFactor; char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); int SignedOffset; #if 0 if (this->GetAddr() == 0x80925f4) { SMP_msg("PROBLEM INSTRUCTION: \n"); this->PrintOperands(); } #endif for (int i = 0; i < STARS_UA_MAXOP; ++i) { STARSOpndTypePtr Opnd = this->STARSInstPtr->GetOpnd(i); if (nullptr == Opnd) // finished processing operands break; if (Opnd->IsMemDisplacementOp() || Opnd->IsMemNoDisplacementOp()) MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset); SignedOffset = (int) offset; if (Opnd->IsMemDisplacementOp()) { if (Opnd->HasSIBByte()) { MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP); } else { // no SIB if (BaseReg == MD_STACK_POINTER_REG) { // ESP-relative constant offset SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDESP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm); } else if (UseFP && (BaseReg == MD_FRAME_POINTER_REG)) { // EBP-relative constant offset SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDEBP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm); } } // end if (Opnd.hasSIB) ... else ... } // end if (Opnd.type == o_displ) else if (Opnd->IsMemNoDisplacementOp()) { offset = 0; // mmStrata thinks [esp] is [esp+0] if (Opnd->HasSIBByte()) { MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP); } else { // Something like [ecx]; is it [esp] or [ebp] ? if (BaseReg == MD_STACK_POINTER_REG) { // ESP-relative constant offset SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDESP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm); } else if (UseFP && (BaseReg == MD_FRAME_POINTER_REG)) { // EBP-relative constant offset SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDEBP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), SignedOffset, disasm); } } // end if (Opnd.hasSIB) ... else ... } // end else if (Opnd.type == o_phrase) } // end for all operands // If we move a stack pointer or frame pointer into another register, we // need to annotate the implicit zero offset, e.g. mov edi,esp == mov edi,esp+0 // and edi is becoming a stack pointer that mmStrata needs to track. if (this->MDIsStackPointerCopy(UseFP)) { // Two possibilities: a move of the stack pointer, or an "lea" // opcode, e.g. lea eax,[esp+8] ==> eax:=esp+8. In the move // instruction (e.g. mov eax,esp), we have the implicit zero // offset from the stack pointer register, but in the lea case, // we might have zero or some other offset (lea eax,[esp] has // the implicit zero). int ESPoffset = 0; if (this->MDIsLoadEffectiveAddressInstr()) { ESPoffset = this->MDGetImmedUse(); } // NOTE: Looks like this next line should be "else" because an lea instruction // looks like it has a memory operand, hence it has already been handled above. // We are getting duplicate annotations for lea instructions. else { if (UseFP && this->GetFirstUse()->GetOp()->MatchesReg(MD_FRAME_POINTER_REG)) { SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDEBP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), ESPoffset, disasm); } else { SMP_fprintf(AnnotFile, "%18llx %6d PTRIMMEDESP STACK %d displ %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), ESPoffset, disasm); } } } return; } // end of SMPInstr::AnnotateStackConstants() // emit all reasons that fast returns are unsafe, or emit that they are safe. void SMPInstr::EmitFastReturnStatus(unsigned short FastReturnStatus) { SMPitype FlowType = this->GetDataFlowType(); char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); char InstrString[12]; if (FlowType == CALL) { SMP_snprintf(InstrString, 10, "CALL"); } else if (FlowType == INDIR_CALL) { SMP_snprintf(InstrString, 10, "INDIRCALL"); } else if (FlowType == RETURN) { SMP_snprintf(InstrString, 10, "RETURN"); } else { SMP_msg("ERROR: EmitFastReturnStatus: Invalid data flow type at %llx \n", (unsigned long long) this->GetAddr()); return; } SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR %s ", (unsigned long long) this->GetAddr(), this->GetSize(), InstrString); if (!global_STARS_program->ShouldSTARSPerformFullAnalysis()) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "NOFASTRETURN REDUCEDANALYSIS"); } else if (FastReturnStatus == SAFE_FAST_RETURN) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "FASTRETURN "); } else { // Iterate through possible reasons and print each reason. SMP_fprintf(global_STARS_program->GetCallReturnFile(), "NOFASTRETURN "); if (UNSAFE_RETURN_ADDRESS & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "RAUNSAFE "); } if (RETURN_ADDRESS_WRITE & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "RAWRITE "); } if (RETURN_ADDRESS_READ & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "RAREAD "); } if (INDIRECTLY_CALLED & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "INDIRECT "); } if (NO_CALLERS & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "NOCALLERS "); } if (TAIL_CALL_TARGET & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "TAILCALLED "); } if (MAKES_TAIL_CALL & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "MAKES_TAIL_CALL "); } if (MULTIPLE_ENTRY_POINTS & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "MULTIENTRY "); } if (UNRESOLVED_INDIR_JUMP & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "INDIRJUMP "); } if (EH_FRAME_ENTRY & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "EXCEPTION_HANDLING "); } if (RAUNSAFE_CALLEES & FastReturnStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "UNSAFE_CALLEES "); } } SMP_fprintf(global_STARS_program->GetCallReturnFile(), "ZZ %s \n", disasm); return; } // end of SMPInstr::EmitFastReturnStatus() // Emit fast return and unsafe return address info into *.STARScallreturn file void SMPInstr::EmitCallReturnStatus(SMPProgram *CurrProg) { SMPitype FlowType = this->GetDataFlowType(); char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); bool ValidFunc = ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc())); if (CALL == FlowType) { STARS_ea_t CalleeAddr = this->GetCallTarget(); SMPFunction *CalleeFunc = NULL; if (ValidFunc) { CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalleeAddr); } else if (NULL != CurrProg) { CalleeFunc = CurrProg->FindFunction(CalleeAddr); } if (nullptr == CalleeFunc) { SMP_msg("ERROR: Cannot find callee function for CALL at %llx \n", (unsigned long long) this->GetAddr()); SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL RAUNSAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); this->EmitFastReturnStatus((unsigned short) NO_CALLERS); } else { FuncType RetAddrStatus = CalleeFunc->GetReturnAddressStatus(); unsigned short FastReturnStatus = CalleeFunc->GetFastReturnStatus(); if (FUNC_SAFE != RetAddrStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL RAUNSAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } else { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL RASAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } this->EmitFastReturnStatus(FastReturnStatus); } } else if (INDIR_CALL == FlowType) { STARS_ea_t CalleeAddr = this->GetCallTarget(); if ((STARS_BADADDR == CalleeAddr) || (!global_STARS_program->ShouldSTARSPerformFullAnalysis())) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR INDIRCALL RAUNSAFE UNKNOWNTARGET %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); unsigned short DummyReturnStatus = INDIRECTLY_CALLED; this->EmitFastReturnStatus(DummyReturnStatus); } else { SMPFunction *CalleeFunc = NULL; if (ValidFunc) { CalleeFunc = this->GetBlock()->GetFunc()->GetProg()->FindFunction(CalleeAddr); } else if (NULL != CurrProg) { CalleeFunc = CurrProg->FindFunction(CalleeAddr); } if (nullptr == CalleeFunc) { SMP_msg("ERROR: Cannot find callee function for CALL at %llx \n", (unsigned long long) this->GetAddr()); SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL RAUNSAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); this->EmitFastReturnStatus((unsigned short) NO_CALLERS); } else { FuncType RetAddrStatus = CalleeFunc->GetReturnAddressStatus(); unsigned short FastReturnStatus = CalleeFunc->GetFastReturnStatus(); if (FUNC_SAFE != RetAddrStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR INDIRCALL RAUNSAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } else { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR INDIRCALL RASAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } this->EmitFastReturnStatus(FastReturnStatus); } } } else if (RETURN == FlowType) { if (this->IsCondTailCall()) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL CONDTAILCALL %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } else if (this->IsTailCall()) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR CALL TAILCALL %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } else if (this->HasReturnOpcode()) { FuncType RetAddrStatus = FUNC_UNSAFE; unsigned short FastReturnStatus = NO_CALLERS; if (ValidFunc) { RetAddrStatus = this->GetBlock()->GetFunc()->GetReturnAddressStatus(); FastReturnStatus = this->GetBlock()->GetFunc()->GetFastReturnStatus(); } if (FUNC_SAFE == RetAddrStatus) { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR RETURN RASAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } else { SMP_fprintf(global_STARS_program->GetCallReturnFile(), "%18llx %6d INSTR RETURN RAUNSAFE %s\n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); } this->EmitFastReturnStatus(FastReturnStatus); } else { SMP_msg("ERROR: Unknown instruction with RETURN data flow type at %llx \n", (unsigned long long) this->GetAddr()); } } return; } // end of SMPInstr::EmitCallReturnStatus() // Emit all annotations for the instruction in the absence of RTL type inference. void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile, SMPProgram *CurrProg) { if (!this->HasGoodRTL()) return; STARS_ea_t addr = this->GetAddr(); SMPitype DataFlowType = this->GetDataFlowType(); int OptType = this->GetOptType(); #if 0 // wait on INDIR_CALL until we have good targets and sound analysis bool CallInst = ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall()); #else bool CallInst = ((CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall()); #endif bool IndirJumpInst = (INDIR_JUMP == DataFlowType); bool IndirJumpAnalyzed = IndirJumpInst && (NULL != this->GetBlock()) && (!this->GetBlock()->GetFunc()->HasUnresolvedIndirectJumps()); bool MemDest = this->HasDestMemoryOperand(); bool MemSrc = this->HasSourceMemoryOperand(); bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(); // assumes 2nd source is Imm or not-numeric?! bool NoWarnFlag = false; // NOWARN annotation emitted? char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); #if SMP_CHILDACCESS_ALL_CODE bool OrphanCode = (NULL == this->BasicBlock); ProfilerInformation *ProfInfo = NULL; if (!OrphanCode) ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo(); #endif global_STARS_program->IncrementOptCount(this->GetOptType()); // keep count for debugging info #if SMP_ANNOTATE_ALL_MEMORY_OPERANDS // Emit informational annotations for memory operands. if (MemSrc) { STARSOpndTypePtr MemSrcOp = this->MDGetMemUseOp(); std::size_t SrcBitWidth = 8 * MemSrcOp->GetByteWidth(); STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemSrcOp, UseFP); // Need to unnormalize stack memory DEFs and USEs before printing annotations. this->MDGetUnnormalizedOp(AnnotDefOp); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSRC %d", (unsigned long long) addr, this->GetSize(), SrcBitWidth); AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit()); SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } if (MemDest) { STARSOpndTypePtr MemDestOp = this->MDGetMemDefOp(); std::size_t DestBitWidth = 8 * MemDestOp->GetByteWidth(); STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemDestOp, UseFP); // Need to unnormalize stack memory DEFs and USEs before printing annotations. this->MDGetUnnormalizedOp(AnnotDefOp); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMDEF %d", (unsigned long long) addr, this->GetSize(), DestBitWidth); AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit()); SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } #endif // If the instruction is a CALL (or INDIR_CALL that has been resolved to // a single target address), then we need to see if the call is to a // function that has been forbidden by a security policy. If so, we // need to output a security alert. // In the near future, we will output SPRI instrumentation to prevent // the system/library call from executing. if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) { // We have a resolved call target address, either via direct or indirect call. string FuncName = this->GetTrimmedCalledFunctionName(); ZST_SysCallType FuncCallType = global_STARS_program->GetCallTypeFromFuncName(FuncName); ZST_Policy FuncCallPolicy = global_STARS_program->GetPolicyFromCallType(FuncCallType); if (ZST_DISALLOW == FuncCallPolicy) { if ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc())) { SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM: Call to %s will be disallowed at %llx in %s\n", FuncName.c_str(), (unsigned long long) this->GetAddr(), this->GetBlock()->GetFunc()->GetFuncName()); } else { SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM: Call to %s will be disallowed at %llx\n", FuncName.c_str(), (unsigned long long) this->GetAddr()); } SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR SECURITYCALL Disallow 1 1 %s \n", (unsigned long long) addr, this->GetSize(), disasm); } } #if SMP_DEBUG_MEM if (MemDest || MemSrc) { SMP_msg("OptType: %d %s", OptType, disasm); this->PrintOperands(); } #endif // Emit appropriate optimization annotations. bool SDTInstrumentation = false; switch (OptType) { case 0: // SDT will have to handle these { #if SMP_DEBUG_TYPE0 SMP_msg("OptType 0: %llx %s\n", (unsigned long long) addr, disasm); #endif // mmStrata wants to suppress warnings on the PUSH // instructions that precede the LocalVarsAllocInstr // (i.e. the PUSHes of callee-saved regs). if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL NoWarn %s \n", (unsigned long long) addr, -3, disasm); NoWarnFlag = true; } else { SDTInstrumentation = true; } break; } case 1: // nothing for SDT to do { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[OptType], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; } case 4: // INC, DEC, etc.: no SDT work unless MemDest { if (MemDest || MemSrc) { SDTInstrumentation = true; break; // treat as category 0 } SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL Always1stSrc %s \n", (unsigned long long) addr, -1, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; } case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work. { if (MemDest || MemSrc) { SDTInstrumentation = true; break; // treat as category 0 } if (SecondSrcOperandImmNum && !this->MDIsFrameAllocInstr() #if SPECIAL_CASE_CARRY_BORROW && (this->GetIDAOpcode() != STARS_NN_adc) && (this->GetIDAOpcode() != STARS_NN_sbb) #endif ) { // treat as category 1 SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[OptType], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } else { SDTInstrumentation = true; } break; } case 6: // Only OS code should include these; problem for SDT { if (MemDest) { SDTInstrumentation = true; break; // treat as category 0 } SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL AlwaysPTR %s \n", (unsigned long long) addr, -OptType, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; } case 8: // Implicitly writes to EDX:EAX, always numeric. { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ZZ %s %s \n", (unsigned long long) addr, -2, OptExplanation[OptType], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); SDTInstrumentation = true; break; } case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0) { if (MemDest) { #if SMP_DEBUG2 // MemDest seems to happen too much. SMP_msg("Floating point MemDest: %s \n", disasm); #endif SDTInstrumentation = true; break; // treat as category 0 } SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[OptType], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; } case 10: // Implicitly writes to EDX:EAX and ECX, always numeric. { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ECX ZZ %s %s \n", (unsigned long long) addr, -2, OptExplanation[OptType], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); SDTInstrumentation = true; break; } default: // 2,3,7: Optimization possibilities depend on operands { #if SMP_DEBUG2 if (OptType == 3) { // MOV instr class if (MemDest) { SMP_msg("MemDest on MOV: %s\n", disasm); } else if (!SecondSrcOperandNum) { SMP_msg("MOV: not 2nd op numeric: %s\n", disasm); this->PrintOperands(); } } #endif SDTInstrumentation = true; if (MemDest) { #if SMP_DEBUG_XOR if (this->GetOptType() == 2) SMP_msg("MemDest on OptType 2: %s\n", disasm); #endif break; // treat as category 0 } if ((this->GetOptType() == 2) || (this->GetOptType() == 7) || SecondSrcOperandImmNum) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s %s %s \n", (unsigned long long) addr, -2, this->DestString(this->GetOptType()), OptExplanation[this->GetOptType()], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } break; } } // end switch (OptType) // always emit stack constant annotations, in case strata is // instrumenting all instructions, or trying to verify speculative annotations. this->AnnotateStackConstants(UseFP, AnnotFile); // If mmStrata is going to have to deal with the // instruction, then we can annotate EBP and ESP // relative constant offsets. If we have emitted // an annotation of type -1, there is no point // in telling mmStrata about these constants. // Likewise, we can tell mmStrata if a MemDest is an // non-directly-accessed child object. if (SDTInstrumentation || NoWarnFlag || CallInst || IndirJumpAnalyzed) { if (this->DeadRegsBitmap.any()) { // Optimize by informing mmStrata of dead registers. It can avoid saving // and restoring dead state. This is particularly important for EFLAGS, // as restoring the flags is a pipeline serializing instruction. this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); } #if SMP_CHILDACCESS_ALL_CODE int ChildOffset, ChildSize; if (MemDest && !OrphanCode && ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr, ChildOffset, ChildSize)) { SMP_fprintf(AnnotFile, "%18llx %6zu INSTR CHILDACCESS %d %d ZZ %s \n", (unsigned long long) addr, this->GetSize(), ChildOffset, ChildSize, disasm); } #endif } if ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || (RETURN == DataFlowType)) { this->EmitCallReturnStatus(CurrProg); } return; } // end of SMPInstr::EmitAnnotations() /** * Emits Safe Returns * Mark the type of the annotation as "-4". Currently the SDT is ignoring this * annotation. */ void SMPInstr::EmitSafeReturn(FILE *AnnotFile) { char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL SafeReturn %s\n", (unsigned long long) this->GetAddr(), -4, disasm); } // Emit all annotations for the instruction using RTL type inference. void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) { STARS_ea_t addr = this->GetAddr(); int TypeGroup = SMPTypeCategory[this->GetIDAOpcode()]; SMPitype DataFlowType = this->GetDataFlowType(); #if 0 // wait on INDIR_CALL until we have good targets and sound analysis bool CallInst = ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall()); #else bool CallInst = ((CALL == DataFlowType) || this->IsTailCall() || this->IsCondTailCall()); #endif bool IndirJumpInst = (INDIR_JUMP == DataFlowType); bool IndirJumpAnalyzed = IndirJumpInst && (!this->GetBlock()->GetFunc()->HasUnresolvedIndirectJumps()); bool NumericDEFs = this->AllDefsNumeric(); // all DEFs are NUMERIC or CODEPTR bool ProfiledDEFs = this->AnyDefsProfiled(); // Some DEFs come from the profiler bool UnusedMetadata = this->AllDefMetadataUnused(); bool MemDest = this->HasDestMemoryOperand(); bool MemSrc = this->HasSourceMemoryOperand(); bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(); // assumes 2nd source is imm or not-numeric?? bool NoWarnFlag = false; // NOWARN annotation emitted? bool CarryBorrow = ((this->GetIDAOpcode() == STARS_NN_adc) || (this->GetIDAOpcode() == STARS_NN_sbb)); // Do we have the special case in which a non-NUMERIC comes into // an add with carry or subtract with borrow and the result // has been inferred to be NUMERIC? bool TypeChange = CarryBorrow && (!IsNumeric(this->AddSubDefUseType)) && NumericDEFs; SMPMetadataType DefMetadataType = this->GetDefMetadataType(); ProfilerInformation *ProfInfo; ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo(); char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); global_STARS_program->IncrementOptCount(this->GetOptType()); // keep count for debugging info if (this->IsNop()) TypeGroup = 1; // no-op idioms need their category reset // Emit appropriate optimization annotations. bool SDTInstrumentation = false; #if 1 // Find moves of code or data pointer constants. bool ValueFound = false; STARS_uval_t ConstValue; if (this->MDIsSimpleAssignment(ValueFound, ConstValue)) { if (ValueFound && (0 != ConstValue)) { // Assignment of constant. STARSDefUseIter DefIter = this->GetFirstDef(); assert(DefIter != this->GetLastDef()); SMPOperandType DefType = DefIter->GetType(); if (IsCodePtr(DefType)) { SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR CODEPTR %llx %s\n", (uint64_t) addr, this->GetSize(), (uint64_t) ConstValue, disasm); } else if (IsDataPtr(DefType)) { SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR DATAPTR %llx %s\n", (uint64_t) addr, this->GetSize(), (uint64_t) ConstValue, disasm); } } } #endif // In case we short circuit this function due to redundant or unused metadata, etc., // perform analyses that are useful to integer error annotations. #if SMP_ANNOTATE_ALL_MEMORY_OPERANDS // Emit informational annotations for memory operands. if (MemSrc) { STARSOpndTypePtr MemSrcOp = this->MDGetMemUseOp(); std::size_t SrcBitWidth = 8 * MemSrcOp->GetByteWidth(); STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemSrcOp, UseFP); // Need to unnormalize stack memory DEFs and USEs before printing annotations. this->MDGetUnnormalizedOp(AnnotDefOp); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSRC %zu", (unsigned long long) addr, this->GetSize(), SrcBitWidth); AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit()); SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } if (MemDest) { STARSOpndTypePtr MemDestOp = this->MDGetMemDefOp(); std::size_t DestBitWidth = 8 * MemDestOp->GetByteWidth(); STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(MemDestOp, UseFP); // Need to unnormalize stack memory DEFs and USEs before printing annotations. this->MDGetUnnormalizedOp(AnnotDefOp); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMDEF %zu", (unsigned long long) addr, this->GetSize(), DestBitWidth); AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit()); SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } #endif // If the instruction is a CALL (or INDIR_CALL that has been resolved to // a single target address), then we need to see if the call is to a // function that has been forbidden by a security policy. If so, we // need to output a security alert. // In the near future, we will output SPRI instrumentation to prevent // the system/library call from executing. if ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())) { // We have a resolved call target address, either via direct or indirect call. string FuncName = this->GetTrimmedCalledFunctionName(); ZST_SysCallType FuncCallType = global_STARS_program->GetCallTypeFromFuncName(FuncName); ZST_Policy FuncCallPolicy = global_STARS_program->GetPolicyFromCallType(FuncCallType); if (ZST_DISALLOW == FuncCallPolicy) { SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM: Call to %s will be disallowed at %llx in %s\n", FuncName.c_str(), (unsigned long long) this->GetAddr(), this->GetBlock()->GetFunc()->GetFuncName()); SMP_fprintf(global_STARS_program->GetAlarmFile(), "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR SECURITYCALL Disallow 1 1 %s \n", (unsigned long long) addr, this->GetSize(), disasm); } if (global_STARS_program->ShouldSTARSPerformConstantPropagation()) { // See if we propagated constants to any outgoing args for the CALL. if (global_STARS_program->ShouldSTARSMaximizeCFGImprovement()) { this->EmitConstOutArgAnnotations(InfoAnnotFile); } } } if ((CALL == DataFlowType) || (INDIR_CALL == DataFlowType) || (RETURN == DataFlowType)) { this->EmitCallReturnStatus(); } // If the DEF metadata is all unused, mmStrata can skip the instruction. // We omit this for groups 1 and 14, so that the metadata analysis // does not get statistical credit for instructions that were already // getting -1 annotations without analysis. // We also cannot skip STARS_NN_adc and STARS_NN_sbb instructions that change the // type of the incoming register. if ((1 != TypeGroup) && (14 != TypeGroup) && (!this->IsInterruptCall()) && !TypeChange) { if (UnusedMetadata) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL MetadataUnused %s \n", (unsigned long long) addr, -1, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); return; } else if (DEF_METADATA_REDUNDANT == DefMetadataType) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL MetadataRedundant %s \n", (unsigned long long) addr, -1, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); return; } else if (DEF_METADATA_PROF_REDUNDANT == DefMetadataType) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL MetadataRedundant %s \n", (unsigned long long) addr, -257, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); // Profiler annotations could be backed off due to false // positives, in which case we will need stack constant // annotations. this->AnnotateStackConstants(UseFP, AnnotFile); this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); return; } } switch (TypeGroup) { case 0: // SDT will have to handle these case 11: // PUSH/POP **!!** What if we push/pop NUMERIC type? Optimize? // --jdh // pop numeric's can be optimized with a numericdef annotation. // numeric push's can't immediately be optimized, but if the stack location // can be proven as dead metadata, then perhaps optimize. // --jdh // mmStrata wants to suppress warnings on the PUSH // instructions that precede the LocalVarsAllocInstr // (i.e. the PUSHes of callee-saved regs). if ((!AllocSeen || !NeedsFrame) && this->MDIsPushInstr()) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL NoWarn %s \n", (unsigned long long) addr, -3, disasm); NoWarnFlag = true; } else if (this->MDIsPopInstr() && NumericDEFs) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n", (unsigned long long) addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->GetOptType()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } else { SDTInstrumentation = true; } break; case 1: // nothing for SDT to do case 14: if (MemDest) { SMP_msg("ERROR: MemDest in Type Category 1 or 14: %llx %s\n", (unsigned long long) addr, disasm); SDTInstrumentation = true; break; } SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[this->GetOptType()], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; case 4: // INC, DEC, etc.: no SDT work unless MemDest if (MemDest || MemSrc) { // pretty conservative here? // could be more aggressive if we know there's no overflow. -- jdh SDTInstrumentation = true; break; // treat as category 0 } SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL Always1stSrc %s \n", (unsigned long long) addr, -1, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work. #if 1 if (MemDest) { SDTInstrumentation = true; break; // treat as category 0 } #endif if (SecondSrcOperandImmNum && !this->MDIsFrameAllocInstr() && !TypeChange #if SPECIAL_CASE_CARRY_BORROW && (!CarryBorrow) #endif ) { // treat as category 1 SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[this->GetOptType()], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } else if (IsEqType(NUMERIC, this->AddSubSourceType) && !this->MDIsFrameAllocInstr() && !TypeChange #if SPECIAL_CASE_CARRY_BORROW && (!CarryBorrow) #endif ) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL 2ndSrcNumeric %s \n", (unsigned long long) addr, -1, disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } else if (NumericDEFs) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n", (unsigned long long) addr, ProfiledDEFs ? -256 - 2 : -2, this->DestString(this->GetOptType()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } #if SMP_OPTIMIZE_ADD_TO_NUMERIC else if ((STARS_NN_add == this->GetIDAOpcode()) && (!MemSrc) && IsNumeric(this->AddSubDefUseType)) { // reg1 := reg1 + reg2, where reg1 comes in as NUMERIC, // means that reg1 will get DEFed to the type of reg2, // whatever it is. If reg2 were known to be NUMERIC, // we would have hit one of the annotation cases above. SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s := %s ZZ AddToNumeric %s \n", (unsigned long long) addr, -5, MDGetRegName(this->GetDefUseAddSubOp()), MDGetRegName(this->GetUseOnlyAddSubOp()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } #endif else { SDTInstrumentation = true; } break; case 6: // Only OS code should include these; problem for SDT if (MemDest) { SDTInstrumentation = true; break; // treat as category 0 } SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL AlwaysPTR %s \n", (unsigned long long) addr, -(this->GetOptType()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); break; case 8: // Implicitly writes to EDX:EAX, always numeric. if (this->GetOptType() == 10) { // writes to ECX also SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ECX ZZ %s %s \n", (unsigned long long) addr, -2, OptExplanation[this->GetOptType()], disasm); } else { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n EDX EAX ZZ %s %s \n", (unsigned long long) addr, -2, OptExplanation[this->GetOptType()], disasm); } global_STARS_program->IncrementAnnotationCount(this->GetOptType()); SDTInstrumentation = true; break; case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0) if (MemDest) { SDTInstrumentation = true; #if 0 if (NumericDEFs) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n", (unsigned long long) addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->GetOptType()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } #endif } else { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[this->GetOptType()], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } break; case 10: // AND, OR, etc.: If all DEFs have been inferred to be // NUMERIC, then output optimizing annotation. SDTInstrumentation = true; if (MemDest) { // **!!** optimize with numeric annotation in future break; // treat as category 0 } else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n", (unsigned long long) addr, ProfiledDEFs ? -256 - 2 : -2, this->DestString(this->GetOptType()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } break; case 12: // Exchange, exchange and add, conditional exchange: All NUMERIC // sources ==> NUMERIC DEFs, so nothing for mmStrata to do. if (MemDest) { // **!!** optimize with numeric annotation in future SDTInstrumentation = true; break; // treat as category 0 } else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, ProfiledDEFs ? -256-1 : -1, OptExplanation[TypeGroup], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } else SDTInstrumentation = true; break; case 13: case 15: // Floating point, NUMERIC, possible memory destination. // If not memory destination, fpreg dest, so nothing for mmStrata to do. if (MemDest) { // **!!** optimize with numeric annotation in future SDTInstrumentation = true; break; // treat as category 0 } else { // NUMERIC floating register result; these regs are always NUMERIC SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL %s %s \n", (unsigned long long) addr, -1, OptExplanation[TypeGroup], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } break; default: // 2,3,7: Optimization possibilities depend on operands SDTInstrumentation = true; if (MemDest) { break; // treat as category 0 } if ((this->GetOptType() == 2) || (this->GetOptType() == 7) || SecondSrcOperandImmNum) { SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s %s %s \n", (unsigned long long) addr, -2, this->DestString(this->GetOptType()), OptExplanation[this->GetOptType()], disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } else if (NumericDEFs) { // NUMERIC move instruction SMP_fprintf(AnnotFile, "%18llx %6d INSTR LOCAL n %s NumericDEFs %s \n", (unsigned long long) addr, ProfiledDEFs ? -256-2 : -2, this->DestString(this->GetOptType()), disasm); global_STARS_program->IncrementAnnotationCount(this->GetOptType()); } break; } // end switch (OptType) // always annotate stack constants for the profiler, etc. this->AnnotateStackConstants(UseFP, AnnotFile); // If mmStrata is going to have to deal with the // instruction, then we can annotate EBP and ESP // relative constant offsets. If we have emitted // an annotation of type -1, there is no point // in telling mmStrata about these constants. // Likewise, we can tell mmStrata if a MemDest is an // non-directly-accessed child object. if (SDTInstrumentation || NoWarnFlag || CallInst || IndirJumpAnalyzed) { // Optimize by informing mmStrata of dead registers. It can avoid saving // and restoring dead state. This is particularly important for EFLAGS, // as restoring the flags is a pipeline serializing instruction. this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); int ChildOffset, ChildSize; if (MemDest && ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr, ChildOffset, ChildSize)) { SMP_fprintf(AnnotFile, "%18llx %6zu INSTR CHILDACCESS %d %d ZZ %s \n", (unsigned long long) addr, this->GetSize(), ChildOffset, ChildSize, disasm); } #if SMP_IDENTIFY_POINTER_ADDRESS_REG // WARNING: This old code was written prior to the normalization of stack operands. if (MemDest) { assert(this->HasDestMemoryOperand()); set<DefOrUse, LessDefUse>::iterator PtrUse; PtrUse = this->GetPointerAddressReg(this->DEFMemOp); if (PtrUse != this->GetLastUse()) { // found POINTER addr reg USE if (PtrUse->GetOp()->GetOpType()->IsRegOp()) { SMP_fprintf(AnnotFile, "%18llx %6zu INSTR POINTER reg %s ZZ %s \n", (unsigned long long) addr, this->GetSize(), MDGetRegName(PtrUse->GetOp()), disasm); } } } #endif } else if (this->HasReturnOpcode()) { // In case we have a COMPLETE return target set, emit DEADREGS annotation for return inst. this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); } else { // Experiment with emitting DEADREGS for every inst, even direct jumps. this->EmitDeadRegsAnnotation(AnnotFile, IndirJumpAnalyzed, disasm); } return; } // end of SMPInstr::EmitTypeAnnotations() // emit DEADREGS annotation using DeadRegsBitmap. void SMPInstr::EmitDeadRegsAnnotation(FILE *AnnotFile, bool IndirJumpAnalyzed, char *disasm) { if (this->DeadRegsBitmap.any() && (NULL != this->GetBlock()) && (!this->GetBlock()->GetFunc()->IsMultiEntry())) { // Ensure that the only dead regs are not floating-point 8087 regs, which are not // useful as scratch registers for instrumentation, and whose deadness we don't // fully trust, so we won't print them in PrintDeadRegs(), anyway. bool RelevantDeadReg = false; for (int i = 0; i < MD_LAST_REG_NO; ++i) { if (!STARS_x86_is_FP8087_reg(i)) { if (this->DeadRegsBitmap[i]) { RelevantDeadReg = true; break; } } } if (RelevantDeadReg) { // Optimize by informing mmStrata of dead registers. It can avoid saving // and restoring dead state. This is particularly important for EFLAGS, // as restoring the flags is a pipeline serializing instruction. SMP_fprintf(AnnotFile, "%18llx %6zu INSTR DEADREGS ", (unsigned long long) this->GetAddr(), this->GetSize()); this->PrintDeadRegs(AnnotFile); SMP_fprintf(AnnotFile, " %s \n", disasm); if (IndirJumpAnalyzed && (!this->DeadRegsBitmap[MD_FLAGS_REG])) { // Unusual case: Switch table has live flags into cases. SMP_msg("INFO: IndirJump at %18llx has live flags register: Successor blocks: ", (unsigned long long) this->GetAddr()); for (list<SMPBasicBlock *>::iterator SuccIter = this->GetBlock()->GetFirstSucc(); SuccIter != this->GetBlock()->GetLastSucc(); ++SuccIter) { SMP_msg("%18llx ", (unsigned long long) (*SuccIter)->GetFirstAddr()); } SMP_msg("\n"); } } } return; } // end of SMPInstr::EmitDeadRegsAnnotation() // emit constant outgoing arg annotations for CALL instructions void SMPInstr::EmitConstOutArgAnnotations(FILE *InfoAnnotFile) { // Iterate through the argument regs for this program's ABI // and see if any of them are USEs in the CALL instruction // and also have constants determined in the SCCP analysis. std::list<STARS_regnum_t>::iterator ArgRegIter; for (ArgRegIter = global_STARS_program->GetFirstArgumentReg(); ArgRegIter != global_STARS_program->GetLastArgumentReg(); ++ArgRegIter) { STARS_regnum_t ArgRegNo = *ArgRegIter; STARSOpndTypePtr ArgRegOp = this->MakeRegOpnd(ArgRegNo); STARSDefUseIter UseIter = this->FindUse(ArgRegOp); if (UseIter != this->GetLastUse()) { // Look up argument reg + SSA number in SCCP hash table int UseSSANum = UseIter->GetSSANum(); SMPBasicBlock *CurrBlock = this->GetBlock(); int UseHashIndex = HashGlobalNameAndSSA(ArgRegOp, UseSSANum); bool LocalName = CurrBlock->IsLocalName(ArgRegOp); STARSSCCPMapIter ConstIter; bool ConstFound = CurrBlock->GetFunc()->FindSCCPConstIter(CurrBlock, UseHashIndex, LocalName, ConstIter); if (ConstFound) { // found an SCCP const entry of type STARS_CONST_HAS_VALUE ++SCCPConstantOutgoingArgWriteCount; STARS_uval_t ConstVal = (*ConstIter).second.ConstValue; SMP_fprintf(InfoAnnotFile, "%18llx %6zu CALL CONSTARG %s %llx ZZ \n", (uint64_t) this->GetAddr(), this->GetSize(), MDGetRegName(ArgRegOp), (uint64_t) ConstVal); } } } // end for all argument regs return; } // end of SMPInstr::EmitConstOutArgAnnotations() // union of sign masks from 2 reg USEs for binary arithmetic unsigned short SMPInstr::SignMaskUnionFromUseRegs(void) { unsigned short UnionMask = 0; unsigned short UseSignMask, DefSignMask; set<DefOrUse, LessDefUse>::iterator UseIter; std::size_t RegOpCount = 0; int UseHashValue; struct FineGrainedInfo UseFGInfo, DefFGInfo; bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer(); if (this->HasSourceMemoryOperand()) { // Don't have binary arithmetic on just registers. return UnionMask; } for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { STARSOpndTypePtr UseOp = UseIter->GetOp(); if (MDIsGeneralPurposeReg(UseOp) && (!MDIsStackPtrReg(UseOp->GetReg(), UseFP))) { ++RegOpCount; UseHashValue = HashGlobalNameAndSSA(UseOp, UseIter->GetSSANum()); bool LocalUseName = this->BasicBlock->IsLocalName(UseOp); if (LocalUseName) { // Local name, find in basic block maps. UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // Global name, find in global maps. UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } UseSignMask = (FG_MASK_SIGNEDNESS_BITS & UseFGInfo.SignMiscInfo); if (0 == UseSignMask) { // Try to get signedness from DEF. if (LocalUseName) { // Local name, find in basic block maps. DefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue); } else { // Global name, find in global maps. DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue); } DefSignMask = (FG_MASK_SIGNEDNESS_BITS & DefFGInfo.SignMiscInfo); UnionMask |= DefSignMask; } else { UnionMask |= UseSignMask; } } } if (2 > RegOpCount) { // only interested in binary arithmetic on two registers UnionMask = 0; } return UnionMask; } // SMPInstr::SignMaskUnionFromUseRegs() // emit check annotations for signedness, overflow, truncation, etc. void SMPInstr::EmitIntegerErrorAnnotations(FILE *InfoAnnotFile, list<std::size_t> &LoopList) { set<DefOrUse, LessDefUse>::iterator UseIter, DefIter; STARSOpndTypePtr UseOp = nullptr, DefOp = nullptr; unsigned short UseWidthInfo, DefWidthInfo, SourceDefWidthInfo; unsigned short DefSignInfo, SourceDefSignInfo; unsigned short UseSignMask, DefSignMask, SourceDefSignMask; struct FineGrainedInfo UseFGInfo, DefFGInfo, SourceDefFGInfo; std::size_t UseBitWidth, DefBitWidth, UseMaxBitWidth, SourceDefBitWidth, DefMaxBitWidth; STARS_ea_t DefAddr; int UseHashValue, DefHashValue, SSANum, DefSSANum, UseSSANum; int IdiomCode = 0; // records code pattern number causing suppression of annotation. bool OverflowOpcode = this->MDIsOverflowingOpcode(); bool UnderflowOpcode = this->MDIsUnderflowingOpcode(); bool CheckForOverflow; bool UseIsSigned, DefIsSigned, UseIsUnsigned, DefIsUnsigned, SourceDefIsSigned, SourceDefIsUnsigned; bool UseSignMixed, SourceDefSignMixed; // inconsistent signedness bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); bool SuppressSignednessCheck = false; // If we are not confident in check, set to true. bool PartialStore; // Store is fewer bits than is defined for the target, e.g. overwriting last 8 bits // of an int or a pointer. Cannot have signedness error in that case, as sign bit // is not affected. bool cases1and2 = (OverflowOpcode || UnderflowOpcode); bool case3 = this->MDIsMultiply(); bool cases4and5 = ((3 == this->GetOptType()) && this->GetMoveSource()->IsRegOp()); bool case6 = ((this->MDIsLoadEffectiveAddressInstr()) && (!(this->IsNop() || this->IsRegClearIdiom()))); bool case7 = this->MDDoublesWidth(); bool case8 = ((STARS_BADADDR != this->GetCallTarget()) && (!this->IsCallUsedAsJump())); // possible memset() call char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); string SinkString(""); if (this->IsNumericAnnotationSuppressed()) { return; // Cannot figure out IdiomCode; suppressed from earlier instruction's analyses } // If the instruction is the beginning of an infinite loop, we want no annotations other than // the infinite loop annotation. if (this->IsFirstInBlock()) { if (this->GetBlock()->IsInfiniteSelfLoop()) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR INFINITELOOP %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), disasm); return; } } if (!(cases1and2 || case3 || cases4and5 || case6 || case7 || case8)) { return; } bool HasIntErrorSink = false; DefIter = this->GetFirstNonFlagsDef(); if (!case8 && (DefIter != this->GetLastDef())) { DefOp = DefIter->GetOp(); SSANum = DefIter->GetSSANum(); bool FoundAnyCall = false; HasIntErrorSink = this->GetBlock()->GetFunc()->HasIntErrorCallSink(DefOp, SSANum, this->GetAddr(), SinkString, FoundAnyCall); #if STARS_USE_NUMERIC_ERROR_BLACKLISTING if (!(HasIntErrorSink || this->HasPEASOUPBlacklistSink(FoundAnyCall))) { return; } #endif } // Case 1: Overflow on addition. // Case 2: Underflow on subtraction. if (OverflowOpcode || UnderflowOpcode) { // If the flags register DEF is dead, we need a CHECK OVERFLOW/UNDERFLOW annotation. STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); DefIter = this->FindDef(FlagsOp); assert(DefIter != this->GetLastDef()); if (this->BasicBlock->IsDefDead(this->GetAddr(), FlagsOp)) { DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); DefOp = DefIter->GetOp(); SSANum = DefIter->GetSSANum(); SMPOperandType DefType = DefIter->GetType(); SMPOperandType MemType; SMPOperandType DefUseType = UNINIT; // type of USE that is also the DEF of the instruction SMPMetadataType DefMetaStatus = DefIter->GetMetadataStatus(); bool DefUnusedMetadata = (DEF_METADATA_UNUSED == DefMetaStatus); bool IgnoreOverflow = this->IsBenignOverflow(IdiomCode); STARS_uval_t ConstValue = 0; // NOTE: We no longer suppress the IgnoreOverflow annotations. Instead, we print // them with an IdiomCode so that suppression can happen downstream, along with // customized continuation policies, statistical summarizing, etc. #if SMP_MEASURE_NUMERIC_ANNOTATIONS if (IgnoreOverflow) ++BenignOverflowInstCount; #endif // Don't worry about stack space allocation instructions. The // program will crash long before the stack pointer underflows // below zero. if (!((DefOp->IsRegOp()) && DefOp->MatchesReg(MD_STACK_POINTER_REG))) { if (!IgnoreOverflow && (this->GetBlock()->IsBenignOverflowDEF(DefOp, SSANum, this->GetAddr(), UnderflowOpcode, IdiomCode))) { IgnoreOverflow = true; #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++BenignOverflowDefCount; #endif } if (DefOp->IsRegOp()) { DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum); if (this->BasicBlock->IsLocalName(DefOp)) { // Local name, find in basic block maps. DefFGInfo = this->BasicBlock->GetDefFGInfo(DefHashValue); } else { // Global name, find in global maps. DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue); } } else if (MDIsDirectStackAccessOpnd(DefOp, UseFP)) { bool success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), DefOp, DefFGInfo); assert(success); } else { // non-stack memory address; we know nothing about it. DefFGInfo.SignMiscInfo = 0; DefFGInfo.SizeInfo = 0; } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++NumericAnnotationsCount12; #endif DefSignInfo = DefFGInfo.SignMiscInfo; DefSignMask = DefSignInfo & FG_MASK_SIGNEDNESS_BITS; DefWidthInfo = DefFGInfo.SizeInfo; DefBitWidth = LargestBitWidthFromMask(DefWidthInfo); if (0 == DefBitWidth) { // Could happen for non-stack memory operands, for example. DefBitWidth = MD_NORMAL_MACHINE_BITWIDTH; } if (DefSignMask == 0) { // If no sign info from DEF, see if we can get it from the USE regs. DefSignMask = this->SignMaskUnionFromUseRegs(); } if ((0 == IdiomCode) && (DefSignMask == FG_MASK_UNSIGNED)) { // UNSIGNED is often unreliable because compilers zero-extend values // just so they can avoid having undefined register bits. Later, only // the lower bits get stored. We already detect this pattern as a benign // truncation, but we need to back off on the certainty of our UNSIGNED // inference on overflow/underflow operations along the path. UseIter = this->FindUse(DefOp); if (UseIter != this->GetLastUse()) { UseOp = UseIter->GetOp(); UseSSANum = UseIter->GetSSANum(); DefUseType = UseIter->GetType(); if (MDIsDataFlowOpnd(UseOp, UseFP)) { if (this->IsOpSourceZeroExtendedMove(UseOp, UseSSANum, false)) { if (this->GetBlock()->IsOpDestTruncatedWrite(DefOp, SSANum, this->GetAddr())) { // Operand source was reduced-width, zero-extended; ultimate use is to store // only the lower bits. The zero extension is no longer a reliable source of // inference for UNSIGNEDness. DefSignMask = FG_MASK_INCONSISTENT_SIGN; } } else if (UnderflowOpcode && this->IsOpSourceSmallPositiveConstant(UseOp, UseSSANum)) { // subtract from small positive, danger of UNSIGNED UNDERFLOW. Most likely, the // inference of UNSIGNED is unreliable. DefSignMask = FG_MASK_INCONSISTENT_SIGN; } } } } if (OverflowOpcode) { if ((17 == IdiomCode) && (FG_MASK_UNSIGNED == DefSignMask)) { // An IdiomCode of 17 means not a benign overflow, but an addition that // produces a jump table offset, which can be an addition of mixed signedness // that produces false positives if treated as UNSIGNED. See discussion in // SMPBasicBlock::IsBenignOverflowDEF(). DefSignMask = FG_MASK_INCONSISTENT_SIGN; } else if (this->IsAdditionOfLargeConstant(ConstValue, DefSignMask)) { IgnoreOverflow = true; IdiomCode = 11; } SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu ", (unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[DefSignMask], DefBitWidth); } else { // must be UnderflowOpcode // (1) Two more benign case to exclude: // movzx eax, byte ptr [esp+37] ; get char, with misleading zero-extension // sub eax,0x65 ; subtract 'A' to see if char is in letter range // cmp eax,25 ; there are 26 capital letters // ja nextcheck ; not in range of 'A' to 'Z' // return true ; found an alphanumeric // These operations make eax look UNSIGNED. But it is an ASCII char, and the subtraction // will underflow whenever the char is less than 'A'. Similar checks occur for 'a' // and the digit '0' quite often. We do not want false positives on underflow checks. // // (2) sub eax,[large constant value] // We might have to follow the subtrahend operand back to its origin. A subtraction of a // number that has a very large absolute value tends to indicate that underflow is benign // and is being ignored. if (!IgnoreOverflow) { if ((DefSignMask == FG_MASK_UNSIGNED) && (this->SubtractsImmedASCII())) { IgnoreOverflow = true; IdiomCode = 9; } else if ((DefSignMask == FG_MASK_UNSIGNED) || (DefSignMask == FG_MASK_SIGNED)) { if (this->IsSubtractionOfLargeConstant(ConstValue, DefSignMask)) { IgnoreOverflow = true; IdiomCode = 11; } } } SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK UNDERFLOW %s %zu ", (unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[DefSignMask], DefBitWidth); } STARSOpndTypePtr AnnotDefOp = CloneIfNecessary(DefOp, UseFP); if (! DefOp->IsRegOp()) { // Need to unnormalize stack memory DEFs and USEs before printing annotations. this->MDGetUnnormalizedOp(AnnotDefOp); } AnnotPrintOperand(AnnotDefOp, InfoAnnotFile, UseFP, this->MDIsAddressing64bit()); if (!IgnoreOverflow) { // See if we made a special detection of an operation involved in a hash function, which can // be expected to overflow benignly. if (this->IsHashOperation()) { IgnoreOverflow = true; IdiomCode = 15; } else if (IsDataPtr(DefType) || IsDataPtr(DefUseType)) { // IDIOM 18 says to let C7 (buffer overflow/underflow) defenses handle the issues if it is a pointer. IgnoreOverflow = true; IdiomCode = 18; } else if (!LoopList.empty()) { // Limit search for address-reg-only case to loops for now. list<std::size_t>::iterator LoopIter; for (LoopIter = LoopList.begin(); LoopIter != LoopList.end(); ++LoopIter) { std::size_t Counter = 0; std::size_t LoopNum = (*LoopIter); MemType = UNINIT; this->GetBlock()->GetFunc()->ResetProcessedBlocks(); bool AddrRegOnly = this->GetBlock()->IsDefOnlyUsedAsAddressReg(this->GetAddr(), DefOp, LoopNum, Counter, MemType); if (AddrRegOnly && (0 < Counter)) { // Similarly, let C7 (buffer overflow/underflow) defenses handle the issues if it is only an index register. DefType = MemType; IgnoreOverflow = true; IdiomCode = 18; break; // Don't need to look at next loop } } } } if (IgnoreOverflow) { if (11 == IdiomCode) { SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d CONST %lu %s \n", IdiomCode, (unsigned long) ConstValue, disasm); } else if (18 == IdiomCode) { // Need a tag field telling what kind of pointer. if (IsEqType(DefType, STACKPTR) || IsEqType(DefUseType, STACKPTR)) { SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d STACKMEMSINK %s \n", IdiomCode, disasm); } else if (IsEqType(DefType, HEAPPTR) || IsEqType(DefUseType, HEAPPTR)) { SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d HEAPMEMSINK %s \n", IdiomCode, disasm); } else if (IsEqType(DefType, GLOBALPTR) || IsEqType(DefUseType, GLOBALPTR)) { SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d GLOBALMEMSINK %s \n", IdiomCode, disasm); } else { // must be unrefined POINTER type. SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d MEMORYSINK %s \n", IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, " ZZ IDIOM %d %s \n", IdiomCode, disasm); } } else if (HasIntErrorSink) { SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } } // end if (!(DEF is stack ptr register)) #if SMP_MEASURE_NUMERIC_ANNOTATIONS else { ++SuppressStackPtrOverflowCount; } #endif } // end if flags reg is dead #if SMP_MEASURE_NUMERIC_ANNOTATIONS else { ++SuppressLiveFlagsOverflowCount; } #endif } // end cases 1-2 // Case 3: Overflow on multiplication with upper bits discarded. if (case3) { // There are five overflow sub-cases for x86: (A) the multiplication result // can go into EDX:EAX for 32x32=>64 bit multiplication; (A2) RDX:RAX gets // result of 64x64=>128-bit multiplication in x86-64; (B) the result // can go into DX:AX for 16x16=>32 bit; (C) the result can be in AX // for 8x8=>16 bit; (D) see below. The latter case (C) will be detected most easily // as a truncation in a later instruction, i.e. if only AL gets stored // later, then we check the AH bits at that time for a truncation // error. Because our SSA numbering lumps AL, AH, AX, and EAX into // a single canonicalized register, we would have a hard time using // SSA-based def-use chains to determine if AH is dead. // For the other three sub-cases, the question is whether EDX becomes dead // starting with the DEF of EDX in the multiply instruction. // Case (D) is where the multiply instruction discards the upper bits // of the multiply. // Sub-cases A&B are detected by checking if EDX is dead, and if so, then // emitting an annotation to check for the overflow flag. The x86 sets // overflow and carry flags on multiplication instructions based on whether // the result carries out of the lower half of the result to the upper half. // Sub-case D is also detected using flags, but we don't need to check whether EDX // is dead. We just need to detect that EDX is not in the DEF set in the // first place. We have a private member flag for that case. CheckForOverflow = false; if (this->AreMultiplicationBitsDiscarded()) { // Sub-case D CheckForOverflow = true; assert(this->RTL.GetCount() > 0); DefOp = this->RTL.GetRT(0)->GetLeftOperand(); DefIter = this->FindDef(DefOp); assert(DefIter != this->GetLastDef()); DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum()); } else { // If the instruction were EDX:=EDX*foo, then it would be // the multiplication bits discarded case and would not // reach this else clause. Therefore, if we find EDX in // the DEF set, it is holding upper result bits of the // multiplication and we have the potential for sub-cases A&B // but not sub-case C. So, we check to see if the DEF of EDX // is dead. DefOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx); DefIter = this->FindDef(DefOp); if (DefIter != this->GetLastDef()) { // We found DEF of EDX, so it is not AX:=AL*op8 sub-case C. // Now, is DEF of EDX dead (i.e. no uses?) CheckForOverflow = this->BasicBlock->IsDefDead(this->GetAddr(), DefOp); if (CheckForOverflow) { DefHashValue = HashGlobalNameAndSSA(DefOp, DefIter->GetSSANum()); } } } // end if sub-case D else if sub-case A or B if (CheckForOverflow) { // need an annotation #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++NumericAnnotationsCount3; #endif if (this->BasicBlock->IsLocalName(DefOp)) { // Local name, find in basic block maps. DefFGInfo = this->BasicBlock->GetDefFGInfo(DefHashValue); } else { // Global name, find in global maps. DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue); } DefWidthInfo = DefFGInfo.SizeInfo; DefBitWidth = LargestBitWidthFromMask(DefWidthInfo); DefSignMask = (DefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); if (DefSignMask == 0) { // If no sign info from DEF, see if we can get it from the USE regs. DefSignMask = this->SignMaskUnionFromUseRegs(); } // Next two statements exclude the inconsistent sign case and the no sign info known case. DefIsSigned = (FG_MASK_SIGNED == DefSignMask); // exact, not bit-mask-AND DefIsUnsigned = (FG_MASK_UNSIGNED == DefSignMask); // exact, not bit-mask-AND STARS_uval_t ConstValue = 0; IdiomCode = 0; bool UnsignedAnnot = (this->MDIsUnsignedArithmetic() || DefIsUnsigned); bool SignedAnnot = (this->MDIsSignedArithmetic() || DefIsSigned); if (0 == DefSignMask) { // Prepare DefSignMask for use by IsMultiplyByLargeConst(), // as it is of no more use in case3. if (UnsignedAnnot) DefSignMask = FG_MASK_UNSIGNED; else if (SignedAnnot) DefSignMask = FG_MASK_SIGNED; } if (this->IsMultiplyByLargeConstant(ConstValue, DefSignMask)) { IdiomCode = 10; } if (this->AreMultiplicationBitsDiscarded() && (!SignedAnnot)) { IdiomCode = 33; } if (UnsignedAnnot) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW UNSIGNED %zu %s ZZ", (unsigned long long) this->GetAddr(), this->GetSize(), DefBitWidth, MDGetRegName(DefOp)); } else if (SignedAnnot) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW SIGNED %zu %s ZZ", (unsigned long long) this->GetAddr(), this->GetSize(), DefBitWidth, MDGetRegName(DefOp)); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW UNKNOWNSIGN %zu %s ZZ", (unsigned long long) this->GetAddr(), this->GetSize(), DefBitWidth, MDGetRegName(DefOp)); } if (33 == IdiomCode) { SMP_fprintf(InfoAnnotFile, " IDIOM %d %s \n", IdiomCode, disasm); } else if (0 < IdiomCode) { SMP_fprintf(InfoAnnotFile, " IDIOM %d CONST %lu %s \n", IdiomCode, (unsigned long) ConstValue, disasm); } else { SMP_fprintf(InfoAnnotFile, " %s \n", disasm); } } // end if (CheckForOverflow) #if SMP_MEASURE_NUMERIC_ANNOTATIONS else { ++LiveMultiplyBitsCount; } #endif } // end of case 3 // Case 4: Signedness error on move. // Case 5: Truncation error on move. IdiomCode = 0; if (cases4and5) { int TruncationIdiomCode = 0; bool SuppressTruncation = this->IsBenignTruncation(TruncationIdiomCode); // Possibilities for a move: reg to reg, mem to reg, or reg to mem. If we load // from memory into a register, we cannot track signedness in memory unless it // is a stack location. In that case, we record the signedness in the stack // map and transfer it to the reg DEF in SMPInstr.MDSetWidthSignInfo(). That // determines the signedness of the reg DEF and it cannot be in conflict with // the stack memory USE. The load from stack to reg also determines width // of the stack operand and we cannot have a truncation. So, we can restrict // our analysis of cases 4-5 to register-source move instructions, as we // have done in the condition above. // // Similarly, we cannot detect a signedness conflict if the destination is a // memory location that is not known to be a particular stack offset location. // // So, we only concern ourselves with signedness errors // when the USE operand of the move is a register, and the destination is another // register or a stack location. // // We can have a truncation error and a signedness error on a single instruction, so // we group them into common code. For example, move the lower half of a 32-bit unsigned // into a 16-bit signed destination. Upper bits set to 1 and discarded would be a // truncation, and setting the sign bit of the 16-bit signed destination would be a // signedness error. // // NOTE: Signedness errors are different from overflow and truncation errors. We // can have incomplete knowledge about an instruction's operands and still determine // that truncation occurred. For example, if we do not know whether register EAX // is signed or unsigned, we can still say that storing only AX is a truncation error // if the upper half of EAX is a mixture of one and zero bits. If EAX is unsigned, // we could be more specific and insist that the upper half be all zero bits; if EAX // is signed, we could insist that the upper half of EAX be the sign-extension of AX. // We can avoid false positives by only declaring a truncation error when the upper // half of EAX is not all zero bits or all one bits. This approach allows a few // potential false negatives. With signedness, if we don't know the signedness // of one of the operands, we can only avoid false positives by doing no checks at // all. UseOp = this->GetMoveSource(); UseBitWidth = 8 * UseOp->GetByteWidth(); STARSOpndTypePtr SearchOp = UseOp->clone(); // clone because we can call SearchOp->SetByteWidth(8) below // Canonicalize sub-regs for searching DEFs and USEs. CanonicalizeOpnd(SearchOp); UseIter = this->FindUse(SearchOp); assert(UseIter != this->GetLastUse()); // Now, the question is: Are we storing fewer bits than // we were using in our computations in this DEF-USE chain? // E.g. if we computed using 32 bits and then only store 16, // we have potential truncation error. But if we computed // using 16 bits all along, we have already checked for 16-bit // overflows on arithmetic in the DU chain and there can be no // truncation on this store. UseSSANum = UseIter->GetSSANum(); UseHashValue = HashGlobalNameAndSSA(SearchOp, UseSSANum); bool LocalSearchOp = this->BasicBlock->IsLocalName(SearchOp); if (LocalSearchOp) { // Local name, find in basic block maps. SourceDefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue); UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // Global name, find in global maps. SourceDefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue); UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } SourceDefWidthInfo = SourceDefFGInfo.SizeInfo; UseWidthInfo = UseFGInfo.SizeInfo; SourceDefBitWidth = LargestBitWidthFromMask(SourceDefWidthInfo); UseMaxBitWidth = LargestBitWidthFromMask(UseWidthInfo); UseSignMask = (UseFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); SourceDefSignInfo = SourceDefFGInfo.SignMiscInfo; SourceDefSignMask = (SourceDefSignInfo & FG_MASK_SIGNEDNESS_BITS); // If the DEF is in the SSA marker instruction at the top of the function, // then the register was live into the function. The register is canonicalized // to full width in the DEF in the marker instruction, making it appear that it // is now being truncated. In fact, what is more likely is that a subword reg // was passed in to the function, zero-extended. We should detect this case and suppress // truncation annotations, else they will increase when we pass interprocedural // types and FG info into the marker instruction. if (!SuppressTruncation && (0 == UseSSANum)) { if (this->GetBlock()->GetFunc()->IsLiveIn(SearchOp)) { SuppressTruncation = true; TruncationIdiomCode = 26; } else { STARS_ea_t DefAddr; if (LocalSearchOp) { if (0 == this->GetBlock()->GetNumber()) { // first block DefAddr = this->GetBlock()->GetDefAddrFromUseAddr(SearchOp, this->GetAddr(), 0, true); } else { DefAddr = STARS_BADADDR; } } else { DefAddr = this->GetBlock()->GetFunc()->GetGlobalDefAddr(SearchOp, 0); } if ((STARS_BADADDR != DefAddr) && (DefAddr < STARS_PSEUDO_ID_MIN)) { // We have the address of a defining instruction for SearchOp+UseSSANum==0. // See if the reg was defined by a move from an incoming arg. If so, the // incoming arg probably has full width, but that does not prove that it // was always full width in the caller, because args are passed full-width on the stack. SMPInstr *DefInst = this->GetBlock()->GetFunc()->GetInstFromAddr(DefAddr); if (DefInst->MDIsMoveInstr()) { STARSOpndTypePtr MoveSourceOp = DefInst->GetMoveSource(); if (this->GetBlock()->GetFunc()->IsInIncomingArgsRegion(DefInst, MoveSourceOp)) { SuppressTruncation = true; TruncationIdiomCode = 26; } } } } } #if 1 // If we have no signedness info at all for the UseSignMask, but // the SourceDefSignMask has info, then we want to use the // SourceDefSignMask as our signedness info. This is because of // simple instruction sequences in which no signedness can be inferred // from the use, e.g.: // // imul eax,ebx ; eax := eax*ebx and eax&ebx are signed // mov [ebp-8],al ; store al on stack // // If we don't know the signedness of stack location [ebp-8], // then we will end up in the S->? case below and we will emit // a CHECK TRUNCATION UNKNOWNSIGN annotation. This discards the // knowledge we have that EAX is signed, from the IMUL opcode. if (0 == UseSignMask) { UseSignMask = SourceDefSignMask; } #endif // Next six statements exclude the inconsistent sign case and the no sign info known case. UseIsSigned = (FG_MASK_SIGNED == UseSignMask); // exact, not bit-mask-AND UseIsUnsigned = (FG_MASK_UNSIGNED == UseSignMask); // exact, not bit-mask-AND SourceDefIsSigned = (FG_MASK_SIGNED == SourceDefSignMask); // exact, not bit-mask-AND SourceDefIsUnsigned = (FG_MASK_UNSIGNED == SourceDefSignMask); // exact, not bit-mask-AND UseSignMixed = (FG_MASK_INCONSISTENT_SIGN == UseSignMask); // exclude uninit sign case SourceDefSignMixed = (FG_MASK_INCONSISTENT_SIGN == SourceDefSignMask); // exclude uninit sign case // Not only the CHECK SIGNEDNESS annotations depend on the signedness of the // source and destination operands. The CHECK TRUNCATION annotations come // in SIGNED, UNSIGNED, and UNKNOWNSIGN variants, so we need to get the // signedness of the destination operand before we proceeed. DefOp = this->RTL.GetRT(0)->GetLeftOperand(); // RTL must be dest := rhs STARSOpndTypePtr DestSearchOp = CloneIfSubwordReg(DefOp); bool StackDestination = false; // Outargs locations are reused for different function calls, so no inference of their // signedness is valid. We maintain a flag to suppress signedness checks on writes to // outargs locations on the stack. We make an exception for the known unsigned args to // certain library functions. bool OutArgsWrite = false; bool IgnoreOutArgsWrite = false; bool NonStackMemDestination = false; if (DestSearchOp->IsRegOp()) { StackDestination = false; CanonicalizeOpnd(DestSearchOp); } else if (!(MDIsDirectStackAccessOpnd(DefOp, UseFP))) { // If destination of move is not a register and is not // a stack location, we cannot track its signedness and width. NonStackMemDestination = true; } else { StackDestination = true; } DefIter = this->FindDef(DestSearchOp); DefSSANum = DefIter->GetSSANum(); if (StackDestination) { // Fetch FG info from stack map. bool success = this->GetBlock()->GetFunc()->MDGetFGStackLocInfo(this->GetAddr(), DefOp, DefFGInfo); assert(success); OutArgsWrite = this->GetBlock()->GetFunc()->IsInOutgoingArgsRegion(DefOp); IgnoreOutArgsWrite = OutArgsWrite && (!(this->IsUnsignedArg())); // ignore out args write iff not a known unsigned argument } else if (NonStackMemDestination) { // We can check truncation of USE operand, but we know nothing about // the DEF operand. DefFGInfo.SignMiscInfo = 0; DefFGInfo.SizeInfo = 0; } else { // Fetch FG info from register FG info maps. DefHashValue = HashGlobalNameAndSSA(DestSearchOp, DefSSANum); if (this->BasicBlock->IsLocalName(DestSearchOp)) { // Local name, find in basic block maps. DefFGInfo = this->BasicBlock->GetDefFGInfo(DefHashValue); } else { // Global name, find in global maps. DefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue); } } DefSignMask = (DefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); // Next two statements exclude the inconsistent sign case and the no sign info known case. DefIsSigned = (FG_MASK_SIGNED == DefSignMask); // exact, not bit-mask-AND DefIsUnsigned = (FG_MASK_UNSIGNED == DefSignMask); // exact, not bit-mask-AND // Get the Def bit width and maximum bit width for special cases. DefWidthInfo = DefFGInfo.SizeInfo; DefMaxBitWidth = LargestBitWidthFromMask(DefWidthInfo); // max width over all defs DefBitWidth = 8 * DefOp->GetByteWidth(); // width of def in current instruction PartialStore = (DefBitWidth < DefMaxBitWidth); if (StackDestination) { // We only do signedness checks in limited, safe analysis cases on stack writes. SuppressSignednessCheck = this->SkipSignednessCheckOnStackWrite(DefSSANum, UseIsSigned); if (SuppressSignednessCheck) { IdiomCode = 7; } } else { // Check signedness on regs, but not on non-stack memory DEFs. SuppressSignednessCheck = NonStackMemDestination; } // If we set the (source) DEF bit width to 0, it means we wanted to have the USEs determine // the width. This happens on sign-extended and zero-extended loads. If we zero-extend // a 16-bit value to 32 bits, then immediately store the lower 16 bits to a 16-bit location, // then the upper bits cannot have any overflow info yet. But if we do 32-bit arithmetic // on the zero-extended value, and then store the lower 16 bits, we need to check for // truncation. So, the key is whether the value ever got used as a 32-bit value. If it // did, check for truncation; if not, there is no need to check. if ((SourceDefBitWidth > UseBitWidth) || ((SourceDefBitWidth == 0) && (UseMaxBitWidth > UseBitWidth))) { // Original DEF (or subsequent USE) was wider than what we are storing now. if (SourceDefBitWidth == 0) { // Convert for printing annotation. SourceDefBitWidth = 8 * SearchOp->GetByteWidth(); } if ((SourceDefBitWidth == 64) && (SearchOp->GetByteWidth() < 8)) { // Unlike overflows, we don't have the original DefOp that is 64 bits; // it is in a previous instruction. We don't want to print ESI instead of RSI, // for example, so we fix the width field of SearchOp. SearchOp->SetByteWidth(8); } // OK, we need to check for possible truncation. But, how we check depends on the // signedness combinations of the source and destination operands of the move. // Each operand can be signed, unsigned, or of unknown sign (and we lump the // inconsistent sign case into the unknown sign case). So, we have a set of 3x3=9 // possible combinations of signedness. // Now we have the DefSignMask to compare to the UseSignMask. The nine possible // combinations, and the annotations we want to emit for each, are shown below. // S = SIGNED, U = UNSIGNED, and ? = unknown or inconsistent sign. // S => U indicates a SIGNED being stored into an UNSIGNED, for example. // Assume without loss of generality that register EAX is the source of // all the move instructions, and that only subword register AX is being stored. // We can perform all truncation and signedness checks on EAX just prior to // the move instruction, which is cheaper than performing checks on the // destination if the destination is in memory. // // U => U // U => S // S => U // U => ? // ? => U // // In these first five cases, EAX must be the zero-extension of AX else there is // a truncation error. In the three cases in which the source (EAX/AX) is UNSIGNED, // discarding upper bits that are not zero is obviously truncation. In the case // of S => U, if the upper bits of EAX are not all zeroes, then we either have // a large positive value of EAX that is being truncated, or EAX is negative and // the lower bits will be misinterpreted in the unsigned destination. Finally, // the ? => U case must be either U => U or S => U, and these two cases already // share the demand that EAX be the zero-extension of AX. So, these five cases // will receive the annotation: CHECK TRUNCATION UNSIGNED 32 EAX 16 AX which // means that EAX is tested against AX to see if it is the 32-bit zero-extension // of 16-bit reg AX. // In the U => S case, we can have a signedness error as well as truncation. Even // if the truncation check passes (all upper half bits of EAX are zero), the top // bit of AX might be 1, and this will be misinterpreted as a sign bit in the // destination. So, this case receives a second annotation: CHECK SIGNEDNESS SIGNED 16 AX. // In the two cases that involve signedness uncertainty, there are possible signedness // errors that we are not checking at tun-time, because we do not have enough information // to perform the checks without generating many more false positives than true positives. // As a result, false negatives on signedness can occur. // // On to more of the 9 combinations: // // S => S // // In this case, EAX must be the sign-extension of AX. Because the destination is also // signed, nothing is lost if the sign-extension bits (all zeroes or all ones) are dropped. // We emit a CHECK TRUNCATION SIGNED 32 EAX 16 AX annotation to test EAX == sign-extended AX. // // S => ? // ? => S // ? => ? // // These final three cases all involve at least one operand of unknown signedness, and no // operands that are known to be unsigned. In each case, there are two possibilities: // either EAX must be the sign-extension of AX, or EAX must be the zero-extension of AX. // Because of the uncertainty that is represented by the question marks, we are not sure // which of these two cases we are dealing with. However, rather than just give up and // perform no run-time checks (to avoid false positives), we can still perform a run-time // check that will catch (perhaps most) true positives while causing no false positives. // We can insist that EAX must be EITHER the sign-extension or the zero-extension of AX. // To be neither type of extension of AX implies that some sort of truncation is happening. // So, we emit a CHECK TRUNCATION UNKNOWNSIGN 32 EAX 16 AX annotation, and the Strata // instrumentation will check for either EAX == sign-extended AX or EAX == zero-extended AX // being true. If neither is true, we raise a true positive alert. False negatives on // signedness errors are the result of the uncertainty, but all truncations are detected // for all nine cases. bool HasSinkString = HasIntErrorSink; if (DefIsUnsigned || UseIsUnsigned) { // First five cases above: any UNSIGNED operand leads to CHECK TRUNCATION UNSIGNED annotation. if (!SuppressTruncation) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION UNSIGNED %zu %s %zu %s", (unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth, MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp)); if (HasSinkString) { SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++TruncationAnnotationsCount; #endif } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION UNSIGNED %zu %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth, MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp), TruncationIdiomCode, disasm); } if (UseIsUnsigned && DefIsSigned && !OutArgsWrite && !PartialStore) { if (!SuppressSignednessCheck && (0 == IdiomCode)) { unsigned short DummySignMask; if ((0 != TruncationIdiomCode) && this->MDIsSignedLoad(DummySignMask)) { // No truncation, extended load, so signedness check is unreliable. IdiomCode = 20; SuppressSignednessCheck = true; } } if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } } else if (DefIsSigned && UseIsSigned) { // S => S case above. Emit CHECK TRUNCATION SIGNED annotation. if (!SuppressTruncation) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION SIGNED %zu %s %zu %s", (unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth, MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp)); if (HasSinkString) { SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++TruncationAnnotationsCount; #endif } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION SIGNED %zu %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth, MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp), TruncationIdiomCode, disasm); } } else { // S => ?, ? => S, ? => ? cases above: CHECK TRUNCATION UNKNOWNSIGN annotation. if (!SuppressTruncation) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK TRUNCATION UNKNOWNSIGN %zu %s %zu %s", (unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth, MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp)); if (HasSinkString) { SMP_fprintf(InfoAnnotFile, " ZZ %s %s \n", SinkString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++TruncationAnnotationsCount; #endif } else { SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR CHECK TRUNCATION UNKNOWNSIGN %6zu %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), SourceDefBitWidth, MDGetRegName(SearchOp), UseBitWidth, MDGetRegName(UseOp), TruncationIdiomCode, disasm); } } #if 1 // Now check for signedness conflicts between the UseOp USEs and its DEF. if (!OutArgsWrite && !PartialStore) { // Inferred signedness of outargs location is invalid anyway if (!SuppressSignednessCheck && (0 == IdiomCode)) { unsigned short DummySignMask; if ((0 != TruncationIdiomCode) && this->MDIsSignedLoad(DummySignMask)) { // No reliable truncation, extended load, so signedness check is unreliable. IdiomCode = 20; SuppressSignednessCheck = true; } } if (UseIsSigned && SourceDefIsUnsigned) { if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } else if (UseIsUnsigned && SourceDefIsSigned) { // Currently same annotation, but might differ in the future for better forensics // and more precise diagnostic messages. if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } else if ((!SourceDefSignMixed) && UseSignMixed) { // DEF has consistent and known signedness, USE is inconsistent. if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[SourceDefSignMask], UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), SignednessStrings[SourceDefSignMask], UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } } #if SMP_MEASURE_NUMERIC_ANNOTATIONS if (SuppressSignednessCheck || (0 < IdiomCode)) { ++SuppressSignednessOnTruncation; } #endif #endif } // end if truncation else if (!IgnoreOutArgsWrite && !PartialStore) { // still need to check for signedness errors even if no truncation if (!SuppressSignednessCheck && (0 == IdiomCode)) { unsigned short DummySignMask; if (this->MDIsSignedLoad(DummySignMask)) { // No truncation, extended load, so signedness check is unreliable. IdiomCode = 20; SuppressSignednessCheck = true; } } if (this->IsUnsignedArg()) { DefIsUnsigned = true; } if (UseIsSigned && DefIsUnsigned) { if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } else if (UseIsUnsigned && DefIsSigned) { // Currently UNSIGNED and SIGNED annotations for signedness differ only in the // arithmetic saturation value applied as a recovery action. UNSIGNED means // left-hand-side is UNSIGNED so saturate a negative right-hand-side up to 0, // while SIGNED means lhs is SIGNED so saturate large rhs to 0x7fff.... // For inconsistent sign cases we default to SIGNED. if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } else if (UseIsSigned && SourceDefIsUnsigned) { if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS UNSIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } else if (UseIsUnsigned && SourceDefIsSigned) { // Currently same annotation, but might differ in the future for better forensics // and more precise diagnostic messages. if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), IdiomCode, disasm); } } #if 0 else if ((!SourceDefSignMixed) && UseSignMixed) { // source DEF has consistent and known signedness, source USE is inconsistent. SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK SIGNEDNESS SIGNED %u %s ZZ %s \n", (unsigned long long)this->GetAddr(), this->GetSize(), UseBitWidth, MDGetRegName(UseOp), disasm); } #endif #if SMP_MEASURE_NUMERIC_ANNOTATIONS if (SuppressSignednessCheck && (0 == IdiomCode)) { ; } else if (!SuppressSignednessCheck && (0 == IdiomCode)) { ++SignednessWithoutTruncationCount; } else { ++SuppressSignednessOnTruncation; } #endif } // end if truncation else check signedness } // end of cases 4-5, (3 == OptType) checking for TRUNCATION and SIGNEDNESS errors else if (case6) { // Case 6: Load Effective Address opcodes can do arithmetic that silently overflows. this->MDEmitLeaOpcodeOverflowAnnotations(InfoAnnotFile, LoopList); } // end of case 6, LoadEffectiveAddress instruction else if (case7) { // case 7: half of register is sign-extended into the full register. // Potential truncation error if entire register was DEFed first, because // only the lower half is used. That also makes a potential signedness // error, because the "sign bit" that is being extended is really a data bit, // not a sign bit. DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); DefOp = DefIter->GetOp(); assert(DefOp->IsRegOp()); SSANum = DefIter->GetSSANum(); DefHashValue = HashGlobalNameAndSSA(DefOp, SSANum); UseIter = this->GetFirstUse(); assert(UseIter != this->GetLastUse()); UseOp = UseIter->GetOp(); assert(UseOp->IsRegOp()); SSANum = UseIter->GetSSANum(); UseHashValue = HashGlobalNameAndSSA(UseOp, SSANum); if (this->GetBlock()->IsLocalName(DefOp)) { DefFGInfo = this->GetBlock()->GetDefFGInfo(DefHashValue); SourceDefFGInfo = this->GetBlock()->GetDefFGInfo(UseHashValue); } else { DefFGInfo = this->GetBlock()->GetFunc()->GetDefFGInfo(DefHashValue); SourceDefFGInfo = this->GetBlock()->GetFunc()->GetDefFGInfo(UseHashValue); } DefWidthInfo = DefFGInfo.SizeInfo; DefMaxBitWidth = LargestBitWidthFromMask(DefWidthInfo); // max width over all defs SourceDefWidthInfo = SourceDefFGInfo.SizeInfo; SourceDefBitWidth = LargestBitWidthFromMask(SourceDefWidthInfo); // max width over all defs // Was the USE in the width-doubling instruction originally DEFed to have more bits // than are used in the width-doubling instruction? If so, we have truncation and // signedness errors to check at run time. UseBitWidth = (DefMaxBitWidth / 2); // USE should have been DEFed with this bit width if (SourceDefBitWidth > UseBitWidth) { // Make checks signed, because of the implications of sign extension by these opcodes. SMP_fprintf(InfoAnnotFile, "%18llx %6d INSTR CHECK TRUNCATION SIGNED %zu %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), DefMaxBitWidth, MDGetRegName(DefOp), UseBitWidth, MDGetRegName(UseOp), disasm); #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++WidthDoublingTruncationCount; #endif } } // end of case 7, doubles width inside register else if (case8) { // PEASOUP wants info on memset() calls. string FuncName = this->GetTrimmedCalledFunctionName(); if (0 == FuncName.compare("memset")) { STARSOpndTypePtr MemSetTarget; std::size_t MemSetSize; int StackOffset; bool FPRelativeTarget = false; // original target before stack delta normalization if (this->GetBlock()->AnalyzeMemSet(this->GetAddr(), MemSetTarget, MemSetSize, StackOffset, FPRelativeTarget)) { if (0 < MemSetSize) { // Emit annotation. // NOTE: We want the unnormalized stack operand, so that Strata and SPRI will get // annotations that match what is seen in the assembly language. if (FPRelativeTarget) { // Must be negative offset from EBP. assert(UseFP); StackOffset -= (int) this->GetBlock()->GetFunc()->GetFramePtrStackDelta(); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSET STACKOFFSET_EBP %d SIZE %zu ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), StackOffset, MemSetSize, disasm); } else { // Must be non-negative offset from ESP. StackOffset -= this->GetStackPtrOffset(); SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR MEMSET STACKOFFSET_ESP %d SIZE %zu ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), StackOffset, MemSetSize, disasm); } } } } } // end of memset() case return; } // end of SMPInstr::EmitIntegerErrorAnnotations() #define MAX_OFFSET_STR_LEN 40 // Emit overflow annotations for lea opcodes that perform arithmetic that // can overflow without affecting the flags. void SMPInstr::MDEmitLeaOpcodeOverflowAnnotations(FILE *InfoAnnotFile, list<std::size_t> &LoopList) { set<DefOrUse, LessDefUse>::iterator UseIter, DefIter; std::size_t OpNum; int BaseReg; int IndexReg; uint16_t ScaleFactor; STARS_ea_t offset; int SignedOffset; bool ScaledIndexReg; bool SourceFound = false; bool DataPointer = false; int SSANum; SMPOperandType DefType, UseType; int UseHashValue; int IdiomCode = 0; struct FineGrainedInfo UseFGInfo, SourceDefFGInfo; unsigned short UseSignMask, SourceDefSignMask, BaseRegSignMask, TempSignMask; unsigned short BaseRegWidthInfo, UseBitWidthInfo; std::size_t BaseRegMaxWidth, IndexRegMaxWidth, TempMaxWidth; char OffsetString[MAX_OFFSET_STR_LEN]; STARSOpndTypePtr TempOp = nullptr, DefOp = nullptr; for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (TempOp->IsMemOp()) { MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset); SignedOffset = (int) offset; // IDA Pro makes offset unsigned for some reason. SourceFound = true; break; } } } assert(SourceFound); if (MDIsStackAccessOpnd(TempOp, this->BasicBlock->GetFunc()->UsesFramePointer())) { // If the lea operand is something like lea ebx,[esp+4] we do not want to waste // time checking for overflow, because stack pointers and frame pointers // are kept within integer bounds (and if not, something big and terrible will // happen long before integer bounds are overflowed or underflowed). #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++SuppressStackPtrOverflowCount; #endif return; } else { // Check for the benign overflow cases we want to ignore. DefIter = this->GetFirstNonFlagsDef(); assert(DefIter != this->GetLastDef()); DefOp = DefIter->GetOp(); SSANum = DefIter->GetSSANum(); DefType = DefIter->GetType(); DataPointer = IsDataPtr(DefType); if (this->IsHashOperation()) { IdiomCode = 15; } else if (this->GetBlock()->IsBenignOverflowDEF(DefOp, SSANum, this->GetAddr(), this->MDIsUnderflowingOpcode(), IdiomCode)) { #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++BenignOverflowDefCount; #endif ; } } if (0 == IdiomCode) { // Any overflow or underflow producing a PTROFFSET type should be suppressed. for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { DefType = DefIter->GetType(); if (IsEqType(DefType, PTROFFSET)) { IdiomCode = 19; break; } else if (IsEqType(DefType, NEGATEDPTR)) { IdiomCode = 13; break; } } } if (0 == IdiomCode) { // Any overflow or underflow using a PTROFFSET type should be suppressed. for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { UseType = UseIter->GetType(); if (IsEqType(UseType, PTROFFSET)) { IdiomCode = 19; break; } else if (IsEqType(UseType, NEGATEDPTR)) { IdiomCode = 13; break; } } } char *disasm = DisAsmText.GetDisAsm(this->GetAddr()); ScaledIndexReg = (0 < ScaleFactor); if (0 != SignedOffset) { (void) SMP_snprintf(OffsetString, MAX_OFFSET_STR_LEN-2, "%d", SignedOffset); } // Build up the computational string one operation at a time and emit // CHECK OVERFLOW annotations after each step. string CurrString(""); const char *ScaleStrings[4] = {"", "*2", "*4", "*8"}; string PtrString(""); if (IdiomCode == 0) { if (!DataPointer && (1 == LoopList.size())) { // Start with simple case of blocks only present in one loop SMPOperandType MemType = UNINIT; std::size_t Counter = 0; std::size_t LoopNum = LoopList.front(); this->GetBlock()->GetFunc()->ResetProcessedBlocks(); bool AddrRegOnly = this->GetBlock()->IsDefOnlyUsedAsAddressReg(this->GetAddr(), DefOp, LoopNum, Counter, MemType); if (AddrRegOnly && (0 < Counter)) { // Similarly, let C7 (buffer overflow/underflow) defenses handle the issues if it is only an index register. DefType = MemType; DataPointer = true; } } if (DataPointer) { if (IsEqType(STACKPTR, DefType)) PtrString = "STACKMEMSINK"; else if (IsEqType(HEAPPTR, DefType)) PtrString = "HEAPMEMSINK"; else if (IsEqType(GLOBALPTR, DefType)) PtrString = "GLOBALMEMSINK"; else PtrString = "MEMORYSINK"; IdiomCode = 18; } else { // Any overflow or underflow using a POINTER type should be suppressed. for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { UseType = UseIter->GetType(); if (IsDataPtr(UseType)) { if (IsEqType(STACKPTR, UseType)) PtrString = "STACKMEMSINK"; else if (IsEqType(HEAPPTR, UseType)) PtrString = "HEAPMEMSINK"; else if (IsEqType(GLOBALPTR, UseType)) PtrString = "GLOBALMEMSINK"; else PtrString = "MEMORYSINK"; IdiomCode = 18; break; } } } } // Gather signedness info about BaseReg, if any, that will be used in multiple cases below. if (STARS_x86_R_none != BaseReg) { STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg)); if (this->MDIsAddressing64bit()) { RegOp->SetByteWidth(8); } UseIter = this->FindUse(RegOp); assert(UseIter != this->GetLastUse()); UseHashValue = HashGlobalNameAndSSA(RegOp, UseIter->GetSSANum()); if (this->BasicBlock->IsLocalName(RegOp)) { // Local name, find in basic block maps. SourceDefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue); UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // Global name, find in global maps. SourceDefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue); UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } UseSignMask = (UseFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); SourceDefSignMask = (SourceDefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); if (UseSignMask == 0) { // Get signedness info wherever it is available. UseSignMask = SourceDefSignMask; } BaseRegSignMask = UseSignMask; if ((17 == IdiomCode) && (FG_MASK_UNSIGNED == BaseRegSignMask)) { // An IdiomCode of 17 means not a benign overflow, but an addition that // produces a jump table offset, which can be an addition of mixed signedness // that produces false positives if treated as UNSIGNED. See discussion in // SMPBasicBlock::IsBenignOverflowDEF(). BaseRegSignMask = FG_MASK_INCONSISTENT_SIGN; } BaseRegWidthInfo = (UseFGInfo.SizeInfo & FG_MASK_BITWIDTH_FIELDS); if (0 == BaseRegWidthInfo) { BaseRegWidthInfo = (SourceDefFGInfo.SizeInfo & FG_MASK_BITWIDTH_FIELDS); } BaseRegMaxWidth = LargestBitWidthFromMask(BaseRegWidthInfo); } else { BaseRegMaxWidth = 0; BaseRegSignMask = 0; } if (STARS_x86_R_none != IndexReg) { // Get signedness info for IndexReg. STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg)); if (this->MDIsAddressing64bit()) { RegOp->SetByteWidth(8); } UseIter = this->FindUse(RegOp); assert(UseIter != this->GetLastUse()); UseHashValue = HashGlobalNameAndSSA(RegOp, UseIter->GetSSANum()); if (this->BasicBlock->IsLocalName(RegOp)) { // Local name, find in basic block maps. SourceDefFGInfo = this->BasicBlock->GetDefFGInfo(UseHashValue); UseFGInfo = this->BasicBlock->GetUseFGInfo(UseHashValue); } else { // Global name, find in global maps. SourceDefFGInfo = this->BasicBlock->GetFunc()->GetDefFGInfo(UseHashValue); UseFGInfo = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue); } UseSignMask = (UseFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); SourceDefSignMask = (SourceDefFGInfo.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS); if (UseSignMask == 0) { // Get signedness info wherever it is available. UseSignMask = SourceDefSignMask; } if ((17 == IdiomCode) && (FG_MASK_UNSIGNED == UseSignMask)) { // An IdiomCode of 17 means not a benign overflow, but an addition that // produces a jump table offset, which can be an addition of mixed signedness // that produces false positives if treated as UNSIGNED. See discussion in // SMPBasicBlock::IsBenignOverflowDEF(). UseSignMask = FG_MASK_INCONSISTENT_SIGN; IdiomCode = 0; // reset; not a benign code idiom } UseBitWidthInfo = (UseFGInfo.SizeInfo & FG_MASK_BITWIDTH_FIELDS); IndexRegMaxWidth = LargestBitWidthFromMask(UseBitWidthInfo); TempSignMask = (BaseRegSignMask | UseSignMask); TempMaxWidth = (BaseRegMaxWidth >= IndexRegMaxWidth) ? BaseRegMaxWidth : IndexRegMaxWidth; if (ScaledIndexReg) { assert((ScaleFactor >= 1) && (ScaleFactor <= 3)); assert((IndexReg >= STARS_x86_R_ax) && (IndexReg <= STARS_x86_R_bh)); CurrString += MDGetRegName(RegOp); CurrString += ScaleStrings[ScaleFactor]; if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[UseSignMask], IndexRegMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[UseSignMask], IndexRegMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[UseSignMask], IndexRegMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif if (STARS_x86_R_none != BaseReg) { // Have BaseReg+IndexReg*ScaleFactor string TempStr(CurrString); CurrString.clear(); STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg)); if (this->MDIsAddressing64bit()) { RegOp->SetByteWidth(8); } CurrString += MDGetRegName(RegOp); CurrString += "+"; CurrString += TempStr; if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif } if (0 != SignedOffset) { // We have [ BaseReg + ] IndexReg*ScaleFactor+offset [BaseReg or not] // CurrString has everything through the end of the scalefactor in either case. #if 0 // easier for instrumentation to always use ADD, even for negative offsets if (0 < SignedOffset) #endif CurrString += "+"; CurrString += OffsetString; if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif } } else if (STARS_x86_R_none != BaseReg) { // We have BaseReg+IndexReg, unscaled. STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg)); if (this->MDIsAddressing64bit()) { RegOp->SetByteWidth(8); } CurrString += MDGetRegName(RegOp); CurrString += "+"; STARSOpndTypePtr IndexOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg)); if (this->MDIsAddressing64bit()) { IndexOp->SetByteWidth(8); } CurrString += MDGetRegName(IndexOp); if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif if (0 != SignedOffset) { // We have BaseReg + IndexReg + offset #if 0 // easier for instrumentation to always use ADD, even for negative offsets if (0 < SignedOffset) #endif CurrString += "+"; CurrString += OffsetString; if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif } } else if (0 != SignedOffset) { // We have just IndexReg+offset. STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) IndexReg)); if (this->MDIsAddressing64bit()) { RegOp->SetByteWidth(8); } CurrString += MDGetRegName(RegOp); #if 0 // easier for instrumentation to always use ADD, even for negative offsets if (0 < SignedOffset) #endif CurrString += "+"; CurrString += OffsetString; if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[TempSignMask], TempMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif } else { // Just IndexReg, no BaseReg or offset, so nothing to do. ; } } else if ((STARS_x86_R_none != BaseReg) && (SignedOffset != 0)) { // No index reg, scaled or otherwise. Just BaseReg+offset STARSOpndTypePtr RegOp = this->STARSInstPtr->MakeRegOpnd(MDCanonicalizeSubReg((STARS_regnum_t) BaseReg)); if (this->MDIsAddressing64bit()) { RegOp->SetByteWidth(8); } CurrString += MDGetRegName(RegOp); if (17 == IdiomCode) { IdiomCode = 0; // reset; not a benign code idiom } #if 0 // easier for instrumentation to always use ADD, even for negative offsets if (0 < SignedOffset) #endif CurrString += "+"; CurrString += OffsetString; if (IdiomCode > 0) { if (IdiomCode == 18) { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[BaseRegSignMask], BaseRegMaxWidth, CurrString.c_str(), IdiomCode, PtrString.c_str(), disasm); } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ IDIOM %d %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[BaseRegSignMask], BaseRegMaxWidth, CurrString.c_str(), IdiomCode, disasm); } } else { SMP_fprintf(InfoAnnotFile, "%18llx %6zu INSTR CHECK OVERFLOW %s %zu %s ZZ %s \n", (unsigned long long) this->GetAddr(), this->GetSize(), LeaSignednessStrings[BaseRegSignMask], BaseRegMaxWidth, CurrString.c_str(), disasm); } #if SMP_MEASURE_NUMERIC_ANNOTATIONS ++LeaInstOverflowCount; #endif } else { // Either just a BaseReg, or just an offset. Nothing to do. ; } return; } // end of SMPInstr::MDEmitLeaOpcodeOverflowAnnotations() // Get the immediate value used in the instruction. Return zero // if no immediate was used. int SMPInstr::MDGetImmedUse(void) { int ImmedVal = 0; set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { STARSOpndTypePtr UseOp = CurrUse->GetOp(); if (UseOp->IsImmedOp()) { assert(sizeof(int) <= sizeof(uintptr_t)); ImmedVal = (int) UseOp->GetImmedValue(); break; } } return ImmedVal; } // end of SMPInstr::MDGetImmedUse() // See which particular SCCP flags (carry flag, zero flag, etc.) are USEd void SMPInstr::MDGetFlagsUsed(set<int> &UsedFlags) { pair<set<int>::iterator, bool> InsertResult; switch (this->GetIDAOpcode()) { case STARS_NN_adc: // Add with Carry case STARS_NN_daa: // Decimal Adjust AL after Addition case STARS_NN_das: // Decimal Adjust AL after Subtraction case STARS_NN_jae: // Jump if Above or Equal (CF=0) case STARS_NN_jb: // Jump if Below (CF=1) case STARS_NN_jc: // Jump if Carry (CF=1) case STARS_NN_jnae: // Jump if Not Above or Equal (CF=1) case STARS_NN_jnb: // Jump if Not Below (CF=0) case STARS_NN_jnc: // Jump if Not Carry (CF=0) case STARS_NN_rcl: // Rotate Through Carry Left case STARS_NN_rcr: // Rotate Through Carry Right case STARS_NN_sbb: // Integer Subtraction with Borrow case STARS_NN_setae: // Set Byte if Above or Equal (CF=0) case STARS_NN_setb: // Set Byte if Below (CF=1) case STARS_NN_setc: // Set Byte if Carry (CF=1) case STARS_NN_setnae: // Set Byte if Not Above or Equal (CF=1) case STARS_NN_setnb: // Set Byte if Not Below (CF=0) case STARS_NN_setnc: // Set Byte if Not Carry (CF=0) case STARS_NN_cmovb: // Move if Below (CF=1) case STARS_NN_cmovnb: // Move if Not Below (CF=0) case STARS_NN_fcmovb: // Floating Move if Below case STARS_NN_fcmovnb: // Floating Move if Not Below case STARS_NN_setalc: // Set AL to Carry Flag case STARS_NN_adcx: // Unsigned Integer Addition of Two Operands with Carry Flag InsertResult = UsedFlags.insert(MD_CARRY_FLAG); break; case STARS_NN_into: // Call to Interrupt Procedure if Overflow Flag = 1 case STARS_NN_jno: // Jump if Not Overflow (OF=0) case STARS_NN_jo: // Jump if Overflow (OF=1) case STARS_NN_setno: // Set Byte if Not Overflow (OF=0) case STARS_NN_seto: // Set Byte if Overflow (OF=1) case STARS_NN_cmovno: // Move if Not Overflow (OF=0) case STARS_NN_cmovo: // Move if Overflow (OF=1) case STARS_NN_adox: // Unsigned Integer Addition of Two Operands with Overflow Flag InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG); break; case STARS_NN_ja: // Jump if Above (CF=0 & ZF=0) case STARS_NN_jbe: // Jump if Below or Equal (CF=1 | ZF=1) case STARS_NN_jna: // Jump if Not Above (CF=1 | ZF=1) case STARS_NN_jnbe: // Jump if Not Below or Equal (CF=0 & ZF=0) a.k.a. ja case STARS_NN_seta: // Set Byte if Above (CF=0 & ZF=0) case STARS_NN_setbe: // Set Byte if Below or Equal (CF=1 | ZF=1) case STARS_NN_setna: // Set Byte if Not Above (CF=1 | ZF=1) case STARS_NN_setnbe: // Set Byte if Not Below or Equal (CF=0 & ZF=0) case STARS_NN_cmova: // Move if Above (CF=0 & ZF=0) case STARS_NN_cmovbe: // Move if Below or Equal (CF=1 | ZF=1) case STARS_NN_fcmovbe: // Floating Move if Below or Equal case STARS_NN_fcmovnbe: // Floating Move if Not Below or Equal InsertResult = UsedFlags.insert(MD_CARRY_FLAG); InsertResult = UsedFlags.insert(MD_ZERO_FLAG); break; case STARS_NN_ins: // Input string; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used case STARS_NN_je: // Jump if Equal (ZF=1) case STARS_NN_jne: // Jump if Not Equal (ZF=0) case STARS_NN_jnz: // Jump if Not Zero (ZF=0) a.k.a. jne case STARS_NN_jz: // Jump if Zero (ZF=1) case STARS_NN_lods: // Load string; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used case STARS_NN_loopwe: // Loop while CX != 0 and ZF=1 case STARS_NN_loope: // Loop while rCX != 0 and ZF=1 case STARS_NN_loopde: // Loop while ECX != 0 and ZF=1 case STARS_NN_loopqe: // Loop while RCX != 0 and ZF=1 case STARS_NN_loopwne: // Loop while CX != 0 and ZF=0 case STARS_NN_loopne: // Loop while rCX != 0 and ZF=0 case STARS_NN_loopdne: // Loop while ECX != 0 and ZF=0 case STARS_NN_loopqne: // Loop while RCX != 0 and ZF=0 case STARS_NN_movs: // Move Byte(s) from String to String; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used case STARS_NN_outs: // Output string; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used case STARS_NN_repe: // Repeat String Operation while ZF=1 case STARS_NN_repne: // Repeat String Operation while ZF=0 case STARS_NN_scas: // Scan String; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used case STARS_NN_sete: // Set Byte if Equal (ZF=1) case STARS_NN_setne: // Set Byte if Not Equal (ZF=0) case STARS_NN_setnz: // Set Byte if Not Zero (ZF=0) case STARS_NN_setz: // Set Byte if Zero (ZF=1) case STARS_NN_stos: // Store String; uses ZERO_FLAG if REPE/REPNE/REPZ/REPNZ prefix is used case STARS_NN_cmovnz: // Move if Not Zero (ZF=0) case STARS_NN_cmovz: // Move if Zero (ZF=1) case STARS_NN_fcmove: // Floating Move if Equal case STARS_NN_fcmovne: // Floating Move if Not Equal InsertResult = UsedFlags.insert(MD_ZERO_FLAG); break; case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) case STARS_NN_jl: // Jump if Less (SF!=OF) case STARS_NN_jnge: // Jump if Not Greater or Equal (SF != OF) ** case STARS_NN_jnl: // Jump if Not Less (SF=OF) a.k.a. jge case STARS_NN_setge: // Set Byte if Greater or Equal (SF=OF) case STARS_NN_setl: // Set Byte if Less (SF!=OF) case STARS_NN_setnge: // Set Byte if Not Greater or Equal (SF!=OF) case STARS_NN_setnl: // Set Byte if Not Less (SF=OF) case STARS_NN_cmovge: // Move if Greater or Equal (SF=OF) case STARS_NN_cmovl: // Move if Less (SF!=OF) InsertResult = UsedFlags.insert(MD_SIGN_FLAG); InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG); break; case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) a.k.a. jle case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) a.k.a. jg case STARS_NN_setg: // Set Byte if Greater (ZF=0 & SF=OF) case STARS_NN_setle: // Set Byte if Less or Equal (ZF=1 | SF!=OF) case STARS_NN_setng: // Set Byte if Not Greater (ZF=1 | SF!=OF) case STARS_NN_setnle: // Set Byte if Not Less or Equal (ZF=0 & SF=OF) case STARS_NN_cmovg: // Move if Greater (ZF=0 & SF=OF) case STARS_NN_cmovle: // Move if Less or Equal (ZF=1 | SF!=OF) InsertResult = UsedFlags.insert(MD_ZERO_FLAG); InsertResult = UsedFlags.insert(MD_SIGN_FLAG); InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG); break; case STARS_NN_jns: // Jump if Not Sign (SF=0) case STARS_NN_js: // Jump if Sign (SF=1) case STARS_NN_setns: // Set Byte if Not Sign (SF=0) case STARS_NN_sets: // Set Byte if Sign (SF=1) case STARS_NN_cmovns: // Move if Not Sign (SF=0) case STARS_NN_cmovs: // Move if Sign (SF=1) InsertResult = UsedFlags.insert(MD_SIGN_FLAG); break; case STARS_NN_jnp: // Jump if Not Parity (PF=0) case STARS_NN_jp: // Jump if Parity (PF=1) InsertResult = UsedFlags.insert(MD_PARITY_FLAG); break; case STARS_NN_lahf: // Load Flags into AH Register InsertResult = UsedFlags.insert(MD_CARRY_FLAG); InsertResult = UsedFlags.insert(MD_ZERO_FLAG); InsertResult = UsedFlags.insert(MD_SIGN_FLAG); break; case STARS_NN_pushfw: // Push Flags Register onto the Stack case STARS_NN_pushf: // Push Flags Register onto the Stack case STARS_NN_pushfd: // Push Flags Register onto the Stack (use32) case STARS_NN_pushfq: // Push Flags Register onto the Stack (use64) InsertResult = UsedFlags.insert(MD_CARRY_FLAG); InsertResult = UsedFlags.insert(MD_ZERO_FLAG); InsertResult = UsedFlags.insert(MD_SIGN_FLAG); InsertResult = UsedFlags.insert(MD_OVERFLOW_FLAG); break; default: if (SMPUsesFlags[this->GetIDAOpcode()]) { SMP_msg("ERROR: SCCP: Unknown flags USEd in instruction opcode at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } break; } // end switch on opcode return; } // end of SMPInstr::MDGetFlagsUsed() // Get funcname from call inst and remove "." and "_" prefices. // Asserts if this is not a call instruction. string SMPInstr::GetTrimmedCalledFunctionName(void) { SMPitype DFType = this->GetDataFlowType(); assert((CALL == DFType) || (INDIR_CALL == DFType) || this->IsTailCall()); STARS_ea_t FuncAddr = this->GetCallTarget(); char IDA_func_name[STARS_MAXSTR]; std::size_t SkipCount; char *TempFuncName; if (CALL == DFType) { // We should have a good call target for direct calls. if (STARS_BADADDR != FuncAddr) { (void) SMP_get_func_name(FuncAddr, IDA_func_name, (std::size_t)(STARS_MAXSTR - 1)); SkipCount = strspn(IDA_func_name, "._"); TempFuncName = &(IDA_func_name[SkipCount]); string FuncName(TempFuncName); return FuncName; } else { string FuncName("syscall"); return FuncName; } } else { // INDIR_CALL // We might have a resolved call target for indirect calls. if (STARS_BADADDR != FuncAddr) { // We have a resolved address for the indirect call. (void) SMP_get_func_name(FuncAddr, IDA_func_name, (std::size_t)(STARS_MAXSTR - 1)); SkipCount = strspn(IDA_func_name, "._"); TempFuncName = &(IDA_func_name[SkipCount]); string IndirFuncName(TempFuncName); return IndirFuncName; } else { // INDIR_CALL, no resolved target. string DummyFuncName("ZST_NEVER_MATCH_THIS_FUNC_NAME"); return DummyFuncName; } } } // end of SMPInstr::GetTrimmedCalledFunctionName() // Build the RTL for an instruction with a unary opcode bool SMPInstr::BuildUnaryRTL(SMPoperator UnaryOp) { std::size_t OpNum; bool DestFound = false; bool WidthDoubler = this->MDDoublesWidth(); unsigned short opcode = this->GetIDAOpcode(); SMPRegTransfer *TempRT = NULL; STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); // Handle special cases first if (SMP_UNARY_FLOATING_ARITHMETIC == UnaryOp) { // Use of the floating register stack top is implicit DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(FPRegOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetLeftOperand(FPRegOp); RightRT->SetOperator(UnaryOp); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); } else if ((STARS_NN_clc == opcode) || (STARS_NN_cld == opcode) || (STARS_NN_cmc == opcode) || (STARS_NN_stc == opcode) || (STARS_NN_std == opcode)) { // Flags register is implicit destination. DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); if (STARS_NN_cmc == opcode) { // complement carry flag USEs old carry flag RightRT->SetLeftOperand(FlagsOp); RightRT->SetOperator(SMP_BITWISE_NOT); } else { RightRT->SetLeftOperand(VoidOp); RightRT->SetOperator(UnaryOp); } RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); } for (OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; STARSOpndTypePtr LeftOp; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); if (WidthDoubler) { // Opcodes that sign-extend a byte to a word, or a word to a dword, // have only one operand. It is implicit, and it is the shorter USE. // That means the DEF op will have the same width as the USE op, e.g. if // we are sign-extending AX to EAX, the USE op and DEF op will both be AX // without a special fix. We fix this problem with the DEF operand now. LeftOp = TempOp->clone(); uint16_t CurrByteWidth = LeftOp->GetByteWidth(); if ((1 == CurrByteWidth) || (2 == CurrByteWidth) || (4 == CurrByteWidth)) { LeftOp->DoubleRegWidth(); } else { SMP_msg("ERROR: Instruction operand %zu not 1,2, or 4 bytes at %llx ; Width: %u\n", OpNum, (unsigned long long) this->GetAddr(), LeftOp->GetByteWidth()); } } else { // No need to clone; we won't alter the operand by doubling it LeftOp = TempOp; } TempRT->SetLeftOperand(LeftOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(UnaryOp); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); } } } // end for (OpNum = 0; ...) #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find unary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } #endif return DestFound; } // end of SMPInstr::BuildUnaryRTL() #if 0 // Cleaner, no special-case version of BuildUnary2OpndRTL() // Build the RTL for an instruction of the form dest := unary_operator(src), with src != dest bool SMPInstr::BuildUnaryTwoOperandRTL(SMPoperator UnaryOp) { std::size_t OpNum; bool DestFound = false; bool SrcFound = false; STARSOpndTypePtr DestOp = nullptr, SrcOp = nullptr; SMPRegTransfer *TempRT = NULL; STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); for (OpNum = 0; (!(DestFound && SourceFound)) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; DestOp = TempOp; } } else { // not dest, see if valid source if (MDKnownOperandType(TempOp)) { SourceFound = true; SrcOp = TempOp; } } } // end for (OpNum = 0; ...) if (DestFound && SourceFound) { TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(DestOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetLeftOperand(SrcOp); RightRT->SetOperator(UnaryOp); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); } #if SMP_DEBUG_BUILD_RTL else { SMP_msg("ERROR: Could not find unary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } #endif return DestFound; } // end of SMPInstr::BuildUnaryTwoOperandRTL() #endif // Build the RTL for an instruction with a binary arithmetic opcode bool SMPInstr::BuildBinaryRTL(SMPoperator BinaryOp, bool HiddenFPStackOp) { std::size_t OpNum; unsigned short opcode = this->GetIDAOpcode(); bool DestFound = false; bool SourceFound = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); // Work around IDA pro error; they assumed that the pcmpeq/ne/gt/ge/lt/le // families of instructions were just compares, so they do not tag // either operand as a DEF. Actually, the first operand has byte or // word or dword fields set to all 1's or all 0's based on the result // of the comparison. bool SrcIsReallyDest = ((SMP_COMPARE_EQ_AND_SET <= BinaryOp) && (SMP_COMPARE_LE_AND_SET >= BinaryOp)); bool StackPointerModification = false; // SP := SP SMP_BITWISE_AND operand bool NeedsGuard = ((STARS_NN_arpl == opcode) || (STARS_NN_bound == opcode)); bool BuildOnlySignalRT = (STARS_NN_bound == opcode); SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; SMPGuard *Guard1 = NULL; RightRT->SetParentInst(this); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG); // floating point register stack // Handle special cases first if (NeedsGuard) { // Need a guard in the RTL. Guard1 = new SMPGuard; Guard1->SetOperator(SMP_U_COMPARE); } else if (HiddenFPStackOp) { // Use of the floating register stack top is implicit DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(FPRegOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(FPRegOp); RightRT->SetOperator(BinaryOp); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); } for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if ((this->STARSInstPtr->IsDefOpnd(OpNum)) || (SrcIsReallyDest && (0 == OpNum))) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { // See comments just below for floating point sources. FP stores // are analogous to FP loads. if (!MemDest || (IsMemOperand(TempOp))) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); if (!BuildOnlySignalRT) { TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); } if (this->IsRegClearIdiom()) { STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); TempRT->SetRightOperand(ZeroOp); SourceFound = true; // cause loop exit } else { if (!BuildOnlySignalRT) { RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); if (TempOp->MatchesReg(MD_STACK_POINTER_REG) && (SMP_BITWISE_AND == BinaryOp)) { StackPointerModification = true; // searching for SP := SP AND immediate } } if (NeedsGuard) { Guard1->SetLeftOperand(TempOp); TempRT->SetGuard(Guard1); } } } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: Skipping DEF operand: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else if (DestFound && (!HiddenFPStackOp)) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("ERROR: Found two DEF operands: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (!SourceFound && MDKnownOperandType(TempOp)) { // If this is a floating point instruction with the fpregs listed as // a USE and a memory operand also listed as a USE, then we want to // ignore the irrelevant USE of the fpreg stack. // Note that MemDest AND MemSrc means something like add mem,reg is being // processed, where the memory operand is both DEF and USE. if (!MemSrc || MemDest || (IsMemOperand(TempOp))) { SourceFound = true; if (!BuildOnlySignalRT) { RightRT->SetRightOperand(TempOp); if (StackPointerModification && (TempOp->IsImmedOp())) { this->SetStackAlignmentInst(); } } } else { SMP_msg("ERROR: Operand not processed as USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } if (NeedsGuard) { Guard1->SetRightOperand(TempOp); } } if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else delete RightRT; #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else { SMP_msg("ERROR: Could not find binary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } else { if (BuildOnlySignalRT) { TempRT->SetLeftOperand(VoidOp); TempRT->SetRightOperand(VoidOp); TempRT->SetOperator(SMP_SIGNAL); delete RightRT; } this->RTL.push_back(TempRT); // The "p" at the end of the opcode indicates that the floating point // register stack gets popped. if ((STARS_NN_fstp == opcode) || (STARS_NN_fbstp == opcode) || (STARS_NN_fistp == opcode)) { this->RTL.ExtraKills.push_back(FPRegOp); } } return (DestFound && SourceFound); } // end of SMPInstr::BuildBinaryRTL() // helper for BuildRTL(); dest := src1 oper src2 bool SMPInstr::BuildBinary3OpndRTL(SMPoperator BinaryOp) { std::size_t OpNum; unsigned short opcode = this->GetIDAOpcode(); bool DestFound = false; bool Source1Found = false; bool Source2Found = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); for (OpNum = 0; !(DestFound && Source1Found && Source2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { if (!MemDest || (IsMemOperand(TempOp))) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); if (this->IsRegClearIdiom()) { STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); TempRT->SetRightOperand(ZeroOp); Source1Found = Source2Found = true; // cause loop exit } else { RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: Skipping DEF operand: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else if (DestFound) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("ERROR: Found two DEF operands: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // Fall through from DEF to USE check, as an operand could be both in a three-operand opcode. if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (!Source1Found && MDKnownOperandType(TempOp)) { Source1Found = true; RightRT->SetLeftOperand(TempOp); } else if (!Source2Found && Source1Found && MDKnownOperandType(TempOp)) { Source2Found = true; RightRT->SetRightOperand(TempOp); } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !Source1Found || !Source2Found) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else delete RightRT; #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else { SMP_msg("ERROR: Could not find binary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } else { this->RTL.push_back(TempRT); } return (DestFound && Source1Found && Source2Found); } // end of SMPInstr::BuildBinary3OpndRTL() // helper for BuildRTL(); dest := (src1 * src2) +/- src3 bool SMPInstr::BuildMultAddOrSub4OpndRTL(SMPoperator BinaryOp1, SMPoperator BinaryOp2) { bool DestFound = false; bool Source1Found = false; bool Source2Found = false; bool Source3Found = false; // RTL shape will be dest := (src3 SMP_ADD (src1 * src2)) or (src3 SMP_NEGATE_AND_ADD (src1 * src2)) // where the first operator is whatever is in BinaryOp2 and * is whatever is in BinaryOp1. // The SMP_NEGATE_AND_ADD is needed because the RTL shape must grow with right tree and no left trees. SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; SMPRegTransfer *RightRightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRightRT->SetParentInst(this); for (size_t OpNum = 0; !(DestFound && Source1Found && Source2Found && Source3Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetOperator(BinaryOp2); TempRT->SetRightTree(RightRT); RightRightRT->SetOperator(BinaryOp1); RightRT->SetRightTree(RightRightRT); } else if (DestFound) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("ERROR: Found two DEF operands: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // end if DEF ... else if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (!Source1Found && MDKnownOperandType(TempOp)) { Source1Found = true; RightRightRT->SetLeftOperand(TempOp); } else if (!Source2Found && Source1Found && MDKnownOperandType(TempOp)) { Source2Found = true; RightRightRT->SetRightOperand(TempOp); } else if (!Source3Found && Source2Found && MDKnownOperandType(TempOp)) { Source3Found = true; RightRT->SetLeftOperand(TempOp); } } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } // end if USE ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !Source1Found || !Source2Found || !Source3Found) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else delete RightRT; #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else { SMP_msg("ERROR: Could not find binary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } else { this->RTL.push_back(TempRT); } return (DestFound && Source1Found && Source2Found && Source3Found); } // end of SMPInstr::BuildMultAddOrSub4OpndRTL() // Build the RTL for a signal/exception raised based on a guarded comparison of operands bool SMPInstr::BuildGuardedSignalRTL(SMPoperator SignalOp) { std::size_t OpNum; bool Source1Found = false; bool Source2Found = false; SMPRegTransfer *TempRT = NULL; SMPGuard *Guard1 = new SMPGuard; STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); Guard1->SetOperator(SMP_U_COMPARE); for (OpNum = 0; !(Source1Found && Source2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: Skipping DEF operand: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (!Source1Found && MDKnownOperandType(TempOp)) { Source1Found = true; Guard1->SetLeftOperand(TempOp); } else if ((!Source2Found) && MDKnownOperandType(TempOp)) { Source2Found = true; Guard1->SetRightOperand(TempOp); } if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!Source1Found || !Source2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL if (!Source1Found) { SMP_msg("ERROR: Could not find first USE operand for BOUND at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else { SMP_msg("ERROR: Could not find second USE operand for BOUND at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } this->PrintOperands(); #endif delete Guard1; } else { TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(VoidOp); TempRT->SetRightOperand(VoidOp); TempRT->SetOperator(SignalOp); TempRT->SetGuard(Guard1); this->RTL.push_back(TempRT); } return (Source1Found && Source2Found); } // end of SMPInstr::BuildGuardedSignalRTL() // bool BuildUnary2OpndPlusImmedRTL(SMPoperator UnaryOp, SMPoperator ImmedOp); // helper for BuildRTL() // Build the RTL for an instruction with a binary arithmetic opcode plus an operator to apply to // the two source-only operands, one of which is an immediate value. bool SMPInstr::BuildBinaryPlusImmedRTL(SMPoperator BinaryOp, SMPoperator ImmedOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool ImmedFound = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; SMPRegTransfer *ImmedRT = new SMPRegTransfer; RightRT->SetParentInst(this); ImmedRT->SetParentInst(this); for (OpNum = 0; !(DestFound && SourceFound && ImmedFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { if (!MemDest || (IsMemOperand(TempOp))) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: Skipping DEF operand: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else if (DestFound) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("ERROR: Found two DEF operands: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (!SourceFound && MDKnownOperandType(TempOp)) { if (!MemSrc || (IsMemOperand(TempOp))) { SourceFound = true; ImmedRT->SetLeftOperand(TempOp); } } else if (!ImmedFound && (TempOp->IsImmedOp())) { ImmedFound = true; ImmedRT->SetRightOperand(TempOp); ImmedRT->SetOperator(ImmedOp); RightRT->SetRightTree(ImmedRT); } if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound || !ImmedFound) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else { delete RightRT; if (!ImmedFound) delete ImmedRT; } #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else if (!ImmedFound) { SMP_msg("ERROR: Could not find immediate operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } else { SMP_msg("ERROR: Could not find binary USE operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound && ImmedFound); } // end of SMPInstr::BuildBinaryPlusImmedRTL() // Build the RTL for an instruction with a binary arithmetic opcode, ignoring a third operand // which is an immediate value which is a control word for packed operations (e.g. SSE, XMM). bool SMPInstr::BuildBinaryIgnoreImmedRTL(SMPoperator BinaryOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool ImmedFound = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); unsigned short opcode = this->GetIDAOpcode(); bool ECXDest = ((STARS_NN_pcmpestri == opcode) || (STARS_NN_pcmpistri == opcode)); bool XMM0Dest = ((STARS_NN_pcmpestrm == opcode) || (STARS_NN_pcmpistrm == opcode)); bool SrcIsReallyDest = (ECXDest || XMM0Dest); // Dest is implicit, so ASM only has source operand SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); for (OpNum = 0; !(DestFound && SourceFound && ImmedFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if ((this->STARSInstPtr->IsDefOpnd(OpNum)) || (SrcIsReallyDest && (0 == OpNum))) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { if (!MemDest || (IsMemOperand(TempOp))) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); if (ECXDest) { STARSOpndTypePtr ECXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); TempRT->SetLeftOperand(ECXOp); } else if (XMM0Dest) { STARSOpndTypePtr XMMOp = this->STARSInstPtr->MakeXMMRegOpnd(STARS_x86_R_xmm0); TempRT->SetLeftOperand(XMMOp); } else { TempRT->SetLeftOperand(TempOp); } TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: Skipping DEF operand: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else if (DestFound) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("ERROR: Found two DEF operands: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (!SourceFound && MDKnownOperandType(TempOp)) { if (!MemSrc || (IsMemOperand(TempOp))) { SourceFound = true; RightRT->SetRightOperand(TempOp); } } else if (!ImmedFound && (TempOp->IsImmedOp())) { ImmedFound = true; } if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound || !ImmedFound) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else delete RightRT; #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find binary DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else if (!ImmedFound) { SMP_msg("ERROR: Could not find immediate operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } else { SMP_msg("ERROR: Could not find binary USE operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound && ImmedFound); } // end of SMPInstr::BuildBinaryIgnoreImmedRTL() // Build the RTL for a load-effective-address instruction. bool SMPInstr::BuildLeaRTL(void) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool EIPRelativeAddr = false; STARSOpndTypePtr DefOp = nullptr; STARSOpndTypePtr UseOp = nullptr; SMPRegTransfer *AssignRT = NULL; int BaseReg; int IndexReg; uint16_t ScaleFactor; STARS_ea_t offset; bool ScaledIndexReg; for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF DefOp = TempOp; DestFound = true; assert(DefOp->IsRegOp()); } else { // USE if (!SourceFound && MDKnownOperandType(TempOp)) { if (IsMemOperand(TempOp)) { SourceFound = true; UseOp = TempOp; MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset); if (TempOp->GetSegReg() == STARS_x86_R_cs) { EIPRelativeAddr = true; #if 0 // Special case of PC-relative addressing, e.g. lea edx,[eip+offset] // which is encoded by IDA Pro with no basereg but CS segreg. if (STARS_x86_R_none == BaseReg) { BaseReg = MD_INSTRUCTION_POINTER_REG; } #endif } } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: Skipping USE operand: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } if (!(this->STARSInstPtr->IsUseOpnd(OpNum))) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find lea DEF operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } else { SMP_msg("ERROR: Could not find lea USE operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } else { // Ready to build the RTL // We build the RTL down to the right, in reverse order, with any multiplication // of the index register by a scale factor at the bottom of the RTL tree. // Note that almost any combination of BaseReg, IndexReg, and offset can be present // or absent. AssignRT = new SMPRegTransfer; AssignRT->SetParentInst(this); AssignRT->SetLeftOperand(DefOp); AssignRT->SetOperator(SMP_ASSIGN); ScaledIndexReg = ((ScaleFactor > 0) && (IndexReg != STARS_x86_R_none)); STARSOpndTypePtr BaseOp = nullptr; size_t ProgramBitWidth = global_STARS_program->GetSTARS_ISA_Bitwidth(); bool DefaultToMachineWidth = ((ProgramBitWidth == 64) && this->MDIsAddressing64bit()) || ((ProgramBitWidth == 32) && this->MDIsAddressing32bit()); if (BaseReg != STARS_x86_R_none) BaseOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) BaseReg, DefaultToMachineWidth); STARSOpndTypePtr IndexOp = nullptr; if (IndexReg != STARS_x86_R_none) IndexOp = this->STARSInstPtr->MakeRegOpnd((STARS_regnum_t) IndexReg, DefaultToMachineWidth); STARSOpndTypePtr OffsetOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) offset); STARSOpndTypePtr ScaleOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) ScaleFactor); if (ScaledIndexReg) { // First, build the subtree to scale the IndexReg. SMPRegTransfer *MultRT = new SMPRegTransfer; MultRT->SetParentInst(this); MultRT->SetLeftOperand(IndexOp); MultRT->SetOperator(SMP_U_LEFT_SHIFT); MultRT->SetRightOperand(ScaleOp); // Now, case on the possibilities for existence of the other address fields. if (0 != offset) { // Add the offset to the scaled index subtree. SMPRegTransfer *AddOffRT = new SMPRegTransfer; AddOffRT->SetParentInst(this); AddOffRT->SetLeftOperand(OffsetOp); AddOffRT->SetOperator(SMP_ADD); AddOffRT->SetRightTree(MultRT); // Add a BaseReg, if any. if (STARS_x86_R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; AddBaseRT->SetParentInst(this); AddBaseRT->SetLeftOperand(BaseOp); AddBaseRT->SetOperator(SMP_ADD); AddBaseRT->SetRightTree(AddOffRT); // Link into assignment root tree. AssignRT->SetRightTree(AddBaseRT); } else { // no BaseReg AssignRT->SetRightTree(AddOffRT); } } // end if nonzero offset else { // no offset to add // Add a BaseReg, if any. if (STARS_x86_R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; AddBaseRT->SetParentInst(this); AddBaseRT->SetLeftOperand(BaseOp); AddBaseRT->SetOperator(SMP_ADD); AddBaseRT->SetRightTree(MultRT); // Link into assignment root tree. AssignRT->SetRightTree(AddBaseRT); } else { // no BaseReg AssignRT->SetRightTree(MultRT); } } } // end if ScaleIndexReg else { // no scaled index register if (0 != offset) { if (STARS_x86_R_none != IndexReg) { SMPRegTransfer *AddOffRT = new SMPRegTransfer; AddOffRT->SetParentInst(this); AddOffRT->SetLeftOperand(OffsetOp); AddOffRT->SetOperator(SMP_ADD); AddOffRT->SetRightOperand(IndexOp); // Add BaseReg, if any. if (STARS_x86_R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; AddBaseRT->SetParentInst(this); AddBaseRT->SetLeftOperand(BaseOp); AddBaseRT->SetOperator(SMP_ADD); AddBaseRT->SetRightTree(AddOffRT); // Link into assignment root tree. AssignRT->SetRightTree(AddBaseRT); } else { // no BaseReg AssignRT->SetRightTree(AddOffRT); } } // end if valid IndexReg else { // no IndexReg // Add BaseReg, if any. if (STARS_x86_R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; AddBaseRT->SetParentInst(this); AddBaseRT->SetLeftOperand(BaseOp); AddBaseRT->SetOperator(SMP_ADD); AddBaseRT->SetRightOperand(OffsetOp); // Link into assignment root tree. AssignRT->SetRightTree(AddBaseRT); } else { // no BaseReg, no IndexReg, just offset? if (!UseOp->IsStaticMemOp()) { SMP_msg("WARNING: lea used as move at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } AssignRT->SetRightOperand(OffsetOp); } } } // end if nonzero offset else { // no offset if ((STARS_x86_R_none == BaseReg) || (STARS_x86_R_none == IndexReg)) { SMP_msg("WARNING: lea used as move at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); if (STARS_x86_R_none != BaseReg) { AssignRT->SetRightOperand(BaseOp); } else { if (STARS_x86_R_none == IndexReg) { // Should be RegClearIdiom in this case, no longer Lea RTL assert(this->IsRegClearIdiom()); STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); AssignRT->SetRightOperand(ZeroOp); } else { AssignRT->SetRightOperand(IndexOp); } } } else { // we have a BaseReg and an IndexReg, unscaled, no offset SMPRegTransfer *AddBaseRT = new SMPRegTransfer; AddBaseRT->SetParentInst(this); AddBaseRT->SetLeftOperand(BaseOp); AddBaseRT->SetOperator(SMP_ADD); AddBaseRT->SetRightOperand(IndexOp); // Link into assignment root tree. AssignRT->SetRightTree(AddBaseRT); } } // end if nonzero offset ... else ... } // end if (ScaledIndexReg) ... else ... this->RTL.push_back(AssignRT); } return (DestFound && SourceFound); } // end of SMPInstr::BuildLeaRTL() // Build the RTL for an double-word shift instruction bool SMPInstr::BuildDoubleShiftRTL(SMPoperator BinaryOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool CountFound = false; SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); SMPRegTransfer *LowerRightRT = new SMPRegTransfer; LowerRightRT->SetParentInst(this); // The doubleword shifts operate as follows: shift the DEF register right or left by // the number of bits specified by the count, and shift in bits from the USE register, // but do not change the USE register. This is hard to represent accurately in an RTL, // so we create an RTL as follows: // // ASSIGN // / \ tree // DEF SHIFT // / \ tree // DEF SHIFT // / \ tree RTL // USE count // // This records all the operands, but it makes it look like the result of the // lower shift is the counter for the upper shift, which is unintentional and // will have to be special cased. In all single word shifts, the lower shift // subtree would be replaced by a single count operand. The presence of a sub-tree // instead of an operand is the identifying marker for double-word shifts. STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); for (OpNum = 0; !(DestFound && SourceFound && CountFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); LowerRightRT->SetOperator(BinaryOp); RightRT->SetRightTree(LowerRightRT); } } else { // USE if (MDKnownOperandType(TempOp)) { if (!SourceFound) { SourceFound = true; LowerRightRT->SetLeftOperand(TempOp); } else { CountFound = true; LowerRightRT->SetRightOperand(TempOp); } } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound || !CountFound) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find double-shift operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); // The carry flag gets the last shifted out bit. this->RTL.ExtraKills.push_back(FlagsOp); } return (DestFound && SourceFound && CountFound); } // end of SMPInstr::BuildDoubleShiftRTL() // Build the RTL for a multiply or divide, which can have implicit EAX and/or EDX operands bool SMPInstr::BuildMultiplyDivideRTL(SMPoperator BinaryOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool x86ImulCase = (BinaryOp == SMP_S_MULTIPLY); bool ThreeOperandCase = false; bool DivisionCase = ((BinaryOp == SMP_S_DIVIDE) || (BinaryOp == SMP_U_DIVIDE)); bool ImplicitDEFs = false; bool InvisibleOperand = false; SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); if (x86ImulCase) { // Detect three-operand case of x86 imul, with reg1 := reg2 * immediate. for (OpNum = 0; (!ThreeOperandCase) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if ((nullptr == TempOp) || TempOp->IsVoidOp()) // finished processing operands break; ThreeOperandCase = TempOp->IsImmedOp(); } } bool FinishedOperands = false; bool ImmedFound = false; bool ByteSourceOperand = false; for (OpNum = 0; (!FinishedOperands) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if ((nullptr == TempOp) || TempOp->IsVoidOp()) { // finished processing operands break; } if (!TempOp->IsVisible()) { // hidden operand InvisibleOperand = true; } if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF // Three-operand case: opnd1 := opnd2 * immed // Two-operand case: opnd1 := opnd1 * opnd2, overflow bits to RDX or discarded if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); if (!ThreeOperandCase) { RightRT->SetLeftOperand(TempOp); } RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } } if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; if (TempOp->IsImmedOp()) { assert(ThreeOperandCase); ImmedFound = true; RightRT->SetRightOperand(TempOp); } else { ByteSourceOperand = (1 == TempOp->GetByteWidth()); if (ThreeOperandCase) { RightRT->SetLeftOperand(TempOp); } else if ((0 == OpNum) && DestFound) { // e.g. RAX := RAX / RCX; processing RAX as both DEF and USE RightRT->SetLeftOperand(TempOp); SourceFound = false; // keep looking for divisor or multiplier } else { RightRT->SetRightOperand(TempOp); } } } } // x86ImulCase can have three operands, need to see VoidOp in order to be sure we saw all operands. FinishedOperands = (ThreeOperandCase) ? (DestFound && SourceFound && ImmedFound) : (DestFound && SourceFound); } // end for (OpNum = 0; ...) if (!FinishedOperands) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else delete RightRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find multiply/divide operand at %p for %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // See the x86 ISA manuals for DIV, IDIV, IMUL, MUL opcodes to see all the cases. ImplicitDEFs = x86ImulCase ? (!ByteSourceOperand && InvisibleOperand) : (!ByteSourceOperand); // IRDB does not have the invisible operands, but it has an implicit DEFs field. if (!ImplicitDEFs) { ImplicitDEFs = this->STARSInstPtr->HasImplicitlyModifiedRegs(); } this->RTL.push_back(TempRT); if (ImplicitDEFs) { // Need another effect for EDX, which was implicit. // Make a deep copy from existing EAX effect and change EAX dest to EDX. // For divisions, we also deep copy EAX effect and change EAX source to EDX. SMPRegTransfer *EDXRT = new SMPRegTransfer; EDXRT->SetParentInst(this); SMPRegTransfer *EDXRightRT = new SMPRegTransfer; EDXRightRT->SetParentInst(this); STARSOpndTypePtr EDXOp = TempRT->GetLeftOperand()->clone(); size_t SourceByteWidth = EDXOp->GetByteWidth(); EDXRT->SetOperator(SMP_ASSIGN); assert(EDXOp->MatchesReg(STARS_x86_R_ax)); EDXOp->SetReg(STARS_x86_R_dx); EDXOp->SetByteWidth(SourceByteWidth); // undo possible width change in SetReg() EDXRT->SetLeftOperand(EDXOp); STARSOpndTypePtr SourceOp = RightRT->GetLeftOperand(); if ((STARS_NN_div == this->GetIDAOpcode()) || (STARS_NN_idiv == this->GetIDAOpcode())) { // Need to change left operand of RightRT to EDX. i.e. we are // changing the effect from eax := eax DIV foo to edx := edx DIV foo. assert(SourceOp->MatchesReg(STARS_x86_R_ax)); EDXRightRT->SetLeftOperand(EDXOp); } else { // just use same source operands for multiplies EDXRightRT->SetLeftOperand(SourceOp); } EDXRightRT->SetOperator(BinaryOp); EDXRightRT->SetRightOperand(RightRT->GetRightOperand()); EDXRT->SetRightTree(EDXRightRT); this->RTL.push_back(EDXRT); this->ResetMultiplicationBitsDiscarded(); } else { // No implicit EDX effect. // If we had 8x8=>16 bit multiply with AL*op8=>AX there // is no discarding of result bits, else there is discarding. if (!ByteSourceOperand) this->SetMultiplicationBitsDiscarded(); } } return (FinishedOperands); } // end of SMPInstr::BuildMultiplyDivideRTL() // Build the RTL for an instruction with a tertiary arithmetic opcode applied to // two operands plus an implied FLAGS operand, e.g. add with carry adds the carry bit // and two operands together; rotate through carry, etc. bool SMPInstr::BuildBinaryPlusFlagsRTL(SMPoperator BinaryOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; SMPRegTransfer *TempRT = NULL; STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); SMPRegTransfer *FlagsRightRT = new SMPRegTransfer; FlagsRightRT->SetParentInst(this); for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } } else { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; FlagsRightRT->SetLeftOperand(TempOp); FlagsRightRT->SetOperator(BinaryOp); FlagsRightRT->SetRightOperand(FlagsOp); RightRT->SetRightTree(FlagsRightRT); } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { if (DestFound) delete TempRT; // also deletes linked in RightRT else delete RightRT; // will also delete FlagsRightRT if SourceFound is true if (!SourceFound) // FlagsRightRT not linked into RightRT yet delete FlagsRightRT; // .. so delete FlagsRightRT separately #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find binary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound); } // end of SMPInstr::BuildBinaryPlusFlagsRTL() #define SMP_FIRST_SET_OPCODE STARS_NN_seta #define SMP_LAST_SET_OPCODE STARS_NN_setz // Build RTL for setting 0 or 1 into a register based on flags. bool SMPInstr::BuildSetFlagIntoRegRTL(SMPoperator GuardOp, SMPoperator InvertedGuardOp) { unsigned short opcode = this->GetIDAOpcode(); assert((SMP_FIRST_SET_OPCODE <= opcode) && (SMP_LAST_SET_OPCODE >= opcode)); SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *InvertedRT = new SMPRegTransfer; InvertedRT->SetParentInst(this); bool DestFound = false; for (size_t OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { DestFound = true; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); } } } // end for (OpNum = 0; ...) if (!DestFound) { if (NULL != TempRT) delete TempRT; if (NULL != InvertedRT) delete InvertedRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find SETcc destination operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // Finish the RTLs. STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); STARSOpndTypePtr OneOp = this->STARSInstPtr->MakeImmediateOpnd(1); TempRT->SetRightOperand(OneOp); // e.g. setz al => al := 1 if GuardOp InvertedRT->SetRightOperand(ZeroOp); // e.g. setz al => al := 0 if InvertedGuardOp // As the set is conditional, set the guard expressions. assert(SMP_NULL_OPERATOR != GuardOp); assert(SMP_NULL_OPERATOR != InvertedGuardOp); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); SMPGuard *Guard1 = new SMPGuard; Guard1->SetLeftOperand(FlagsOp); Guard1->SetOperator(GuardOp); Guard1->SetRightOperand(ZeroOp); TempRT->SetGuard(Guard1); this->RTL.push_back(TempRT); SMPGuard *Guard2 = new SMPGuard; Guard2->SetLeftOperand(FlagsOp); Guard2->SetOperator(InvertedGuardOp); Guard2->SetRightOperand(ZeroOp); InvertedRT->SetGuard(Guard2); this->RTL.push_back(InvertedRT); } return (DestFound); } // end of SMPInstr::BuildSetFlagIntoRegRTL() // Build the RTL for an instruction of form dest := unary_operator(source), dest != source bool SMPInstr::BuildUnary2OpndRTL(SMPoperator UnaryOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); unsigned short opcode = this->GetIDAOpcode(); bool ExtendedMove = ((STARS_NN_movsx == opcode) || (STARS_NN_movzx == opcode) || (STARS_NN_movsxd == opcode)); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); STARSOpndTypePtr PortNumOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx); PortNumOp->SetByteWidth(2); // always DX, 16-bit STARSOpndTypePtr PortDataOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax); // Handle special cases first. if ((SMP_FIRST_SET_OPCODE <= opcode) && (SMP_LAST_SET_OPCODE >= opcode)) { // Set instructions implicitly use the flags register. SourceFound = true; RightRT->SetLeftOperand(FlagsOp); } for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; if (STARS_NN_in == opcode) { #if 0 SMP_msg("ERROR: Explicit DEF for IN from port opcode at %x : ", this->GetAddr()); PrintOperand(TempOp); SMP_msg("\n"); #endif TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(UnaryOp); } else if (STARS_NN_out == opcode) { TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(UnaryOp); } else { TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetRightOperand(VoidOp); RightRT->SetOperator(UnaryOp); TempRT->SetRightTree(RightRT); } } } else { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; if (STARS_NN_in == opcode) { TempRT->SetRightOperand(TempOp); } else if (STARS_NN_out == opcode) { #if 0 SMP_msg("ERROR: Explicit USE for OUT to port opcode at %x : ", this->GetAddr()); PrintOperand(TempOp); SMP_msg("\n"); #endif TempRT->SetRightOperand(TempOp); } else { RightRT->SetLeftOperand(TempOp); if (ExtendedMove) this->MoveSource = CloneIfNecessary(TempOp, true); } } } } // end for (OpNum = 0; ...) if (!SourceFound && (STARS_NN_in == opcode)) { // Input from port is implicitly from port # in DX register if not // specified with an immediate operand. SourceFound = true; TempRT->SetRightOperand(PortNumOp); } if (!DestFound && (STARS_NN_in == opcode)) { // Input from port is implicitly to register AL, AX, or EAX // depending on the opcode and bit width mode. // NOTE: Two different machine codes for 8-bit and 32-bit widths. // We should check and set dtyp field accordingly. DestFound = true; TempRT->SetLeftOperand(PortDataOp); TempRT->SetOperator(UnaryOp); } if (!DestFound && (STARS_NN_out == opcode)) { // Output to port is implicitly to port # in DX register if not // specified with an immediate operand. // NOTE: Two different machine codes for 8-bit and 32-bit widths. // We should check and set dtyp field accordingly. DestFound = true; TempRT->SetLeftOperand(PortNumOp); TempRT->SetOperator(SMP_ASSIGN); } if (!SourceFound && (STARS_NN_out == opcode)) { // Output to port is implicitly from register AL, AX, or EAX // depending on the opcode and bit width mode. SourceFound = true; TempRT->SetRightOperand(PortDataOp); } if (!DestFound || !SourceFound) { if (!DestFound) delete RightRT; // never linked in to TempRT if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find unary operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); if ((STARS_NN_in == opcode) || (STARS_NN_out == opcode)) delete RightRT; // unused for port I/O } return (DestFound && SourceFound); } // end of SMPInstr::BuildUnary2OpndRTL() // Build the RTL for an instruction of form: dec ECX, loop to address with optional condition code guard bool SMPInstr::BuildLoopRTL(SMPoperator GuardOp) { std::size_t OpNum; bool SourceFound = false; bool EqFlag = false; // loopeq variants bool NeqFlag = false; // loopne variants uint16_t CounterByteWidth; // width of loop counter reg (RCX, ECX, CX, CL) SMPRegTransfer *LoopRT = new SMPRegTransfer; LoopRT->SetParentInst(this); SMPRegTransfer *DecCounterRT = new SMPRegTransfer; DecCounterRT->SetParentInst(this); STARSOpndTypePtr OneOp = this->STARSInstPtr->MakeImmediateOpnd(1); STARSOpndTypePtr CountOp = nullptr; switch (this->GetIDAOpcode()) { case STARS_NN_loopw: // Loop while ECX != 0 CounterByteWidth = 4; break; case STARS_NN_loop: // Loop while CX != 0 CounterByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); break; case STARS_NN_loopd: // Loop while ECX != 0 CounterByteWidth = 4; break; case STARS_NN_loopq: // Loop while RCX != 0 CounterByteWidth = 8; break; case STARS_NN_loopwe: // Loop while CX != 0 and ZF=1 CounterByteWidth = 2; EqFlag = true; break; case STARS_NN_loope: // Loop while rCX != 0 and ZF=1 CounterByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); EqFlag = true; break; case STARS_NN_loopde: // Loop while ECX != 0 and ZF=1 CounterByteWidth = 4; EqFlag = true; break; case STARS_NN_loopqe: // Loop while RCX != 0 and ZF=1 CounterByteWidth = 8; EqFlag = true; break; case STARS_NN_loopwne: // Loop while CX != 0 and ZF=0 CounterByteWidth = 2; NeqFlag = true; break; case STARS_NN_loopne: // Loop while rCX != 0 and ZF=0 CounterByteWidth = global_STARS_program->GetSTARS_ISA_Bytewidth(); NeqFlag = true; break; case STARS_NN_loopdne: // Loop while ECX != 0 and ZF=0 CounterByteWidth = 4; NeqFlag = true; break; case STARS_NN_loopqne: // Loop while RCX != 0 and ZF=0 CounterByteWidth = 8; NeqFlag = true; break; default: SMP_msg("ERROR: Unknown loop instruction opcode at %llx in BuildLoopRTL.\n", (unsigned long long) this->GetAddr()); CounterByteWidth = 4; break; } OneOp->SetByteWidth(CounterByteWidth); if (CounterByteWidth == 1) { CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cl); } else { CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); CountOp->SetByteWidth(CounterByteWidth); } STARSOpndTypePtr EIPOp = this->STARSInstPtr->MakeRegOpnd(MD_INSTRUCTION_POINTER_REG); // All x86 loop instructions behave as follows: // 1. Decrement RCX/ECX/CX depending on 64/32/16-bit mode of CPU. // 2. If counter decremented to zero, fall through to next instruction. // 3. For condition code variants, fall through if zero flag is 1 or 0, depending on variant. // 4. Otherwise, loop back by adding a signed 8-bit offset to the instruction counter. // // So, for LOOP, it is simply decrement ECX and loop back if ECX did not become zero. // For LOOPE a.k.a. LOOPZ, it is decrement ECX and loop back if ECX != 0 and ZF == 1, which means // that ZF (zero flag) was set to 1 by an instruction before the LOOPE instruction, not by the // decrement of ECX within the microcode for LOOPE. // For LOOPNE a.k.a. LOOPNZ, change ZF == 1 to ZF == 0 in above description. // // For RTLs, this means we need an RTL to decrement ECX, and a guarded RTL to add an immediate to the EIP reg. // The guard can be simple (ECX != 0) or compound ((ECX != 0) AND (ZF is 0 or 1)). However, because RTs in // an RTL happen in parallel, we compare ECX to 1 because the comparison happens before it is decremented by // another RT in the RTL. Note also that IDA Pro has converted the signed 8-bit relative offset to a near address // in the operand list. STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); DecCounterRT->SetLeftOperand(CountOp); DecCounterRT->SetOperator(SMP_DECREMENT); DecCounterRT->SetRightOperand(VoidOp); for (OpNum = 0; (!SourceFound && (OpNum < STARS_UA_MAXOP)); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Unexpected DEF Operand in LOOP instruction: "); PrintOperand(TempOp); SMP_msg(" at %x in %s\n", this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif ; } if (!SourceFound && (this->STARSInstPtr->IsUseOpnd(OpNum)) && MDKnownOperandType(TempOp)) { if (TempOp->IsNearPointer()) { LoopRT->SetLeftOperand(EIPOp); LoopRT->SetOperator(SMP_ASSIGN); LoopRT->SetRightOperand(TempOp); SourceFound = true; } } } // end for (OpNum = 0; ...) if (!SourceFound) { if (NULL != LoopRT) delete LoopRT; if (NULL != DecCounterRT) delete DecCounterRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find loop operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // If the move is conditional, set the guard expression. // NOTE: We do not want to complicate the SMPGuard class to handle compound expressions yet. // If the need arises, we can do so. For now, just treat all loop instructions as a simple LOOP // even if it is LOOPE or LOOPNE. SMPGuard *Guard1 = new SMPGuard; Guard1->SetLeftOperand(CountOp); Guard1->SetOperator(SMP_EQUAL); Guard1->SetRightOperand(OneOp); LoopRT->SetGuard(Guard1); this->RTL.push_back(LoopRT); this->RTL.push_back(DecCounterRT); } return (SourceFound); } // end of SMPInstr::BuildLoopRTL() // Build the RTL for an instruction of form dest := source, where dest != source bool SMPInstr::BuildMoveRTL(SMPoperator GuardOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); bool AltersRSI = false; // for string operations bool AltersRDI = false; // for string operations unsigned short opcode = this->GetIDAOpcode(); SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax); STARSOpndTypePtr ALOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_al); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG); STARSOpndTypePtr PortNumOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx); STARSOpndTypePtr PortDataOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax); #if SMP_DEBUG_BUILD_RTL if (MemSrc && MemDest && (STARS_NN_movs != opcode) && (STARS_NN_movss != opcode) && (STARS_NN_movsd != opcode)) { if ((STARS_NN_stos != opcode) && (STARS_NN_outs != opcode)) { SMP_msg("ERROR: IDA Pro error: MemDest and MemSrc in move at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #if 1 else { // IDA incorrectly lists [EDI] as both DEF and USE, because reg EDI // is both DEF and USE in STARS_NN_stos. SMP_msg("WARNING: Ignoring IDA Pro error: MemDest and MemSrc in move at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); this->PrintOperands(); } #endif } #endif // First, handle special cases with implicit operands if (STARS_NN_lahf == opcode) { // load AH from flags TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(EAXOp); TempRT->SetRightOperand(FlagsOp); this->RTL.push_back(TempRT); return true; } if (STARS_NN_sahf == opcode) { // store AH to flags TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(FlagsOp); TempRT->SetRightOperand(EAXOp); this->RTL.push_back(TempRT); return true; } if ((STARS_NN_movs == opcode) || (STARS_NN_stos == opcode) || (STARS_NN_ins == opcode) || (STARS_NN_outs == opcode)) { // The ESI and EDI registers get incremented or decremented, depending // on the direction flag DF, for MOVS; only EDI for STOS and INS; // only ESI for OUTS. // This is true with or without a repeat prefix. STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si); STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di); STARSOpndTypePtr ESIMemOp = this->STARSInstPtr->MakeMemPhraseOpnd(STARS_x86_R_si, STARS_x86_R_none, 0); // [esi] STARSOpndTypePtr EDIMemOp = this->STARSInstPtr->MakeMemPhraseOpnd(STARS_x86_R_di, STARS_x86_R_none, 0); // [edi] if (STARS_NN_movs == opcode) { AltersRSI = true; AltersRDI = true; TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(EDIMemOp); TempRT->SetRightOperand(ESIMemOp); DestFound = true; SourceFound = true; } else if (STARS_NN_stos == opcode) { AltersRDI = true; TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(EDIMemOp); TempRT->SetRightOperand(ALOp); // default in case we don't find source later DestFound = true; } else if (STARS_NN_ins == opcode) { AltersRDI = true; TempRT->SetOperator(SMP_INPUT); TempRT->SetLeftOperand(EDIMemOp); TempRT->SetRightOperand(PortNumOp); DestFound = true; SourceFound = true; } else if (STARS_NN_outs == opcode) { AltersRSI = true; TempRT->SetOperator(SMP_OUTPUT); TempRT->SetLeftOperand(ESIMemOp); TempRT->SetRightOperand(PortNumOp); DestFound = true; SourceFound = true; } } // Some floating point instructions use the floating point register stack top as // an implicit source or destination, but the other operand of the load or store // is explicit, so we set the implicit operand and let control flow pass to the // main processing loop below. if ((STARS_NN_fld == opcode) || (STARS_NN_fbld == opcode) || (STARS_NN_fild == opcode)) { // Loads implicitly use the floating point stack top as destination. TempRT->SetLeftOperand(FPRegOp); TempRT->SetOperator(SMP_ASSIGN); DestFound = true; } else if ((STARS_NN_fst == opcode) || (STARS_NN_fstp == opcode) || (STARS_NN_fbstp == opcode) || (STARS_NN_fist == opcode) || (STARS_NN_fistp == opcode)) { // Stores implicitly use the floating point stack top as source TempRT->SetRightOperand(FPRegOp); SourceFound = true; // The "p" at the end of the opcode indicates that the floating point // register stack gets popped. if ((STARS_NN_fstp == opcode) || (STARS_NN_fbstp == opcode) || (STARS_NN_fistp == opcode)) { this->RTL.ExtraKills.push_back(FPRegOp); } } else if ((STARS_NN_ldmxcsr == opcode) || (STARS_NN_vldmxcsr == opcode)) { // The MMX Control & Status Register is used implicitly. STARSOpndTypePtr MXCSROp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_mxcsr); // MMX Control & Status Register TempRT->SetLeftOperand(MXCSROp); DestFound = true; } else if ((STARS_NN_stmxcsr == opcode) || (STARS_NN_vstmxcsr == opcode)) { // The MMX Control & Status Register is used implicitly. STARSOpndTypePtr MXCSROp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_mxcsr); // MMX Control & Status Register TempRT->SetRightOperand(MXCSROp); SourceFound = true; } else if (STARS_NN_fldcw == opcode) { // The FP control Register is used implicitly. STARSOpndTypePtr FPControlOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_fpctrl); // FP control Register TempRT->SetRightOperand(FPControlOp); DestFound = true; } else if ((STARS_NN_fstcw == opcode) || (STARS_NN_fnstcw == opcode)) { // The FP control Register is used implicitly. STARSOpndTypePtr FPControlOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_fpctrl); // FP control Register TempRT->SetRightOperand(FPControlOp); SourceFound = true; } else if ((STARS_NN_fstsw == opcode) || (STARS_NN_fnstsw == opcode)) { // The FP Status Register is used implicitly. STARSOpndTypePtr FPStatusOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_fpstat); // FP Status Register TempRT->SetRightOperand(FPStatusOp); SourceFound = true; } for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { // See comments just below for floating point sources. FP stores // are analogous to FP loads. if (!MemDest || (IsMemOperand(TempOp))) { DestFound = true; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); } } } else { // USE if (!SourceFound && MDKnownOperandType(TempOp)) { // If this is a floating point instruction with the fpregs listed as // a USE and a memory operand also listed as a USE, then we want to // ignore the irrelevant USE of the fpreg stack. // Note that MemDest AND MemSrc means something like stosb is being // processed, where the memory operand is both DEF and USE to IDA // for mysterious reasons. if (!MemSrc || MemDest || (IsMemOperand(TempOp))) { SourceFound = true; TempRT->SetRightOperand(TempOp); this->MoveSource = CloneIfNecessary(TempOp, true); } } if (!this->STARSInstPtr->IsUseOpnd(OpNum)) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); SMP_msg(" at %llx in %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find move operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // If the move is conditional, set the guard expression. if (SMP_NULL_OPERATOR != GuardOp) { STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); SMPGuard *Guard1 = new SMPGuard; Guard1->SetLeftOperand(FlagsOp); Guard1->SetOperator(GuardOp); Guard1->SetRightOperand(ZeroOp); TempRT->SetGuard(Guard1); } this->RTL.push_back(TempRT); // Now, create the repeat prefix effects STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); STARSOpndTypePtr FirstOpnd = this->GetOperand(0); uint16_t ByteWidth = FirstOpnd->GetByteWidth(); STARSOpndTypePtr IncrementOp = this->MakeImmediateOpnd((STARS_uval_t) ByteWidth); bool HasRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix(); if (HasRepeatPrefix) { // Must be MOVS or STOS or INS or OUTS // The repeat causes USE and DEF of ECX as a counter STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); SMPRegTransfer *CounterRT = new SMPRegTransfer; CounterRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); CounterRT->SetLeftOperand(CountOp); CounterRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(CountOp); RightRT->SetOperator(SMP_DECREMENT); RightRT->SetRightOperand(VoidOp); CounterRT->SetRightTree(RightRT); this->RTL.push_back(CounterRT); } // Depending on the opcode, we increment or decrement RSI, RDI, or both. if (AltersRSI) { STARSOpndTypePtr AddrOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si); SMPRegTransfer *AddrRT = new SMPRegTransfer; AddrRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); AddrRT->SetLeftOperand(AddrOp); AddrRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(AddrOp); // NOTE: SMP_ADD assumes default setting of DirectionFlag. RightRT->SetOperator(SMP_ADD); RightRT->SetRightOperand(IncrementOp); AddrRT->SetRightTree(RightRT); this->RTL.push_back(AddrRT); } if (AltersRDI) { STARSOpndTypePtr AddrOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di); SMPRegTransfer *AddrRT = new SMPRegTransfer; AddrRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); AddrRT->SetLeftOperand(AddrOp); AddrRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(AddrOp); // NOTE: SMP_ADD assumes default setting of DirectionFlag. RightRT->SetOperator(SMP_ADD); RightRT->SetRightOperand(IncrementOp); AddrRT->SetRightTree(RightRT); this->RTL.push_back(AddrRT); } } return (DestFound && SourceFound); } // end of SMPInstr::BuildMoveRTL() // Build the RTL for a load string instruction, which loads from DS:ESI into EAX // (or into AX or AL) and increments or decrements ESI based on the direction flag DF. bool SMPInstr::BuildLoadStringRTL(void) { bool DestFound = false; unsigned short ByteSize = 0; STARSOpndTypePtr DestOp = nullptr; for (std::size_t OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (MDKnownOperandType(TempOp)) { if ((TempOp->IsRegOp()) && (this->STARSInstPtr->IsDefOpnd(OpNum))) { // DEF DestFound = true; if (TempOp->MatchesReg(STARS_x86_R_al)) { ByteSize = 1; DestOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_al); } else if (TempOp->MatchesReg(STARS_x86_R_ax)) { ByteSize = global_STARS_program->GetSTARS_ISA_Bytewidth(); DestOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax); } else { SMP_msg("ERROR: Load string destination operand is neither AL nor EAX at %llx\n", (unsigned long long) this->GetAddr()); ByteSize = 1; // default to AL destination DestOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_al); } } } } // end for (OpNum = 0; ...) // Return false if we did not find a destination if (!DestFound) { return false; } STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); STARSOpndTypePtr OneOp = this->STARSInstPtr->MakeImmediateOpnd(1); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si); STARSOpndTypePtr DerefESIOp = this->STARSInstPtr->MakeMemPhraseOpnd(STARS_x86_R_si, STARS_x86_R_none, 0); SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *GuardedIncRT = new SMPRegTransfer; GuardedIncRT->SetParentInst(this); SMPRegTransfer *GuardedDecRT = new SMPRegTransfer; GuardedDecRT->SetParentInst(this); SMPRegTransfer *RightIncRT = new SMPRegTransfer; RightIncRT->SetParentInst(this); SMPRegTransfer *RightDecRT = new SMPRegTransfer; RightDecRT->SetParentInst(this); // Build the load string RTL. Ignore DS segment register for now. // Load string is: AL := [ESI]; if (DF == 0) ESI += 1 else ESI -= 1; // for the 8-bit case, and EAX := [ESI]; if (DF == 0) ESI += 4 else ESI -= 4; // for the 32-bit case. // AL := [ESI] or EAX := [ESI] TempRT->SetLeftOperand(DestOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(DerefESIOp); this->RTL.push_back(TempRT); // Guarded increment RTL: If the DF (Direction Flag) in EFLAGS is 0, increment ESI // by ByteSize. STARSOpndTypePtr IncDecOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) ByteSize); SMPGuard *Guard1 = new SMPGuard; Guard1->SetLeftOperand(FlagsOp); Guard1->SetOperator(SMP_U_COMPARE); Guard1->SetRightOperand(ZeroOp); GuardedIncRT->SetGuard(Guard1); GuardedIncRT->SetLeftOperand(ESIOp); GuardedIncRT->SetOperator(SMP_ASSIGN); RightIncRT->SetLeftOperand(ESIOp); RightIncRT->SetOperator(SMP_ADD); RightIncRT->SetRightOperand(IncDecOp); GuardedIncRT->SetRightTree(RightIncRT); this->RTL.push_back(GuardedIncRT); // Guarded decrement RTL: If the DF (Direction Flag) in EFLAGS is 1, decrement ESI // by ByteSize. SMPGuard *Guard2 = new SMPGuard; Guard2->SetLeftOperand(FlagsOp); Guard2->SetOperator(SMP_U_COMPARE); Guard2->SetRightOperand(OneOp); GuardedDecRT->SetGuard(Guard2); GuardedDecRT->SetLeftOperand(ESIOp); GuardedDecRT->SetOperator(SMP_ASSIGN); RightDecRT->SetLeftOperand(ESIOp); RightDecRT->SetOperator(SMP_SUBTRACT); RightDecRT->SetRightOperand(IncDecOp); GuardedDecRT->SetRightTree(RightDecRT); this->RTL.push_back(GuardedDecRT); return true; } // end of SMPInstr::BuildLoadStringRTL() // Build the RTL for a compare string instruction, possibly with repeat prefix. bool SMPInstr::BuildCompareStringRTL(void) { std::size_t OpNum; bool Src1Found = false; bool Src2Found = false; STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (MDKnownOperandType(TempOp)) { if (!Src1Found) { Src1Found = true; TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(SMP_U_COMPARE); TempRT->SetRightTree(RightRT); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF SMP_msg("CMPS 1st opnd is DEF\n"); else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE SMP_msg("CMPS 1st opnd is USE\n"); else SMP_msg("ERROR: CMPS 1st opnd neither DEF nor USE\n"); #endif } else { Src2Found = true; RightRT->SetRightOperand(TempOp); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF SMP_msg("CMPS 2nd opnd is DEF\n"); else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE SMP_msg("CMPS 2nd opnd is USE\n"); else SMP_msg("ERROR: CMPS 2nd opnd neither DEF nor USE\n"); #endif } } } // end for (OpNum = 0; ...) if (!Src1Found || !Src2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find CMPS operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); // Now, create the repeat prefix effects bool HasRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix(); if (HasRepeatPrefix) { // The repeat causes USE and DEF of ECX as a counter SMPRegTransfer *CounterRT = new SMPRegTransfer; CounterRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); CounterRT->SetLeftOperand(CountOp); CounterRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(CountOp); RightRT->SetOperator(SMP_UNARY_NUMERIC_OPERATION); RightRT->SetRightOperand(VoidOp); CounterRT->SetRightTree(RightRT); this->RTL.push_back(CounterRT); } } return (Src1Found && Src2Found); } // end of SMPInstr::BuildCompareStringRTL() // Build the RTL for an instruction of form dest := source, source := dest bool SMPInstr::BuildExchangeRTL(void) { std::size_t OpNum; bool Src1Found = false; bool Src2Found = false; SMPRegTransfer *TempRT = new SMPRegTransfer; // second effect, src := dest TempRT->SetParentInst(this); for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (MDKnownOperandType(TempOp)) { if (!Src1Found) { Src1Found = true; TempRT->SetRightOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF SMP_msg("CORRECT: XCHG 1st opnd is DEF\n"); else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE SMP_msg("WARNING: XCHG 1st opnd is USE\n"); else SMP_msg("ERROR: XCHG 1st opnd neither DEF nor USE\n"); #endif } else { Src2Found = true; TempRT->SetLeftOperand(TempOp); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF SMP_msg("WARNING: XCHG 2nd opnd is DEF\n"); else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE SMP_msg("CORRECT: XCHG 2nd opnd is USE\n"); else SMP_msg("ERROR: XCHG 2nd opnd neither DEF nor USE\n"); #endif } } } // end for (OpNum = 0; ...) if (!Src1Found || !Src2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find XCHG operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // Create the first effect, dest := src SMPRegTransfer *FirstRT = new SMPRegTransfer; FirstRT->SetParentInst(this); FirstRT->SetLeftOperand(TempRT->GetRightOperand()); FirstRT->SetRightOperand(TempRT->GetLeftOperand()); FirstRT->SetOperator(SMP_ASSIGN); this->RTL.push_back(FirstRT); // Push the second effect on the list, src := dest this->RTL.push_back(TempRT); } return (Src1Found && Src2Found); } // end of SMPInstr::BuildExchangeRTL() // Build the RTL for an instruction of form dest := dest + source, source := dest bool SMPInstr::BuildExchangeAddRTL(void) { std::size_t OpNum; bool Src1Found = false; bool Src2Found = false; SMPRegTransfer *TempRT = new SMPRegTransfer; // second effect, src := dest TempRT->SetParentInst(this); for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (MDKnownOperandType(TempOp)) { if (!Src1Found) { Src1Found = true; TempRT->SetRightOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF SMP_msg("CORRECT: XADD 1st opnd is DEF\n"); // should be the case else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE SMP_msg("WARNING: XADD 1st opnd is USE\n"); else SMP_msg("ERROR: XADD 1st opnd neither DEF nor USE\n"); #endif } else { Src2Found = true; TempRT->SetLeftOperand(TempOp); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->STARSInstPtr->IsDefOpnd(OpNum)) // DEF SMP_msg("WARNING: XADD 2nd opnd is DEF\n"); else if (this->STARSInstPtr->IsUseOpnd(OpNum)) // USE SMP_msg("CORRECT: XADD 2nd opnd is USE\n"); // should be the case else SMP_msg("ERROR: XADD 2nd opnd neither DEF nor USE\n"); #endif } } } // end for (OpNum = 0; ...) if (!Src1Found || !Src2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find XADD operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // Create the first effect, dest := dest + src SMPRegTransfer *FirstRT = new SMPRegTransfer; FirstRT->SetParentInst(this); SMPRegTransfer *AddRT = new SMPRegTransfer; AddRT->SetParentInst(this); AddRT->SetLeftOperand(TempRT->GetRightOperand()); AddRT->SetOperator(SMP_ADD); AddRT->SetRightOperand(TempRT->GetLeftOperand()); FirstRT->SetLeftOperand(TempRT->GetRightOperand()); FirstRT->SetRightTree(AddRT); FirstRT->SetOperator(SMP_ASSIGN); this->RTL.push_back(FirstRT); // Push the second effect on the list, src := dest this->RTL.push_back(TempRT); } return (Src1Found && Src2Found); } // end of SMPInstr::BuildExchangeAddRTL() // Build the RTL for an instruction of form: // if (dest==EAX) dest := source else EAX := dest bool SMPInstr::BuildCompareExchangeRTL(void) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; STARSOpndTypePtr DestOp = nullptr; STARSOpndTypePtr SourceOp = nullptr; SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (MDKnownOperandType(TempOp)) { if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (!DestFound) { DestFound = true; DestOp = TempOp; } else { SMP_msg("ERROR: CMPXCHG has two DEF operands.\n"); } } else if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (!SourceFound) { SourceFound = true; SourceOp = TempOp; } else { SMP_msg("ERROR: CMPXCHG has two USE operands.\n"); } } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find CMPXCHG operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { // Create the first effect, if (dest == EAX) dest := src SMPGuard *Guard1 = new SMPGuard; STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax); Guard1->SetLeftOperand(DestOp); Guard1->SetOperator(SMP_EQUAL); Guard1->SetRightOperand(EAXOp); SMPRegTransfer *FirstRT = new SMPRegTransfer; FirstRT->SetParentInst(this); FirstRT->SetLeftOperand(DestOp); FirstRT->SetRightOperand(SourceOp); FirstRT->SetOperator(SMP_ASSIGN); FirstRT->SetGuard(Guard1); this->RTL.push_back(FirstRT); // Push the second effect on the list, if (dest!=EAX) dest := EAX SMPGuard *Guard2 = new SMPGuard; Guard2->SetLeftOperand(DestOp); Guard2->SetOperator(SMP_EQUAL); Guard2->SetRightOperand(EAXOp); TempRT->SetLeftOperand(DestOp); TempRT->SetRightOperand(EAXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetGuard(Guard2); this->RTL.push_back(TempRT); } return (DestFound && SourceFound); } // end of SMPInstr::BuildCompareExchangeRTL() // Build the RTL for an extended FP concatenate and shift instruction bool SMPInstr::BuildPackShiftRTL(SMPoperator PackOp, SMPoperator ShiftOp) { std::size_t OpNum; bool DestFound = false; bool SourceFound = false; bool CountFound = false; SMPRegTransfer *TempRT = NULL; SMPRegTransfer *ShiftRT = new SMPRegTransfer; ShiftRT->SetParentInst(this); SMPRegTransfer *PackRT = new SMPRegTransfer; PackRT->SetParentInst(this); // RTL structure: top operator is assignment, next right operator is a reverse // shift with the shift count as its left operand, and lowest right operator // is the concatenation operator. Sequence of operations is pack, shift, assign. for (OpNum = 0; !(DestFound && SourceFound && CountFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); PackRT->SetLeftOperand(TempOp); PackRT->SetOperator(PackOp); ShiftRT->SetOperator(ShiftOp); ShiftRT->SetRightTree(PackRT); TempRT->SetRightTree(ShiftRT); } } else { // USE if (MDKnownOperandType(TempOp)) { if (!SourceFound) { SourceFound = true; PackRT->SetRightOperand(TempOp); } else { CountFound = true; ShiftRT->SetLeftOperand(TempOp); } } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound || !CountFound) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find MMX/XMM pack and shift operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound && CountFound); } // end of SMPInstr::BuildPackShiftRTL() // Build the RTL for a compare or test instruction with an implicit EFLAGS destination operand bool SMPInstr::BuildFlagsDestBinaryRTL(SMPoperator BinaryOp) { std::size_t OpNum; unsigned short opcode = this->GetIDAOpcode(); bool Source1Found = false; bool Source2Found = false; bool NoOperandsRequired = ((STARS_NN_scas == opcode) || (STARS_NN_cmps == opcode)); SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); // Some floating point instructions use the floating point register stack top as // an implicit source or destination, but the other operand of the load or store // is explicit, so we set the implicit operand and let control flow pass to the // main processing loop below. if ((STARS_NN_fcomi == opcode) || (STARS_NN_fucomi == opcode) || (STARS_NN_fcomip == opcode) || (STARS_NN_fucomip == opcode)) { // Compares implicitly use the floating point stack top as destination. STARSOpndTypePtr FPRegOp = this->STARSInstPtr->MakeFloatingPointRegOpnd(MD_FIRST_FP_STACK_REG); TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(FPRegOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); Source1Found = true; // The "p" at the end of the opcode indicates that the floating point // register stack gets popped. if ((STARS_NN_fcomip == opcode) || (STARS_NN_fucomip == opcode)) { this->RTL.ExtraKills.push_back(FPRegOp); } } for (OpNum = 0; !(Source1Found && Source2Found) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Found destination for compare or test at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); PrintOperand(TempOp); SMP_msg("\n"); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { if (!Source1Found) { Source1Found = true; TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } else { assert(!Source2Found); Source2Found = true; RightRT->SetRightOperand(TempOp); } } } } // end for (OpNum = 0; ...) // The compare string instruction always uses DS:ESI and ES:EDI as its source // operands, regardless of the explicit operands given, and might not have // explicit operands; explicit operands are just for documentation. // The scan string instruction uses EAX/AX/AH/AL and ES:EDI as its source // operands and might not have any explicit operands at all. if ((!NoOperandsRequired) && (!Source1Found || !Source2Found)) { if (!Source1Found) delete RightRT; else delete TempRT; #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find CMP/TEST operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); // Now, create the repeat prefix effects bool HasRepeatPrefix = this->STARSInstPtr->HasAnyRepeatPrefix(); if (HasRepeatPrefix) { // Must be CMPS or SCAS // The repeat causes USE and DEF of ECX as a counter SMPRegTransfer *CounterRT = new SMPRegTransfer; CounterRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); CounterRT->SetLeftOperand(CountOp); CounterRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(CountOp); RightRT->SetOperator(SMP_UNARY_NUMERIC_OPERATION); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); RightRT->SetRightOperand(VoidOp); CounterRT->SetRightTree(RightRT); this->RTL.push_back(CounterRT); } if ((STARS_NN_cmps == opcode) || (STARS_NN_scas == opcode)) { // The ESI and EDI registers get incremented or decremented, depending // on the direction flag DF, for CMPS; only EDI for SCAS. // This is true with or without a repeat prefix. if (STARS_NN_cmps == opcode) { STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si); this->RTL.ExtraKills.push_back(ESIOp); } STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di); this->RTL.ExtraKills.push_back(EDIOp); } } return (NoOperandsRequired || (Source1Found && Source2Found)); } // end of SMPInstr::BuildFlagsDestBinaryRTL() // Build the RTL for a direct or indirect call instruction bool SMPInstr::BuildCallRTL(void) { std::size_t OpNum; bool SourceFound = false; uint16_t opcode = this->GetIDAOpcode(); bool ParameterlessCall = ((opcode == STARS_NN_syscall) || (opcode == STARS_NN_sysenter) || (opcode == STARS_NN_into) || (opcode == STARS_NN_int3)); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); SMPRegTransfer *TempRT = NULL; if (ParameterlessCall) { TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(VoidOp); TempRT->SetOperator(SMP_CALL); STARSOpndTypePtr TargetOp = this->STARSInstPtr->MakeNearPointerOpnd(STARS_BADADDR); TempRT->SetRightOperand(TargetOp); } else { for (OpNum = 0; !SourceFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Found destination operand for call at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(VoidOp); TempRT->SetOperator(SMP_CALL); TempRT->SetRightOperand(TempOp); } } } // end for (OpNum = 0; ...) } if (!SourceFound && !ParameterlessCall) { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find CALL operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { this->RTL.push_back(TempRT); } return (SourceFound || ParameterlessCall); } // end of SMPInstr::BuildCallRTL() // Build the RTL for a return instruction, with or without extra bytes popped off stack bool SMPInstr::BuildReturnRTL(void) { std::size_t OpNum; STARS_uval_t PopBytes = (STARS_uval_t) global_STARS_program->GetSTARS_ISA_Bytewidth(); // default: pop off return address switch (this->GetIDAOpcode()) { // Returns modified by operand size prefixes case STARS_NN_retnw: // Return Near from Procedure (use16) case STARS_NN_retfw: // Return Far from Procedure (use16) PopBytes = 2; break; case STARS_NN_retnd: // Return Near from Procedure (use32) case STARS_NN_retfd: // Return Far from Procedure (use32) PopBytes = 4; break; case STARS_NN_retnq: // Return Near from Procedure (use64) case STARS_NN_retfq: // Return Far from Procedure (use64) PopBytes = 8; break; } for (OpNum = 0; OpNum < STARS_UA_MAXOP; ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Found destination operand for RET at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { if (TempOp->IsImmedOp()) { PopBytes += TempOp->GetImmedValue(); } else { #if SMP_DEBUG_BUILD_RTL if (!(this->IsTailCall())) { SMP_msg("ERROR: Found unexpected operand for return at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } #endif } } } } // end for (OpNum = 0; ...) this->AddToStackPointer(PopBytes); this->SetHasReturnOpcode(); return true; } // end of SMPInstr::BuildReturnRTL() // Build the RTL for an ENTER instruction bool SMPInstr::BuildEnterRTL(void) { // An "ENTER k,0" instruction with allocation k and nesting level 0 does the following: // push ebp // mov ebp,esp // sub esp,k // This can be modeled by the parallel effects: // [esp-4] := ebp; ebp := esp - 4; esp := esp - (k + 4) // If nesting level is greater than zero, we have a block structure language with // nested procedures, in which additional frame pointers are saved: // "ENTER k,n" pushes n additional frame pointers on the stack. We will only model // the change in the stack pointer here, and not attempt to transfer the display // pointers. A warning will be issued to the log file. Parallel effects are: // [esp-4] := ebp; ebp := esp - 4; esp := esp - (((k + n)*4)+4) // Note that k and n are immediate values so the final expression can be computed. std::size_t OpNum; STARS_uval_t NestingLevel = 0; STARS_uval_t AllocBytes = 0; bool AllocFound = false; bool NestingLevelFound = false; STARSOpndTypePtr StackPointerOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG); STARSOpndTypePtr FramePointerOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG); STARSOpndTypePtr ImmedWordSizeOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) global_STARS_program->GetSTARS_ISA_Bytewidth()); STARSOpndTypePtr SavedEBP = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, (-((STARS_ea_t) global_STARS_program->GetSTARS_ISA_Bytewidth()))); // [ESP-4 or 8], location of saved EBP for (OpNum = 0; !(AllocFound && NestingLevelFound) && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Found destination operand for ENTER at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { if (TempOp->IsImmedOp()) { if (!AllocFound) { AllocBytes = TempOp->GetImmedValue(); AllocFound = true; } else { NestingLevel = TempOp->GetImmedValue(); NestingLevelFound = true; } } else { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Found unexpected operand for ENTER at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } } } } // end for (OpNum = 0; ...) if (!AllocFound) { #if SMP_DEBUG_BUILD_RTL SMP_msg("ERROR: Could not find allocation operand for ENTER at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); #endif } else { SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); // Add first effect: [esp - wordsize] := ebp TempRT->SetLeftOperand(SavedEBP); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(FramePointerOp); this->RTL.push_back(TempRT); TempRT = NULL; // Add second effect: ebp := esp - wordsize TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(FramePointerOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetLeftOperand(StackPointerOp); RightRT->SetOperator(SMP_SUBTRACT); RightRT->SetRightOperand(ImmedWordSizeOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); TempRT = NULL; RightRT = NULL; // Add final effect on stack pointer AllocBytes += (global_STARS_program->GetSTARS_ISA_Bytewidth() * (NestingLevel + 1)); if (0 != NestingLevel) { SMP_msg("WARNING: Nested procedures in ENTER instruction at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } this->SubFromStackPointer(AllocBytes); } return AllocFound; } // end of SMPInstr::BuildEnterRTL() // Build the RTL for a LEAVE instruction bool SMPInstr::BuildLeaveRTL(void) { // A LEAVE instruction simulates the following instructions: // mov ebp into esp (deallocates stack frame) // pop saved ebp off stack into ebp // We want to model these two instructions with three parallel effects: // esp := ebp; ebp := [ebp+0]; esp = esp + wordsize; // There cannot be two definitions of esp in the list of effects, so we do: // esp := ebp + wordsize; ebp := [ebp+0] as our two parallel effects STARSOpndTypePtr StackPointerOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG); STARSOpndTypePtr FramePointerOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG); STARSOpndTypePtr ImmedWordSizeOp = this->STARSInstPtr->MakeImmediateOpnd((STARS_uval_t) global_STARS_program->GetSTARS_ISA_Bytewidth()); STARSOpndTypePtr SavedEBP = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_FRAME_POINTER_REG, STARS_x86_R_none, 0, 0); // Build first effect: ESP := EBP + wordsize SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(StackPointerOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetOperator(SMP_ADD); RightRT->SetLeftOperand(FramePointerOp); RightRT->SetRightOperand(ImmedWordSizeOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); TempRT = NULL; RightRT = NULL; // Build second effect: EBP := [EBP+0] TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(FramePointerOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(SavedEBP); this->RTL.push_back(TempRT); TempRT = NULL; return true; } // end of SMPInstr::BuildLeaveRTL() // Build OptCategory 8 RTLs, which set system info into EDX:EAX. bool SMPInstr::BuildOptType8RTL(void) { STARSOpndTypePtr DestOp1 = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx); STARSOpndTypePtr DestOp2 = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax); STARSOpndTypePtr VoidOp = this->STARSInstPtr->MakeVoidOpnd(); STARSOpndTypePtr LeftOp = nullptr; if (STARS_NN_xgetbv == this->GetIDAOpcode()) { // AMD xgetbv opcode gets control register number to read out of ECX. LeftOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); } else { LeftOp = VoidOp; } // Create the effect on EDX. SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(DestOp1); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetLeftOperand(LeftOp); RightRT->SetOperator(SMP_SYSTEM_OPERATION); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); // Create the effect on EAX. TempRT = NULL; RightRT = NULL; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(DestOp2); TempRT->SetOperator(SMP_ASSIGN); RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); RightRT->SetLeftOperand(LeftOp); RightRT->SetOperator(SMP_SYSTEM_OPERATION); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); return true; } // end of BuildOptType8RTL() // Build the RTL for a direct or indirect jump instruction bool SMPInstr::BuildJumpRTL(SMPoperator CondBranchOp) { std::size_t OpNum; bool TargetFound = false; SMPRegTransfer *TempRT = NULL; STARSOpndTypePtr EIPOp = this->STARSInstPtr->MakeRegOpnd(MD_INSTRUCTION_POINTER_REG); STARSOpndTypePtr CountOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx); STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG); STARSOpndTypePtr ZeroOp = this->STARSInstPtr->MakeImmediateOpnd(0); #if 0 if (this->IsTailCall()) return this->BuildReturnRTL(); #endif for (OpNum = 0; !TargetFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (MDKnownOperandType(TempOp)) { TargetFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(EIPOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(TempOp); if (CondBranchOp != SMP_NULL_OPERATOR) { // Set up a guard expression comparing EFLAGS to zero. // NOTE: This is imprecise for value-set purposes, but OK for types. SMPGuard *BranchCondition = new SMPGuard; BranchCondition->SetOperator(CondBranchOp); // The conditional jumps on ECX==0 compare to ECX, not EFLAGS. if ((STARS_NN_jcxz <= this->GetIDAOpcode()) && (STARS_NN_jrcxz >= this->GetIDAOpcode())) BranchCondition->SetLeftOperand(CountOp); else BranchCondition->SetLeftOperand(FlagsOp); BranchCondition->SetRightOperand(ZeroOp); TempRT->SetGuard(BranchCondition); } this->RTL.push_back(TempRT); } } } // end for (OpNum = 0; ...) #if SMP_DEBUG_BUILD_RTL if (!TargetFound) { SMP_msg("ERROR: Could not find jump target at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } #endif return TargetFound; } // end of SMPInstr::BuildJumpRTL() // Add to the stack pointer to deallocate stack space, e.g. for a pop instruction. void SMPInstr::AddToStackPointer(STARS_uval_t delta) { SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr DeltaOp = this->STARSInstPtr->MakeImmediateOpnd(delta); TempRT->SetLeftOperand(StackOp); // ESP := RightRT TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(StackOp); // ESP + delta RightRT->SetOperator(SMP_ADD); RightRT->SetRightOperand(DeltaOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); return; } // end of SMPInstr::AddToStackPointer() // Subtract from the stack pointer to allocate stack space, e.g. for a push instruction. void SMPInstr::SubFromStackPointer(STARS_uval_t delta) { SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetParentInst(this); STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr DeltaOp = this->STARSInstPtr->MakeImmediateOpnd(delta); TempRT->SetLeftOperand(StackOp); // ESP := RightRT TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(StackOp); // ESP - delta RightRT->SetOperator(SMP_SUBTRACT); RightRT->SetRightOperand(DeltaOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); return; } // end of SMPInstr::SubFromStackPointer() #define SMP_FIRST_POP_FLAGS STARS_NN_popfw #define SMP_LAST_POP_FLAGS STARS_NN_popfq #define SMP_FIRST_POP_ALL STARS_NN_popaw #define SMP_LAST_POP_ALL STARS_NN_popaq // Build the RTL for a pop instruction bool SMPInstr::BuildPopRTL(void) { std::size_t OpNum, OpSize; bool DestFound = false; SMPRegTransfer *TempRT = NULL; // Handle special cases first. if ((SMP_FIRST_POP_FLAGS <= this->GetIDAOpcode()) && (SMP_LAST_POP_FLAGS >= this->GetIDAOpcode())) { STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 0); // [ESP+0] TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->AddToStackPointer(global_STARS_program->GetSTARS_ISA_Bytewidth()); return true; } if ((SMP_FIRST_POP_ALL <= this->GetIDAOpcode()) && (SMP_LAST_POP_ALL >= this->GetIDAOpcode())) { // We pop off 7 registers from the 8 that were pushed on the stack. // The pushed stack pointer is ignored. Instead, the stack pointer value is // adjusted at the end, per the Intel instruction manuals. // EDI comes from [ESP+0] STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp0 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 0 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(EDIOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp0); this->RTL.push_back(TempRT); TempRT = NULL; // ESI comes from [ESP+4 or 8] STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp1 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 1 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(ESIOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp1); this->RTL.push_back(TempRT); TempRT = NULL; // EBP comes from [ESP+8 or 16] STARSOpndTypePtr EBPOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp2 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 2 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(EBPOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp2); this->RTL.push_back(TempRT); TempRT = NULL; // Skip over saved ESP at [ESP+12 or 24] // EBX comes from [ESP+16 or 32] STARSOpndTypePtr EBXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_bx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp4 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 4 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(EBXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp4); this->RTL.push_back(TempRT); TempRT = NULL; // EDX comes from [ESP+20 or 40] STARSOpndTypePtr EDXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp5 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 5 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(EDXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp5); this->RTL.push_back(TempRT); TempRT = NULL; // ECX comes from [ESP+24 or 48] STARSOpndTypePtr ECXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp6 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 6 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(ECXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp6); this->RTL.push_back(TempRT); TempRT = NULL; // EAX comes from [ESP+28 or 56] STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp7 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, ((STARS_ea_t) 7 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(EAXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp7); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->AddToStackPointer(8*global_STARS_program->GetSTARS_ISA_Bytewidth()); return true; } // end for "pop all" instructions // If we reach this point, we have a simple POP instruction. for (OpNum = 0; !DestFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsDefOpnd(OpNum)) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); OpSize = TempOp->GetByteWidth(); STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, 0); StackOp->SetByteWidth(OpSize); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); // Now create the stack pointer increment effect. this->AddToStackPointer((STARS_uval_t) OpSize); } } } // end for (OpNum = 0; ...) #if SMP_DEBUG_BUILD_RTL if (!DestFound) { SMP_msg("ERROR: Could not find pop operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } #endif return DestFound; } // end of SMPInstr::BuildPopRTL() #define SMP_FIRST_PUSH_FLAGS STARS_NN_pushfw #define SMP_LAST_PUSH_FLAGS STARS_NN_pushfq #define SMP_FIRST_PUSH_ALL STARS_NN_pushaw #define SMP_LAST_PUSH_ALL STARS_NN_pushaq // Build the RTL for a push instruction bool SMPInstr::BuildPushRTL(void) { std::size_t OpNum, OpSize; bool SourceFound = false; SMPRegTransfer *TempRT = NULL; // Handle special cases first. if ((SMP_FIRST_PUSH_FLAGS <= this->GetIDAOpcode()) && (SMP_LAST_PUSH_FLAGS >= this->GetIDAOpcode())) { STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); // Now create the stack pointer increment effect. this->SubFromStackPointer(global_STARS_program->GetSTARS_ISA_Bytewidth()); return true; } if ((SMP_FIRST_PUSH_ALL <= this->GetIDAOpcode()) && (SMP_LAST_PUSH_ALL >= this->GetIDAOpcode())) { // EDI goes to [ESP-32 or 64] STARSOpndTypePtr EDIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_di, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp8 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 8 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(EDIOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp8); this->RTL.push_back(TempRT); TempRT = NULL; // ESI goes to [ESP-28 or 56] STARSOpndTypePtr ESIOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_si, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp7 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 7 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(ESIOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp7); this->RTL.push_back(TempRT); TempRT = NULL; // EBP goes to [ESP-24 or 48] STARSOpndTypePtr EBPOp = this->STARSInstPtr->MakeRegOpnd(MD_FRAME_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp6 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 6 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(EBPOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp6); this->RTL.push_back(TempRT); TempRT = NULL; // ESP goes to [ESP-20 or 40] STARSOpndTypePtr ESPOp = this->STARSInstPtr->MakeRegOpnd(MD_STACK_POINTER_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp5 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 5 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(ESPOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp5); this->RTL.push_back(TempRT); TempRT = NULL; // EBX goes to [ESP-16 or 32] STARSOpndTypePtr EBXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_bx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp4 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 4 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(EBXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp4); this->RTL.push_back(TempRT); TempRT = NULL; // EDX goes to [ESP-12 or 24] STARSOpndTypePtr EDXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_dx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp3 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 3 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(EDXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp3); this->RTL.push_back(TempRT); TempRT = NULL; // ECX goes to [ESP-8 or 16] STARSOpndTypePtr ECXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_cx, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp2 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 2 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(ECXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp2); this->RTL.push_back(TempRT); TempRT = NULL; // EAX goes to [ESP-4] STARSOpndTypePtr EAXOp = this->STARSInstPtr->MakeRegOpnd(STARS_x86_R_ax, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); STARSOpndTypePtr StackOp1 = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) 1 * global_STARS_program->GetSTARS_ISA_Bytewidth())); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(EAXOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp1); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->SubFromStackPointer((STARS_uval_t) 8 * global_STARS_program->GetSTARS_ISA_Bytewidth()); return true; } // end for "pop all" instructions // If we reach this point, we have a simple PUSH instruction. for (OpNum = 0; !SourceFound && (OpNum < STARS_UA_MAXOP); ++OpNum) { STARSOpndTypePtr TempOp = this->STARSInstPtr->GetOpnd(OpNum); if (nullptr == TempOp) // finished processing operands break; if (this->STARSInstPtr->IsUseOpnd(OpNum)) { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; OpSize = TempOp->GetByteWidth(); TempRT = new SMPRegTransfer; TempRT->SetParentInst(this); TempRT->SetRightOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); OpSize = TempRT->MDSignExtend64RightOpIfNeeded(); STARSOpndTypePtr StackOp = this->STARSInstPtr->MakeMemDisplacementOpnd(MD_STACK_POINTER_REG, STARS_x86_R_none, 0, -((STARS_ea_t) OpSize)); StackOp->SetByteWidth(OpSize); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->SubFromStackPointer((STARS_uval_t) OpSize); #if 0 this->RTL.Dump(); #endif } } } // end for (OpNum = 0; ...) #if SMP_DEBUG_BUILD_RTL if (!SourceFound) { SMP_msg("ERROR: Could not find push operand at %llx for %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); } #endif return SourceFound; } // end of SMPInstr::BuildPushRTL() // Build RTL trees from the SMPcmd info. bool SMPInstr::BuildRTL(void) { STARSOpndTypePtr FlagsOp = this->STARSInstPtr->MakeRegOpnd(X86_FLAGS_REG, (global_STARS_program->GetSTARS_ISA_Bitwidth() == 64)); SMPRegTransfer *NopRT = NULL; // no-op register transfer // We don't want to explicitly represent the various no-ops except as NULL operations. // E.g. mov esi,esi should not generate DEF and USE of esi, because esi does not change. if (this->IsNop()) { NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; } switch (this->GetIDAOpcode()) { case STARS_NN_aaa: // ASCII Adjust after Addition case STARS_NN_aad: // ASCII Adjust AX before Division case STARS_NN_aam: // ASCII Adjust AX after Multiply case STARS_NN_aas: // ASCII Adjust AL after Subtraction return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_adc: // Add with Carry #if SMP_BUILD_SPECIAL_ADC_SBB_RTL return this->BuildBinaryPlusFlagsRTL(SMP_ADD_CARRY); #else return this->BuildBinaryRTL(SMP_ADD_CARRY); #endif case STARS_NN_add: // Add return this->BuildBinaryRTL(SMP_ADD); case STARS_NN_and: // Logical AND return this->BuildBinaryRTL(SMP_BITWISE_AND); case STARS_NN_arpl: // Adjust RPL Field of Selector return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_bound: // Check Array Index Against Bounds return this->BuildGuardedSignalRTL(SMP_SIGNAL); case STARS_NN_bsf: // Bit Scan Forward case STARS_NN_bsr: // Bit Scan Reverse return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_bt: // Bit Test return this->BuildFlagsDestBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_btc: // Bit Test and Complement case STARS_NN_btr: // Bit Test and Reset case STARS_NN_bts: // Bit Test and Set // Has effects on both the carry flag and the first operand this->RTL.ExtraKills.push_back(FlagsOp); return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_call: // Call Procedure case STARS_NN_callfi: // Indirect Call Far Procedure case STARS_NN_callni: // Indirect Call Near Procedure return this->BuildCallRTL(); case STARS_NN_cbw: // AL -> AX (with sign) case STARS_NN_cwde: // AX -> EAX (with sign) case STARS_NN_cdqe: // EAX -> RAX (with sign) return this->BuildUnaryRTL(SMP_SIGN_EXTEND); case STARS_NN_clc: // Clear Carry Flag case STARS_NN_cld: // Clear Direction Flag return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_cli: // Clear Interrupt Flag case STARS_NN_clts: // Clear Task-Switched Flag in CR0 // We don't track the interrupt flag or the special registers, // so we can just consider these to be no-ops. // NOTE: Shouldn't we killthe EFLAGS register on STARS_NN_cli ??!!??!! NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_cmc: // Complement Carry Flag return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_cmp: // Compare Two Operands return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); case STARS_NN_cmps: // Compare Strings // Why do we no longer use BuildCompareStringRTL()? ****!!!!**** Test it! return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE); case STARS_NN_cwd: // AX -> DX:AX (with sign) case STARS_NN_cdq: // EAX -> EDX:EAX (with sign) case STARS_NN_cqo: // RAX -> RDX:RAX (with sign) return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); case STARS_NN_daa: // Decimal Adjust AL after Addition case STARS_NN_das: // Decimal Adjust AL after Subtraction return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_dec: // Decrement by 1 return this->BuildUnaryRTL(SMP_DECREMENT); case STARS_NN_div: // Unsigned Divide return this->BuildMultiplyDivideRTL(SMP_U_DIVIDE); case STARS_NN_enterw: // Make Stack Frame for Procedure Parameters case STARS_NN_enter: // Make Stack Frame for Procedure Parameters case STARS_NN_enterd: // Make Stack Frame for Procedure Parameters case STARS_NN_enterq: // Make Stack Frame for Procedure Parameters return this->BuildEnterRTL(); case STARS_NN_hlt: // Halt // Treat as a no-op NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_idiv: // Signed Divide return this->BuildMultiplyDivideRTL(SMP_S_DIVIDE); case STARS_NN_imul: // Signed Multiply return this->BuildMultiplyDivideRTL(SMP_S_MULTIPLY); case STARS_NN_in: // Input from Port return this->BuildUnary2OpndRTL(SMP_INPUT); case STARS_NN_inc: // Increment by 1 return this->BuildUnaryRTL(SMP_INCREMENT); case STARS_NN_ins: // Input Byte(s) from Port to String return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_int: // Call to Interrupt Procedure case STARS_NN_into: // Call to Interrupt Procedure if Overflow Flag = 1 case STARS_NN_int3: // Trap to Debugger return this->BuildCallRTL(); case STARS_NN_iretw: // Interrupt Return case STARS_NN_iret: // Interrupt Return case STARS_NN_iretd: // Interrupt Return (use32) case STARS_NN_iretq: // Interrupt Return (use64) return this->BuildReturnRTL(); case STARS_NN_ja: // Jump if Above (CF=0 & ZF=0) return this->BuildJumpRTL(SMP_ABOVE); case STARS_NN_jae: // Jump if Above or Equal (CF=0) return this->BuildJumpRTL(SMP_ABOVE_EQUAL); case STARS_NN_jb: // Jump if Below (CF=1) return this->BuildJumpRTL(SMP_BELOW); case STARS_NN_jbe: // Jump if Below or Equal (CF=1 | ZF=1) return this->BuildJumpRTL(SMP_BELOW_EQUAL); case STARS_NN_jc: // Jump if Carry (CF=1) return this->BuildJumpRTL(SMP_BELOW); case STARS_NN_jcxz: // Jump if CX is 0 case STARS_NN_jecxz: // Jump if ECX is 0 case STARS_NN_jrcxz: // Jump if RCX is 0 return this->BuildJumpRTL(SMP_EQUAL); // special case in BuildJumpRTL() case STARS_NN_je: // Jump if Equal (ZF=1) return this->BuildJumpRTL(SMP_EQUAL); case STARS_NN_jg: // Jump if Greater (ZF=0 & SF=OF) return this->BuildJumpRTL(SMP_GREATER_THAN); case STARS_NN_jge: // Jump if Greater or Equal (SF=OF) return this->BuildJumpRTL(SMP_GREATER_EQUAL); case STARS_NN_jl: // Jump if Less (SF!=OF) return this->BuildJumpRTL(SMP_LESS_THAN); case STARS_NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) return this->BuildJumpRTL(SMP_LESS_EQUAL); case STARS_NN_jna: // Jump if Not Above (CF=1 | ZF=1) return this->BuildJumpRTL(SMP_BELOW_EQUAL); case STARS_NN_jnae: // Jump if Not Above or Equal (CF=1) return this->BuildJumpRTL(SMP_BELOW); case STARS_NN_jnb: // Jump if Not Below (CF=0) return this->BuildJumpRTL(SMP_ABOVE_EQUAL); case STARS_NN_jnbe: // Jump if Not Below or Equal (CF=0 & ZF=0) a.k.a. ja return this->BuildJumpRTL(SMP_ABOVE); case STARS_NN_jnc: // Jump if Not Carry (CF=0) return this->BuildJumpRTL(SMP_ABOVE_EQUAL); case STARS_NN_jne: // Jump if Not Equal (ZF=0) return this->BuildJumpRTL(SMP_NOT_EQUAL); case STARS_NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) a.k.a. jle return this->BuildJumpRTL(SMP_LESS_EQUAL); case STARS_NN_jnge: // Jump if Not Greater or Equal (SF != OF) ** return this->BuildJumpRTL(SMP_LESS_THAN); case STARS_NN_jnl: // Jump if Not Less (SF=OF) a.k.a. jge return this->BuildJumpRTL(SMP_GREATER_EQUAL); case STARS_NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) a.k.a. jg return this->BuildJumpRTL(SMP_GREATER_THAN); case STARS_NN_jno: // Jump if Not Overflow (OF=0) case STARS_NN_jnp: // Jump if Not Parity (PF=0) case STARS_NN_jns: // Jump if Not Sign (SF=0) return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_jnz: // Jump if Not Zero (ZF=0) a.k.a. jne return this->BuildJumpRTL(SMP_NOT_EQUAL); case STARS_NN_jo: // Jump if Overflow (OF=1) case STARS_NN_jp: // Jump if Parity (PF=1) case STARS_NN_jpe: // Jump if Parity Even (PF=1) case STARS_NN_jpo: // Jump if Parity Odd (PF=0) case STARS_NN_js: // Jump if Sign (SF=1) return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_jz: // Jump if Zero (ZF=1) return this->BuildJumpRTL(SMP_EQUAL); case STARS_NN_jmp: // Jump case STARS_NN_jmpfi: // Indirect Far Jump case STARS_NN_jmpni: // Indirect Near Jump case STARS_NN_jmpshort: // Jump Short (not used) return this->BuildJumpRTL(SMP_NULL_OPERATOR); case STARS_NN_lahf: // Load Flags into AH Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_lar: // Load Access Right Byte return false; break; case STARS_NN_lea: // Load Effective Address return this->BuildLeaRTL(); break; case STARS_NN_leavew: // High Level Procedure Exit case STARS_NN_leave: // High Level Procedure Exit case STARS_NN_leaved: // High Level Procedure Exit case STARS_NN_leaveq: // High Level Procedure Exit return this->BuildLeaveRTL(); break; case STARS_NN_lgdt: // Load Global Descriptor Table Register case STARS_NN_lidt: // Load Interrupt Descriptor Table Register return false; break; case STARS_NN_lgs: // Load Full Pointer to GS:xx case STARS_NN_lss: // Load Full Pointer to SS:xx case STARS_NN_lds: // Load Full Pointer to DS:xx case STARS_NN_les: // Load Full Pointer to ES:xx case STARS_NN_lfs: // Load Full Pointer to FS:xx // These instructions differ from STARS_NN_lea only in setting // a segment register in addition to a pointer. We are // not yet tracking segment registers. return this->BuildLeaRTL(); break; case STARS_NN_lldt: // Load Local Descriptor Table Register case STARS_NN_lmsw: // Load Machine Status Word return false; break; case STARS_NN_lock: // Assert LOCK# Signal Prefix NOTE: This is now a no-op NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_lods: // Load String return this->BuildLoadStringRTL(); break; case STARS_NN_loopw: // Loop while ECX != 0 case STARS_NN_loop: // Loop while CX != 0 case STARS_NN_loopd: // Loop while ECX != 0 case STARS_NN_loopq: // Loop while RCX != 0 case STARS_NN_loopwe: // Loop while CX != 0 and ZF=1 case STARS_NN_loope: // Loop while rCX != 0 and ZF=1 case STARS_NN_loopde: // Loop while ECX != 0 and ZF=1 case STARS_NN_loopqe: // Loop while RCX != 0 and ZF=1 case STARS_NN_loopwne: // Loop while CX != 0 and ZF=0 case STARS_NN_loopne: // Loop while rCX != 0 and ZF=0 case STARS_NN_loopdne: // Loop while ECX != 0 and ZF=0 case STARS_NN_loopqne: // Loop while RCX != 0 and ZF=0 return this->BuildLoopRTL(SMP_NULL_OPERATOR); break; case STARS_NN_lsl: // Load Segment Limit case STARS_NN_ltr: // Load Task Register return false; break; case STARS_NN_mov: // Move Data case STARS_NN_movsp: // Move to/from Special Registers case STARS_NN_movs: // Move Byte(s) from String to String return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_movsx: // Move with Sign-Extend return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); case STARS_NN_movzx: // Move with Zero-Extend return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND); case STARS_NN_mul: // Unsigned Multiplication of AL or AX return this->BuildMultiplyDivideRTL(SMP_U_MULTIPLY); case STARS_NN_neg: // Two's Complement Negation return this->BuildUnaryRTL(SMP_NEGATE); case STARS_NN_nop: // No Operation NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_not: // One's Complement Negation return this->BuildUnaryRTL(SMP_BITWISE_NOT); case STARS_NN_or: // Logical Inclusive OR return this->BuildBinaryRTL(SMP_BITWISE_OR); case STARS_NN_out: // Output to Port return this->BuildUnary2OpndRTL(SMP_OUTPUT); case STARS_NN_outs: // Output Byte(s) to Port return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_pop: // Pop a word from the Stack case STARS_NN_popaw: // Pop all General Registers case STARS_NN_popa: // Pop all General Registers case STARS_NN_popad: // Pop all General Registers (use32) case STARS_NN_popaq: // Pop all General Registers (use64) case STARS_NN_popfw: // Pop Stack into Flags Register case STARS_NN_popf: // Pop Stack into Flags Register case STARS_NN_popfd: // Pop Stack into Eflags Register case STARS_NN_popfq: // Pop Stack into Rflags Register return this->BuildPopRTL(); case STARS_NN_push: // Push Operand onto the Stack case STARS_NN_pushaw: // Push all General Registers case STARS_NN_pusha: // Push all General Registers case STARS_NN_pushad: // Push all General Registers (use32) case STARS_NN_pushaq: // Push all General Registers (use64) case STARS_NN_pushfw: // Push Flags Register onto the Stack case STARS_NN_pushf: // Push Flags Register onto the Stack case STARS_NN_pushfd: // Push Flags Register onto the Stack (use32) case STARS_NN_pushfq: // Push Flags Register onto the Stack (use64) return this->BuildPushRTL(); case STARS_NN_rcl: // Rotate Through Carry Left return this->BuildBinaryPlusFlagsRTL(SMP_ROTATE_LEFT_CARRY); case STARS_NN_rcr: // Rotate Through Carry Right return this->BuildBinaryPlusFlagsRTL(SMP_ROTATE_RIGHT_CARRY); case STARS_NN_rol: // Rotate Left return this->BuildBinaryRTL(SMP_ROTATE_LEFT); case STARS_NN_ror: // Rotate Right return this->BuildBinaryRTL(SMP_ROTATE_RIGHT); case STARS_NN_rep: // Repeat String Operation case STARS_NN_repe: // Repeat String Operation while ZF=1 case STARS_NN_repne: // Repeat String Operation while ZF=0 return false; break; case STARS_NN_retn: // Return Near from Procedure case STARS_NN_retf: // Return Far from Procedure return this->BuildReturnRTL(); case STARS_NN_sahf: // Store AH into Flags Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_sal: // Shift Arithmetic Left return this->BuildBinaryRTL(SMP_S_LEFT_SHIFT); case STARS_NN_sar: // Shift Arithmetic Right return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT); case STARS_NN_shl: // Shift Logical Left return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT); case STARS_NN_shr: // Shift Logical Right return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT); case STARS_NN_sbb: // Integer Subtraction with Borrow #if SMP_BUILD_SPECIAL_ADC_SBB_RTL return this->BuildBinaryPlusFlagsRTL(SMP_SUBTRACT_BORROW); #else return this->BuildBinaryRTL(SMP_SUBTRACT_BORROW); #endif case STARS_NN_scas: // Scan String return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE); case STARS_NN_seta: // Set Byte if Above (CF=0 & ZF=0) return this->BuildSetFlagIntoRegRTL(SMP_ABOVE, SMP_BELOW_EQUAL); case STARS_NN_setae: // Set Byte if Above or Equal (CF=0) return this->BuildSetFlagIntoRegRTL(SMP_ABOVE_EQUAL, SMP_BELOW); case STARS_NN_setb: // Set Byte if Below (CF=1) return this->BuildSetFlagIntoRegRTL(SMP_BELOW, SMP_ABOVE_EQUAL); case STARS_NN_setbe: // Set Byte if Below or Equal (CF=1 | ZF=1) return this->BuildSetFlagIntoRegRTL(SMP_BELOW_EQUAL, SMP_ABOVE); case STARS_NN_setc: // Set Byte if Carry (CF=1) return this->BuildSetFlagIntoRegRTL(SMP_CARRY, SMP_NOT_CARRY); case STARS_NN_sete: // Set Byte if Equal (ZF=1) return this->BuildSetFlagIntoRegRTL(SMP_EQUAL, SMP_NOT_EQUAL); case STARS_NN_setg: // Set Byte if Greater (ZF=0 & SF=OF) return this->BuildSetFlagIntoRegRTL(SMP_GREATER_THAN, SMP_LESS_EQUAL); case STARS_NN_setge: // Set Byte if Greater or Equal (SF=OF) return this->BuildSetFlagIntoRegRTL(SMP_GREATER_EQUAL, SMP_LESS_THAN); case STARS_NN_setl: // Set Byte if Less (SF!=OF) return this->BuildSetFlagIntoRegRTL(SMP_LESS_THAN, SMP_GREATER_EQUAL); case STARS_NN_setle: // Set Byte if Less or Equal (ZF=1 | SF!=OF) return this->BuildSetFlagIntoRegRTL(SMP_LESS_EQUAL, SMP_GREATER_THAN); case STARS_NN_setna: // Set Byte if Not Above (CF=1 | ZF=1) return this->BuildSetFlagIntoRegRTL(SMP_BELOW_EQUAL, SMP_ABOVE); case STARS_NN_setnae: // Set Byte if Not Above or Equal (CF=1) return this->BuildSetFlagIntoRegRTL(SMP_BELOW, SMP_ABOVE_EQUAL); case STARS_NN_setnb: // Set Byte if Not Below (CF=0) return this->BuildSetFlagIntoRegRTL(SMP_ABOVE_EQUAL, SMP_BELOW); case STARS_NN_setnbe: // Set Byte if Not Below or Equal (CF=0 & ZF=0) return this->BuildSetFlagIntoRegRTL(SMP_ABOVE, SMP_BELOW_EQUAL); case STARS_NN_setnc: // Set Byte if Not Carry (CF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_CARRY, SMP_CARRY); case STARS_NN_setne: // Set Byte if Not Equal (ZF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_EQUAL, SMP_EQUAL); case STARS_NN_setng: // Set Byte if Not Greater (ZF=1 | SF!=OF) return this->BuildSetFlagIntoRegRTL(SMP_LESS_EQUAL, SMP_GREATER_THAN); case STARS_NN_setnge: // Set Byte if Not Greater or Equal (ZF=1) return this->BuildSetFlagIntoRegRTL(SMP_LESS_THAN, SMP_GREATER_EQUAL); case STARS_NN_setnl: // Set Byte if Not Less (SF=OF) return this->BuildSetFlagIntoRegRTL(SMP_GREATER_EQUAL, SMP_LESS_THAN); case STARS_NN_setnle: // Set Byte if Not Less or Equal (ZF=0 & SF=OF) return this->BuildSetFlagIntoRegRTL(SMP_GREATER_THAN, SMP_LESS_EQUAL); case STARS_NN_setno: // Set Byte if Not Overflow (OF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_OVERFLOW, SMP_OVERFLOW); case STARS_NN_setnp: // Set Byte if Not Parity (PF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_PARITY, SMP_PARITY); case STARS_NN_setns: // Set Byte if Not Sign (SF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_SIGN_BIT_SET, SMP_SIGN_BIT_SET); case STARS_NN_setnz: // Set Byte if Not Zero (ZF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_EQUAL, SMP_EQUAL); case STARS_NN_seto: // Set Byte if Overflow (OF=1) return this->BuildSetFlagIntoRegRTL(SMP_OVERFLOW, SMP_NOT_OVERFLOW); case STARS_NN_setp: // Set Byte if Parity (PF=1) case STARS_NN_setpe: // Set Byte if Parity Even (PF=1) return this->BuildSetFlagIntoRegRTL(SMP_PARITY, SMP_NOT_PARITY); case STARS_NN_setpo: // Set Byte if Parity Odd (PF=0) return this->BuildSetFlagIntoRegRTL(SMP_NOT_PARITY, SMP_PARITY); case STARS_NN_sets: // Set Byte if Sign (SF=1) return this->BuildSetFlagIntoRegRTL(SMP_SIGN_BIT_SET, SMP_NOT_SIGN_BIT_SET); case STARS_NN_setz: // Set Byte if Zero (ZF=1) return this->BuildSetFlagIntoRegRTL(SMP_EQUAL, SMP_NOT_EQUAL); case STARS_NN_sgdt: // Store Global Descriptor Table Register case STARS_NN_sidt: // Store Interrupt Descriptor Table Register return false; break; case STARS_NN_shld: // Double Precision Shift Left return this->BuildDoubleShiftRTL(SMP_U_LEFT_SHIFT); case STARS_NN_shrd: // Double Precision Shift Right return this->BuildDoubleShiftRTL(SMP_U_RIGHT_SHIFT); case STARS_NN_sldt: // Store Local Descriptor Table Register case STARS_NN_smsw: // Store Machine Status Word return false; break; case STARS_NN_stc: // Set Carry Flag case STARS_NN_std: // Set Direction Flag return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_sti: // Set Interrupt Flag NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_stos: // Store String return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_str: // Store Task Register return false; break; case STARS_NN_sub: // Integer Subtraction return this->BuildBinaryRTL(SMP_SUBTRACT); case STARS_NN_test: // Logical Compare return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE); case STARS_NN_verr: // Verify a Segment for Reading case STARS_NN_verw: // Verify a Segment for Writing case STARS_NN_wait: // Wait until BUSY# Pin is Inactive (HIGH) NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; if (STARS_NN_wait != this->GetIDAOpcode()) this->RTL.ExtraKills.push_back(FlagsOp); return true; case STARS_NN_xchg: // Exchange Register/Memory with Register return this->BuildExchangeRTL(); case STARS_NN_xlat: // Table Lookup Translation return false; break; case STARS_NN_xor: // Logical Exclusive OR return this->BuildBinaryRTL(SMP_BITWISE_XOR); // // 486 instructions // case STARS_NN_cmpxchg: // Compare and Exchange return this->BuildCompareExchangeRTL(); case STARS_NN_bswap: // Swap bits in EAX return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case STARS_NN_xadd: // t<-dest; dest<-src+dest; src<-t return this->BuildExchangeAddRTL(); case STARS_NN_invd: // Invalidate Data Cache case STARS_NN_wbinvd: // Invalidate Data Cache (write changes) case STARS_NN_invlpg: // Invalidate TLB entry NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // // Pentium instructions // case STARS_NN_rdmsr: // Read Machine Status Register return this->BuildOptType8RTL(); case STARS_NN_wrmsr: // Write Machine Status Register return false; break; case STARS_NN_cpuid: // Get CPU ID return this->BuildOptType8RTL(); case STARS_NN_cmpxchg8b: // Compare and Exchange Eight Bytes return false; break; case STARS_NN_rdtsc: // Read Time Stamp Counter return this->BuildOptType8RTL(); case STARS_NN_rsm: // Resume from System Management Mode NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // // Pentium Pro instructions // case STARS_NN_cmova: // Move if Above (CF=0 & ZF=0) return this->BuildMoveRTL(SMP_ABOVE); case STARS_NN_cmovb: // Move if Below (CF=1) return this->BuildMoveRTL(SMP_BELOW); case STARS_NN_cmovbe: // Move if Below or Equal (CF=1 | ZF=1) return this->BuildMoveRTL(SMP_BELOW_EQUAL); case STARS_NN_cmovg: // Move if Greater (ZF=0 & SF=OF) return this->BuildMoveRTL(SMP_GREATER_THAN); case STARS_NN_cmovge: // Move if Greater or Equal (SF=OF) return this->BuildMoveRTL(SMP_GREATER_EQUAL); case STARS_NN_cmovl: // Move if Less (SF!=OF) return this->BuildMoveRTL(SMP_LESS_THAN); case STARS_NN_cmovle: // Move if Less or Equal (ZF=1 | SF!=OF) return this->BuildMoveRTL(SMP_LESS_EQUAL); case STARS_NN_cmovnb: // Move if Not Below (CF=0) return this->BuildMoveRTL(SMP_ABOVE_EQUAL); case STARS_NN_cmovno: // Move if Not Overflow (OF=0) case STARS_NN_cmovnp: // Move if Not Parity (PF=0) case STARS_NN_cmovns: // Move if Not Sign (SF=0) return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_cmovnz: // Move if Not Zero (ZF=0) return this->BuildMoveRTL(SMP_NOT_EQUAL); case STARS_NN_cmovo: // Move if Overflow (OF=1) case STARS_NN_cmovp: // Move if Parity (PF=1) case STARS_NN_cmovs: // Move if Sign (SF=1) return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_cmovz: // Move if Zero (ZF=1) return this->BuildMoveRTL(SMP_EQUAL); case STARS_NN_fcmovb: // Floating Move if Below return this->BuildMoveRTL(SMP_BELOW); case STARS_NN_fcmove: // Floating Move if Equal return this->BuildMoveRTL(SMP_EQUAL); case STARS_NN_fcmovbe: // Floating Move if Below or Equal return this->BuildMoveRTL(SMP_BELOW_EQUAL); case STARS_NN_fcmovu: // Floating Move if Unordered return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_fcmovnb: // Floating Move if Not Below return this->BuildMoveRTL(SMP_ABOVE_EQUAL); case STARS_NN_fcmovne: // Floating Move if Not Equal return this->BuildMoveRTL(SMP_NOT_EQUAL); case STARS_NN_fcmovnbe: // Floating Move if Not Below or Equal return this->BuildMoveRTL(SMP_ABOVE); case STARS_NN_fcmovnu: // Floating Move if Not Unordered return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_fcomi: // FP Compare: result in EFLAGS case STARS_NN_fucomi: // FP Unordered Compare: result in EFLAGS case STARS_NN_fcomip: // FP Compare: result in EFLAGS: pop stack case STARS_NN_fucomip: // FP Unordered Compare: result in EFLAGS: pop stack return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_rdpmc: // Read Performance Monitor Counter return this->BuildOptType8RTL(); // // FPP instructions // case STARS_NN_fld: // Load Real case STARS_NN_fst: // Store Real case STARS_NN_fstp: // Store Real and Pop return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_fxch: // Exchange Registers // FP registers remain NUMERIC anyway, so this is a no-op to our type system. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_fild: // Load Integer return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_fist: // Store Integer case STARS_NN_fistp: // Store Integer and Pop return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); case STARS_NN_fbld: // Load BCD case STARS_NN_fbstp: // Store BCD and Pop return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_fadd: // Add Real case STARS_NN_faddp: // Add Real and Pop case STARS_NN_fiadd: // Add Integer case STARS_NN_fsub: // Subtract Real case STARS_NN_fsubp: // Subtract Real and Pop case STARS_NN_fisub: // Subtract Integer case STARS_NN_fsubr: // Subtract Real Reversed case STARS_NN_fsubrp: // Subtract Real Reversed and Pop case STARS_NN_fisubr: // Subtract Integer Reversed case STARS_NN_fmul: // Multiply Real case STARS_NN_fmulp: // Multiply Real and Pop case STARS_NN_fimul: // Multiply Integer case STARS_NN_fdiv: // Divide Real case STARS_NN_fdivp: // Divide Real and Pop case STARS_NN_fidiv: // Divide Integer case STARS_NN_fdivr: // Divide Real Reversed case STARS_NN_fdivrp: // Divide Real Reversed and Pop case STARS_NN_fidivr: // Divide Integer Reversed return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC, true); case STARS_NN_fsqrt: // Square Root case STARS_NN_fscale: // Scale: st(0) <- st(0) * 2^st(1) case STARS_NN_fprem: // Partial Remainder case STARS_NN_frndint: // Round to Integer case STARS_NN_fxtract: // Extract exponent and significand case STARS_NN_fabs: // Absolute value case STARS_NN_fchs: // Change Sign return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC); case STARS_NN_fcom: // Compare Real case STARS_NN_fcomp: // Compare Real and Pop case STARS_NN_fcompp: // Compare Real and Pop Twice case STARS_NN_ficom: // Compare Integer case STARS_NN_ficomp: // Compare Integer and Pop case STARS_NN_ftst: // Test case STARS_NN_fxam: // Examine // Floating comparison instructions use FP reg stack locations // as sources and set only the FP flags. All of these are numeric // type and we don't track any of them, so all such instructions // can be considered to be no-ops. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_fptan: // Partial tangent case STARS_NN_fpatan: // Partial arctangent case STARS_NN_f2xm1: // 2^x - 1 case STARS_NN_fyl2x: // Y * lg2(X) case STARS_NN_fyl2xp1: // Y * lg2(X+1) // We can consider it a unary operation when both arguments come // off the floating point register stack, unless we ever start // modeling the different locations in the FP register stack. return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC); case STARS_NN_fldz: // Load +0.0 case STARS_NN_fld1: // Load +1.0 case STARS_NN_fldpi: // Load PI=3.14... case STARS_NN_fldl2t: // Load lg2(10) case STARS_NN_fldl2e: // Load lg2(e) case STARS_NN_fldlg2: // Load lg10(2) case STARS_NN_fldln2: // Load ln(2) case STARS_NN_finit: // Initialize Processor case STARS_NN_fninit: // Initialize Processor (no wait) case STARS_NN_fsetpm: // Set Protected Mode // Floating point stack and control word and flags operations // with no memory operands are no-ops to us. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_fldcw: // Load Control Word case STARS_NN_fstcw: // Store Control Word case STARS_NN_fnstcw: // Store Control Word (no wait) case STARS_NN_fstsw: // Store Status Word case STARS_NN_fnstsw: // Store Status Word (no wait) return this->BuildMoveRTL(SMP_NULL_OPERATOR); case STARS_NN_fclex: // Clear Exceptions case STARS_NN_fnclex: // Clear Exceptions (no wait) // Floating point stack and control word and flags operations // with no memory operands are no-ops to us. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_fstenv: // Store Environment case STARS_NN_fnstenv: // Store Environment (no wait) case STARS_NN_fldenv: // Load Environment case STARS_NN_fsave: // Save State case STARS_NN_fnsave: // Save State (no wait) case STARS_NN_frstor: // Restore State case STARS_NN_fincstp: // Increment Stack Pointer case STARS_NN_fdecstp: // Decrement Stack Pointer case STARS_NN_ffree: // Free Register // Floating point stack and control word and flags operations // with no memory operands are no-ops to us. // NOTE: We might want to deal with the memory operands in some // of these opcodes later. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_fnop: // No Operation NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_feni: // (8087 only) case STARS_NN_fneni: // (no wait) (8087 only) case STARS_NN_fdisi: // (8087 only) case STARS_NN_fndisi: // (no wait) (8087 only) return false; break; // // 80387 instructions // case STARS_NN_fprem1: // Partial Remainder ( < half ) case STARS_NN_fsincos: // t<-cos(st); st<-sin(st); push t case STARS_NN_fsin: // Sine case STARS_NN_fcos: // Cosine case STARS_NN_fucom: // Compare Unordered Real case STARS_NN_fucomp: // Compare Unordered Real and Pop case STARS_NN_fucompp: // Compare Unordered Real and Pop Twice // Floating point stack and control word and flags operations // with no memory operands are no-ops to us. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // // Instructions added 28.02.96 // case STARS_NN_setalc: // Set AL to Carry Flag case STARS_NN_svdc: // Save Register and Descriptor case STARS_NN_rsdc: // Restore Register and Descriptor case STARS_NN_svldt: // Save LDTR and Descriptor case STARS_NN_rsldt: // Restore LDTR and Descriptor case STARS_NN_svts: // Save TR and Descriptor case STARS_NN_rsts: // Restore TR and Descriptor case STARS_NN_icebp: // ICE Break Point case STARS_NN_loadall: // Load the entire CPU state from ES:EDI return false; break; // // MMX instructions // case STARS_NN_emms: // Empty MMX state NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; break; case STARS_NN_movd: // Move 32 bits case STARS_NN_movq: // Move 64 bits return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_packsswb: // Pack with Signed Saturation (Word->Byte) case STARS_NN_packssdw: // Pack with Signed Saturation (Dword->Word) return this->BuildBinaryRTL(SMP_PACK_S); break; case STARS_NN_packuswb: // Pack with Unsigned Saturation (Word->Byte) return this->BuildBinaryRTL(SMP_PACK_U); break; case STARS_NN_paddb: // Packed Add Byte case STARS_NN_paddw: // Packed Add Word case STARS_NN_paddd: // Packed Add Dword case STARS_NN_paddsb: // Packed Add with Saturation (Byte) case STARS_NN_paddsw: // Packed Add with Saturation (Word) case STARS_NN_paddusb: // Packed Add Unsigned with Saturation (Byte) case STARS_NN_paddusw: // Packed Add Unsigned with Saturation (Word) return this->BuildBinaryRTL(SMP_ADD); break; case STARS_NN_pand: // Bitwise Logical And return this->BuildBinaryRTL(SMP_BITWISE_AND); break; case STARS_NN_pandn: // Bitwise Logical And Not return this->BuildBinaryRTL(SMP_BITWISE_AND_NOT); break; case STARS_NN_pcmpeqb: // Packed Compare for Equal (Byte) case STARS_NN_pcmpeqw: // Packed Compare for Equal (Word) case STARS_NN_pcmpeqd: // Packed Compare for Equal (Dword) return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_pcmpgtb: // Packed Compare for Greater Than (Byte) case STARS_NN_pcmpgtw: // Packed Compare for Greater Than (Word) case STARS_NN_pcmpgtd: // Packed Compare for Greater Than (Dword) return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_pmaddwd: // Packed Multiply and Add return this->BuildBinaryRTL(SMP_MULTIPLY_AND_ADD); break; case STARS_NN_pmulhw: // Packed Multiply High case STARS_NN_pmullw: // Packed Multiply Low return this->BuildBinaryRTL(SMP_U_MULTIPLY); break; case STARS_NN_por: // Bitwise Logical Or return this->BuildBinaryRTL(SMP_BITWISE_OR); break; case STARS_NN_psllw: // Packed Shift Left Logical (Word) case STARS_NN_pslld: // Packed Shift Left Logical (Dword) case STARS_NN_psllq: // Packed Shift Left Logical (Qword) return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT); break; case STARS_NN_psraw: // Packed Shift Right Arithmetic (Word) case STARS_NN_psrad: // Packed Shift Right Arithmetic (Dword) return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT); break; case STARS_NN_psrlw: // Packed Shift Right Logical (Word) case STARS_NN_psrld: // Packed Shift Right Logical (Dword) case STARS_NN_psrlq: // Packed Shift Right Logical (Qword) return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT); break; case STARS_NN_psubb: // Packed Subtract Byte case STARS_NN_psubw: // Packed Subtract Word case STARS_NN_psubd: // Packed Subtract Dword return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_psubsb: // Packed Subtract with Saturation (Byte) case STARS_NN_psubsw: // Packed Subtract with Saturation (Word) return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_psubusb: // Packed Subtract Unsigned with Saturation (Byte) case STARS_NN_psubusw: // Packed Subtract Unsigned with Saturation (Word) return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_punpckhbw: // Unpack High Packed Data (Byte->Word) case STARS_NN_punpckhwd: // Unpack High Packed Data (Word->Dword) case STARS_NN_punpckhdq: // Unpack High Packed Data (Dword->Qword) case STARS_NN_punpcklbw: // Unpack Low Packed Data (Byte->Word) case STARS_NN_punpcklwd: // Unpack Low Packed Data (Word->Dword) case STARS_NN_punpckldq: // Unpack Low Packed Data (Dword->Qword) return this->BuildBinaryRTL(SMP_INTERLEAVE); break; case STARS_NN_pxor: // Bitwise Logical Exclusive Or return this->BuildBinaryRTL(SMP_BITWISE_XOR); break; // // Undocumented Deschutes processor instructions // case STARS_NN_fxsave: // Fast save FP context case STARS_NN_fxrstor: // Fast restore FP context return false; break; // Pentium II instructions case STARS_NN_sysenter: // Fast Transition to System Call Entry Point case STARS_NN_sysexit: // Fast Transition from System Call Entry Point return false; break; // 3DNow! instructions case STARS_NN_pavgusb: // Packed 8-bit Unsigned Integer Averaging return this->BuildBinaryRTL(SMP_AVERAGE_U); break; case STARS_NN_pfadd: // Packed Floating-Point Addition return this->BuildBinaryRTL(SMP_ADD); break; case STARS_NN_pfsub: // Packed Floating-Point Subtraction case STARS_NN_pfsubr: // Packed Floating-Point Reverse Subtraction !!!!****!!!! Fix this reversal if we care about the details return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_pfacc: // Packed Floating-Point Accumulate return this->BuildBinaryRTL(SMP_ADD); break; case STARS_NN_pfcmpge: // Packed Floating-Point Comparison: Greater or Equal return this->BuildBinaryRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_pfcmpgt: // Packed Floating-Point Comparison: Greater return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_pfcmpeq: // Packed Floating-Point Comparison: Equal return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_pfmin: // Packed Floating-Point Minimum return this->BuildBinaryRTL(SMP_MIN_S); break; case STARS_NN_pfmax: // Packed Floating-Point Maximum return this->BuildBinaryRTL(SMP_MAX_S); break; case STARS_NN_pi2fd: // Packed 32-bit Integer to Floating-Point return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_pf2id: // Packed Floating-Point to 32-bit Integer return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_pfrcp: // Packed Floating-Point Reciprocal Approximation case STARS_NN_pfrsqrt: // Packed Floating-Point Reciprocal Square Root Approximation return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_pfmul: // Packed Floating-Point Multiplication return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_pfrcpit1: // Packed Floating-Point Reciprocal First Iteration Step case STARS_NN_pfrsqit1: // Packed Floating-Point Reciprocal Square Root First Iteration Step case STARS_NN_pfrcpit2: // Packed Floating-Point Reciprocal Second Iteration Step return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_pmulhrw: // Packed Floating-Point 16-bit Integer Multiply with rounding return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_femms: // Faster entry/exit of the MMX or floating-point state NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; break; case STARS_NN_prefetch: // Prefetch at least a 32-byte line into L1 data cache case STARS_NN_prefetchw: // Prefetch processor cache line into L1 data cache (mark as modified) // Prefetch opcodes are no-ops to us. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // Pentium III instructions case STARS_NN_addps: // Packed Single-FP Add case STARS_NN_addss: // Scalar Single-FP Add return this->BuildBinaryRTL(SMP_FLOATING_ADD); break; case STARS_NN_andnps: // Bitwise Logical And Not for Single-FP case STARS_NN_andps: // Bitwise Logical And for Single-FP return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_cmpps: // Packed Single-FP Compare case STARS_NN_cmpss: // Scalar Single-FP Compare return this->BuildBinaryPlusImmedRTL(SMP_GENERAL_COMPARE, SMP_CREATE_MASK); break; case STARS_NN_comiss: // Scalar Ordered Single-FP Compare and Set EFLAGS return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_cvtpi2ps: // Packed signed INT32 to Packed Single-FP conversion return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_cvtps2pi: // Packed Single-FP to Packed INT32 conversion return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_cvtsi2ss: // Scalar signed INT32 to Single-FP conversion return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_cvtss2si: // Scalar Single-FP to signed INT32 conversion case STARS_NN_cvttps2pi: // Packed Single-FP to Packed INT32 conversion (truncate) case STARS_NN_cvttss2si: // Scalar Single-FP to signed INT32 conversion (truncate) return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_divps: // Packed Single-FP Divide case STARS_NN_divss: // Scalar Single-FP Divide return this->BuildBinaryRTL(SMP_FLOATING_DIVIDE); break; case STARS_NN_ldmxcsr: // Load Streaming SIMD Extensions Technology Control/Status Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_maxps: // Packed Single-FP Maximum case STARS_NN_maxss: // Scalar Single-FP Maximum return this->BuildBinaryRTL(SMP_MAX_S); break; case STARS_NN_minps: // Packed Single-FP Minimum case STARS_NN_minss: // Scalar Single-FP Minimum return this->BuildBinaryRTL(SMP_MIN_S); break; case STARS_NN_movaps: // Move Aligned Four Packed Single-FP case STARS_NN_movhlps: // Move High to Low Packed Single-FP case STARS_NN_movhps: // Move High Packed Single-FP case STARS_NN_movlhps: // Move Low to High Packed Single-FP case STARS_NN_movlps: // Move Low Packed Single-FP case STARS_NN_movmskps: // Move Mask to Register case STARS_NN_movss: // Move Scalar Single-FP case STARS_NN_movups: // Move Unaligned Four Packed Single-FP return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_mulps: // Packed Single-FP Multiply case STARS_NN_mulss: // Scalar Single-FP Multiply return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_orps: // Bitwise Logical OR for Single-FP Data return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_rcpps: // Packed Single-FP Reciprocal case STARS_NN_rcpss: // Scalar Single-FP Reciprocal case STARS_NN_rsqrtps: // Packed Single-FP Square Root Reciprocal case STARS_NN_rsqrtss: // Scalar Single-FP Square Root Reciprocal return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_shufps: // Shuffle Single-FP return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_sqrtps: // Packed Single-FP Square Root case STARS_NN_sqrtss: // Scalar Single-FP Square Root return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_stmxcsr: // Store Streaming SIMD Extensions Technology Control/Status Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_subps: // Packed Single-FP Subtract case STARS_NN_subss: // Scalar Single-FP Subtract return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT); break; case STARS_NN_ucomiss: // Scalar Unordered Single-FP Compare and Set EFLAGS return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_unpckhps: // Unpack High Packed Single-FP Data case STARS_NN_unpcklps: // Unpack Low Packed Single-FP Data return this->BuildBinaryRTL(SMP_INTERLEAVE); break; case STARS_NN_xorps: // Bitwise Logical XOR for Single-FP Data return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_pavgb: // Packed Average (Byte) case STARS_NN_pavgw: // Packed Average (Word) return this->BuildBinaryRTL(SMP_AVERAGE_U); break; case STARS_NN_pextrw: // Extract Word return this->BuildBinaryPlusImmedRTL(SMP_EXTRACT_ZERO_EXTEND, SMP_CREATE_MASK); break; case STARS_NN_pinsrw: // Insert Word return this->BuildBinaryPlusImmedRTL(SMP_BITWISE_AND, SMP_CREATE_MASK); break; case STARS_NN_pmaxsw: // Packed Signed Integer Word Maximum return this->BuildBinaryRTL(SMP_MAX_S); break; case STARS_NN_pmaxub: // Packed Unsigned Integer Byte Maximum return this->BuildBinaryRTL(SMP_MAX_U); break; case STARS_NN_pminsw: // Packed Signed Integer Word Minimum return this->BuildBinaryRTL(SMP_MIN_S); break; case STARS_NN_pminub: // Packed Unsigned Integer Byte Minimum return this->BuildBinaryRTL(SMP_MIN_U); break; case STARS_NN_pmovmskb: // Move Byte Mask to Integer return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_pmulhuw: // Packed Multiply High Unsigned return this->BuildBinaryRTL(SMP_U_MULTIPLY); break; case STARS_NN_psadbw: // Packed Sum of Absolute Differences return this->BuildBinaryRTL(SMP_SUM_OF_DIFFS); break; case STARS_NN_pshufw: // Packed Shuffle Word return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_maskmovq: // Byte Mask write return false; break; case STARS_NN_movntps: // Move Aligned Four Packed Single-FP Non Temporal case STARS_NN_movntq: // Move 64 Bits Non Temporal return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_prefetcht0: // Prefetch to all cache levels case STARS_NN_prefetcht1: // Prefetch to all cache levels case STARS_NN_prefetcht2: // Prefetch to L2 cache case STARS_NN_prefetchnta: // Prefetch to L1 cache case STARS_NN_sfence: // Store Fence // Cache prefetch and store fence opcodes are no-ops to us. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // Pentium III Pseudo instructions case STARS_NN_cmpeqps: // Packed Single-FP Compare EQ return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpltps: // Packed Single-FP Compare LT return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_cmpleps: // Packed Single-FP Compare LE return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_cmpunordps: // Packed Single-FP Compare UNORD return this->BuildBinaryRTL(SMP_GENERAL_COMPARE); break; case STARS_NN_cmpneqps: // Packed Single-FP Compare NOT EQ return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_cmpnltps: // Packed Single-FP Compare NOT LT return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_cmpnleps: // Packed Single-FP Compare NOT LE return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_cmpordps: // Packed Single-FP Compare ORDERED return this->BuildBinaryRTL(SMP_GENERAL_COMPARE); break; case STARS_NN_cmpeqss: // Scalar Single-FP Compare EQ return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpltss: // Scalar Single-FP Compare LT return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_cmpless: // Scalar Single-FP Compare LE return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_cmpunordss: // Scalar Single-FP Compare UNORD return this->BuildBinaryRTL(SMP_GENERAL_COMPARE); break; case STARS_NN_cmpneqss: // Scalar Single-FP Compare NOT EQ return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_cmpnltss: // Scalar Single-FP Compare NOT LT return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_cmpnless: // Scalar Single-FP Compare NOT LE return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_cmpordss: // Scalar Single-FP Compare ORDERED return this->BuildBinaryRTL(SMP_GENERAL_COMPARE); break; // AMD K7 instructions case STARS_NN_pf2iw: // Packed Floating-Point to Integer with Sign Extend return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_pfnacc: // Packed Floating-Point Negative Accumulate case STARS_NN_pfpnacc: // Packed Floating-Point Mixed Positive-Negative Accumulate return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_pi2fw: // Packed 16-bit Integer to Floating-Point return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_pswapd: // Packed Swap Double Word return this->BuildExchangeRTL(); break; // Undocumented FP instructions (thanks to norbert.juffa@adm.com) case STARS_NN_fstp1: // Alias of Store Real and Pop case STARS_NN_fcom2: // Alias of Compare Real case STARS_NN_fcomp3: // Alias of Compare Real and Pop case STARS_NN_fxch4: // Alias of Exchange Registers case STARS_NN_fcomp5: // Alias of Compare Real and Pop return false; break; case STARS_NN_ffreep: // Free Register and Pop; used in mplayer binary // Floating point stack and control word and flags operations // with no memory operands are no-ops to us. NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_fxch7: // Alias of Exchange Registers case STARS_NN_fstp8: // Alias of Store Real and Pop case STARS_NN_fstp9: // Alias of Store Real and Pop return false; break; // Pentium 4 instructions case STARS_NN_addpd: // Add Packed Double-Precision Floating-Point Values case STARS_NN_addsd: // Add Scalar Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_FLOATING_ADD); break; case STARS_NN_andnpd: // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values case STARS_NN_andpd: // Bitwise Logical AND of Packed Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_clflush: // Flush Cache Line NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; break; case STARS_NN_cmppd: // Compare Packed Double-Precision Floating-Point Values case STARS_NN_cmpsd: // Compare Scalar Double-Precision Floating-Point Values return this->BuildBinary3OpndRTL(SMP_GENERAL_COMPARE); break; case STARS_NN_comisd: // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_cvtdq2pd: // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values case STARS_NN_cvtdq2ps: // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_cvtpd2dq: // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_cvtpd2pi: // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_cvtpd2ps: // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_cvtpi2pd: // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_cvtps2dq: // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_cvtps2pd: // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values case STARS_NN_cvtsd2si: // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer case STARS_NN_cvtsd2ss: // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_cvtsi2sd: // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_cvtss2sd: // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value case STARS_NN_cvttpd2dq: // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_cvttpd2pi: // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_cvttps2dq: // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_cvttsd2si: // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_divpd: // Divide Packed Double-Precision Floating-Point Values case STARS_NN_divsd: // Divide Scalar Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_FLOATING_DIVIDE); break; case STARS_NN_lfence: // Load Fence NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_maskmovdqu: // Store Selected Bytes of Double Quadword return false; break; case STARS_NN_maxpd: // Return Maximum Packed Double-Precision Floating-Point Values case STARS_NN_maxsd: // Return Maximum Scalar Double-Precision Floating-Point Value return this->BuildBinaryRTL(SMP_MAX_S); break; case STARS_NN_mfence: // Memory Fence NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_minpd: // Return Minimum Packed Double-Precision Floating-Point Values case STARS_NN_minsd: // Return Minimum Scalar Double-Precision Floating-Point Value return this->BuildBinaryRTL(SMP_MIN_S); break; case STARS_NN_movapd: // Move Aligned Packed Double-Precision Floating-Point Values case STARS_NN_movdq2q: // Move Quadword from XMM to MMX Register case STARS_NN_movdqa: // Move Aligned Double Quadword case STARS_NN_movdqu: // Move Unaligned Double Quadword case STARS_NN_movhpd: // Move High Packed Double-Precision Floating-Point Values case STARS_NN_movlpd: // Move Low Packed Double-Precision Floating-Point Values return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_movmskpd: // Extract Packed Double-Precision Floating-Point Sign Mask return false; break; case STARS_NN_movntdq: // Store Double Quadword Using Non-Temporal Hint case STARS_NN_movnti: // Store Doubleword Using Non-Temporal Hint case STARS_NN_movntpd: // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint case STARS_NN_movq2dq: // Move Quadword from MMX to XMM Register case STARS_NN_movsd: // Move Scalar Double-Precision Floating-Point Values case STARS_NN_movupd: // Move Unaligned Packed Double-Precision Floating-Point Values return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_mulpd: // Multiply Packed Double-Precision Floating-Point Values case STARS_NN_mulsd: // Multiply Scalar Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_orpd: // Bitwise Logical OR of Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_paddq: // Add Packed Quadword Integers return this->BuildBinaryRTL(SMP_ADD); break; case STARS_NN_pause: // Spin Loop Hint NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case STARS_NN_pmuludq: // Multiply Packed Unsigned Doubleword Integers return this->BuildBinaryRTL(SMP_U_MULTIPLY); break; case STARS_NN_pshufd: // Shuffle Packed Doublewords case STARS_NN_pshufhw: // Shuffle Packed High Words case STARS_NN_pshuflw: // Shuffle Packed Low Words return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_pslldq: // Shift Double Quadword Left Logical return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT); break; case STARS_NN_psrldq: // Shift Double Quadword Right Logical return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT); break; case STARS_NN_psubq: // Subtract Packed Quadword Integers return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_punpckhqdq: // Unpack High Data case STARS_NN_punpcklqdq: // Unpack Low Data return this->BuildBinaryRTL(SMP_INTERLEAVE); break; case STARS_NN_shufpd: // Shuffle Packed Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_sqrtpd: // Compute Square Roots of Packed Double-Precision Floating-Point Values case STARS_NN_sqrtsd: // Compute Square Rootof Scalar Double-Precision Floating-Point Value return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_subpd: // Subtract Packed Double-Precision Floating-Point Values case STARS_NN_subsd: // Subtract Scalar Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT); break; case STARS_NN_ucomisd: // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_unpckhpd: // Unpack and Interleave High Packed Double-Precision Floating-Point Values case STARS_NN_unpcklpd: // Unpack and Interleave Low Packed Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_INTERLEAVE); break; case STARS_NN_xorpd: // Bitwise Logical OR of Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; // AMD syscall/sysret instructions case STARS_NN_syscall: // Low latency system call return this->BuildCallRTL(); case STARS_NN_sysret: // Return from system call // AMD64 instructions case STARS_NN_swapgs: // Exchange GS base with KernelGSBase MSR return false; break; // New Pentium instructions (SSE3) case STARS_NN_movddup: // Move One Double-FP and Duplicate case STARS_NN_movshdup: // Move Packed Single-FP High and Duplicate case STARS_NN_movsldup: // Move Packed Single-FP Low and Duplicate return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; // Missing AMD64 instructions : NOTE: Also found in Intel manual -- clc case STARS_NN_movsxd: // Move with Sign-Extend Doubleword return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); case STARS_NN_cmpxchg16b: // Compare and Exchange 16 Bytes return false; break; // SSE3 instructions case STARS_NN_addsubpd: // Add /Sub packed DP FP numbers case STARS_NN_addsubps: // Add /Sub packed SP FP numbers case STARS_NN_haddpd: // Add horizontally packed DP FP numbers case STARS_NN_haddps: // Add horizontally packed SP FP numbers case STARS_NN_hsubpd: // Sub horizontally packed DP FP numbers case STARS_NN_hsubps: // Sub horizontally packed SP FP numbers return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_monitor: // Set up a linear address range to be monitored by hardware case STARS_NN_mwait: // Wait until write-back store performed within the range specified by the MONITOR instruction NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; break; case STARS_NN_fisttp: // Store ST in intXX (chop) and pop return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_lddqu: // Load unaligned integer 128-bit return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; // SSSE3 instructions case STARS_NN_psignb: // Packed SIGN Byte case STARS_NN_psignw: // Packed SIGN Word case STARS_NN_psignd: // Packed SIGN Doubleword case STARS_NN_pshufb: // Packed Shuffle Bytes return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_pmulhrsw: // Packed Multiply High with Round and Scale return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_pmaddubsw: // Multiply and Add Packed Signed and Unsigned Bytes return this->BuildBinaryRTL(SMP_MULTIPLY_AND_ADD); break; case STARS_NN_phsubsw: // Packed Horizontal Subtract and Saturate return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_phaddsw: // Packed Horizontal Add and Saturate return this->BuildBinaryRTL(SMP_ADD); break; case STARS_NN_phaddw: // Packed Horizontal Add Word case STARS_NN_phaddd: // Packed Horizontal Add Doubleword return this->BuildBinaryRTL(SMP_ADD); break; case STARS_NN_phsubw: // Packed Horizontal Subtract Word case STARS_NN_phsubd: // Packed Horizontal Subtract Doubleword return this->BuildBinaryRTL(SMP_SUBTRACT); break; case STARS_NN_palignr: // Packed Align Right return this->BuildPackShiftRTL(SMP_CONCATENATE, SMP_REVERSE_SHIFT_U); break; case STARS_NN_pabsb: // Packed Absolute Value Byte case STARS_NN_pabsw: // Packed Absolute Value Word case STARS_NN_pabsd: // Packed Absolute Value Doubleword return this->BuildUnary2OpndRTL(SMP_ABSOLUTE_VALUE); break; // VMX instructions case STARS_NN_vmcall: // Call to VM Monitor case STARS_NN_vmclear: // Clear Virtual Machine Control Structure case STARS_NN_vmlaunch: // Launch Virtual Machine case STARS_NN_vmresume: // Resume Virtual Machine case STARS_NN_vmptrld: // Load Pointer to Virtual Machine Control Structure case STARS_NN_vmptrst: // Store Pointer to Virtual Machine Control Structure case STARS_NN_vmread: // Read Field from Virtual Machine Control Structure case STARS_NN_vmwrite: // Write Field from Virtual Machine Control Structure case STARS_NN_vmxoff: // Leave VMX Operation case STARS_NN_vmxon: // Enter VMX Operation return false; break; case STARS_NN_ud2: // Undefined Instruction // Should be unreachable, so make it a nop so the whole func can be analyzed NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // Added with x86-64 case STARS_NN_rdtscp: // Read Time-Stamp Counter and Processor ID return false; break; // Geode LX 3DNow! extensions case STARS_NN_pfrcpv: // Reciprocal Approximation for a Pair of 32-bit Floats case STARS_NN_pfrsqrtv: // Reciprocal Square Root Approximation for a Pair of 32-bit Floats return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; // SSE2 pseudoinstructions case STARS_NN_cmpeqpd: // Packed Double-FP Compare EQ return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpltpd: // Packed Double-FP Compare LT return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_cmplepd: // Packed Double-FP Compare LE return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_cmpunordpd: // Packed Double-FP Compare UNORD return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpneqpd: // Packed Double-FP Compare NOT EQ return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_cmpnltpd: // Packed Double-FP Compare NOT LT return this->BuildBinaryRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_cmpnlepd: // Packed Double-FP Compare NOT LE return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_cmpordpd: // Packed Double-FP Compare ORDERED return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpeqsd: // Scalar Double-FP Compare EQ return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpltsd: // Scalar Double-FP Compare LT return this->BuildBinaryRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_cmplesd: // Scalar Double-FP Compare LE return this->BuildBinaryRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_cmpunordsd: // Scalar Double-FP Compare UNORD return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_cmpneqsd: // Scalar Double-FP Compare NOT EQ return this->BuildBinaryRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_cmpnltsd: // Scalar Double-FP Compare NOT LT return this->BuildBinaryRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_cmpnlesd: // Scalar Double-FP Compare NOT LE return this->BuildBinaryRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_cmpordsd: // Scalar Double-FP Compare ORDERED return this->BuildBinaryRTL(SMP_COMPARE_EQ_AND_SET); break; // SSSE4.1 instructions case STARS_NN_blendpd: // Blend Packed Double Precision Floating-Point Values case STARS_NN_blendps: // Blend Packed Single Precision Floating-Point Values case STARS_NN_blendvpd: // Variable Blend Packed Double Precision Floating-Point Values case STARS_NN_blendvps: // Variable Blend Packed Single Precision Floating-Point Values return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_dppd: // Dot Product of Packed Double Precision Floating-Point Values case STARS_NN_dpps: // Dot Product of Packed Single Precision Floating-Point Values return this->BuildBinaryPlusImmedRTL(SMP_BINARY_FLOATING_ARITHMETIC, SMP_CREATE_MASK); break; case STARS_NN_extractps: // Extract Packed Single Precision Floating-Point Value case STARS_NN_insertps: // Insert Packed Single Precision Floating-Point Value case STARS_NN_movntdqa: // Load Double Quadword Non-Temporal Aligned Hint case STARS_NN_mpsadbw: // Compute Multiple Packed Sums of Absolute Difference return false; break; case STARS_NN_packusdw: // Pack with Unsigned Saturation return this->BuildBinaryRTL(SMP_PACK_U); break; case STARS_NN_pblendvb: // Variable Blend Packed Bytes case STARS_NN_pblendw: // Blend Packed Words return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_pcmpeqq: // Compare Packed Qword Data for Equal return false; break; case STARS_NN_pextrb: // Extract Byte case STARS_NN_pextrd: // Extract Dword case STARS_NN_pextrq: // Extract Qword return this->BuildBinaryPlusImmedRTL(SMP_EXTRACT_ZERO_EXTEND, SMP_CREATE_MASK); case STARS_NN_phminposuw: // Packed Horizontal Word Minimum return false; break; case STARS_NN_pinsrb: // Insert Byte case STARS_NN_pinsrd: // Insert Dword case STARS_NN_pinsrq: // Insert Qword return this->BuildBinaryPlusImmedRTL(SMP_BITWISE_AND, SMP_CREATE_MASK); break; case STARS_NN_pmaxsb: // Maximum of Packed Signed Byte Integers case STARS_NN_pmaxsd: // Maximum of Packed Signed Dword Integers return this->BuildBinaryRTL(SMP_MAX_S); break; case STARS_NN_pmaxud: // Maximum of Packed Unsigned Dword Integers case STARS_NN_pmaxuw: // Maximum of Packed Word Integers return this->BuildBinaryRTL(SMP_MAX_U); break; case STARS_NN_pminsb: // Minimum of Packed Signed Byte Integers case STARS_NN_pminsd: // Minimum of Packed Signed Dword Integers return this->BuildBinaryRTL(SMP_MIN_S); break; case STARS_NN_pminud: // Minimum of Packed Unsigned Dword Integers case STARS_NN_pminuw: // Minimum of Packed Word Integers return this->BuildBinaryRTL(SMP_MIN_U); break; case STARS_NN_pmovsxbw: // Packed Move with Sign Extend case STARS_NN_pmovsxbd: // Packed Move with Sign Extend case STARS_NN_pmovsxbq: // Packed Move with Sign Extend case STARS_NN_pmovsxwd: // Packed Move with Sign Extend case STARS_NN_pmovsxwq: // Packed Move with Sign Extend case STARS_NN_pmovsxdq: // Packed Move with Sign Extend return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); break; case STARS_NN_pmovzxbw: // Packed Move with Zero Extend case STARS_NN_pmovzxbd: // Packed Move with Zero Extend case STARS_NN_pmovzxbq: // Packed Move with Zero Extend case STARS_NN_pmovzxwd: // Packed Move with Zero Extend case STARS_NN_pmovzxwq: // Packed Move with Zero Extend case STARS_NN_pmovzxdq: // Packed Move with Zero Extend return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND); break; case STARS_NN_pmuldq: // Multiply Packed Signed Dword Integers case STARS_NN_pmulld: // Multiply Packed Signed Dword Integers and Store Low Result return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_ptest: // Logical Compare return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE); case STARS_NN_roundpd: // Round Packed Double Precision Floating-Point Values case STARS_NN_roundps: // Round Packed Single Precision Floating-Point Values case STARS_NN_roundsd: // Round Scalar Double Precision Floating-Point Values case STARS_NN_roundss: // Round Scalar Single Precision Floating-Point Values return this->BuildBinaryPlusImmedRTL(SMP_UNARY_FLOATING_ARITHMETIC, SMP_CREATE_MASK); break; // SSSE4.2 instructions case STARS_NN_crc32: // Accumulate CRC32 Value return false; break; case STARS_NN_pcmpestri: // Packed Compare Explicit Length Strings, Return Index case STARS_NN_pcmpestrm: // Packed Compare Explicit Length Strings, Return Mask case STARS_NN_pcmpistri: // Packed Compare Implicit Length Strings, Return Index case STARS_NN_pcmpistrm: // Packed Compare Implicit Length Strings, Return Mask return BuildBinaryIgnoreImmedRTL(SMP_GENERAL_COMPARE); break; case STARS_NN_pcmpgtq: // Compare Packed Data for Greater Than return false; break; case STARS_NN_popcnt: // Return the Count of Number of Bits Set to 1 return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION); // AMD SSE4a instructions case STARS_NN_extrq: // Extract Field From Register case STARS_NN_insertq: // Insert Field case STARS_NN_movntsd: // Move Non-Temporal Scalar Double-Precision Floating-Point case STARS_NN_movntss: // Move Non-Temporal Scalar Single-Precision Floating-Point case STARS_NN_lzcnt: // Leading Zero Count return false; break; // xsave/xrstor instructions case STARS_NN_xgetbv: // Get Value of Extended Control Register return this->BuildOptType8RTL(); case STARS_NN_xrstor: // Restore Processor Extended States case STARS_NN_xsave: // Save Processor Extended States case STARS_NN_xsetbv: // Set Value of Extended Control Register return false; break; // Intel Safer Mode Extensions (SMX) case STARS_NN_getsec: // Safer Mode Extensions (SMX) Instruction return false; break; // AMD-V Virtualization ISA Extension case STARS_NN_clgi: // Clear Global Interrupt Flag case STARS_NN_invlpga: // Invalidate TLB Entry in a Specified ASID case STARS_NN_skinit: // Secure Init and Jump with Attestation case STARS_NN_stgi: // Set Global Interrupt Flag case STARS_NN_vmexit: // Stop Executing Guest, Begin Executing Host case STARS_NN_vmload: // Load State from VMCB case STARS_NN_vmmcall: // Call VMM case STARS_NN_vmrun: // Run Virtual Machine case STARS_NN_vmsave: // Save State to VMCB return false; break; // VMX+ instructions case STARS_NN_invept: // Invalidate Translations Derived from EPT case STARS_NN_invvpid: // Invalidate Translations Based on VPID return false; break; // Intel Atom instructions case STARS_NN_movbe: // Move Data After Swapping Bytes return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION); // Intel AES instructions case STARS_NN_aesenc: // Perform One Round of an AES Encryption Flow case STARS_NN_aesenclast: // Perform the Last Round of an AES Encryption Flow case STARS_NN_aesdec: // Perform One Round of an AES Decryption Flow case STARS_NN_aesdeclast: // Perform the Last Round of an AES Decryption Flow case STARS_NN_aesimc: // Perform the AES InvMixColumn Transformation case STARS_NN_aeskeygenassist: // AES Round Key Generation Assist return this->BuildBinaryRTL(SMP_ENCRYPTION_OPERATION); break; // Carryless multiplication case STARS_NN_pclmulqdq: // Carry-Less Multiplication Quadword return BuildBinaryIgnoreImmedRTL(SMP_U_MULTIPLY); break; // Returns modified by operand size prefixes case STARS_NN_retnw: // Return Near from Procedure (use16) case STARS_NN_retnd: // Return Near from Procedure (use32) case STARS_NN_retnq: // Return Near from Procedure (use64) case STARS_NN_retfw: // Return Far from Procedure (use16) case STARS_NN_retfd: // Return Far from Procedure (use32) case STARS_NN_retfq: // Return Far from Procedure (use64) return this->BuildReturnRTL(); // RDRAND support case STARS_NN_rdrand: // Read Random Number return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); // new GPR instructions case STARS_NN_adcx: // Unsigned Integer Addition of Two Operands with Carry Flag case STARS_NN_adox: // Unsigned Integer Addition of Two Operands with Overflow Flag #if SMP_BUILD_SPECIAL_ADC_SBB_RTL return this->BuildBinaryPlusFlagsRTL(SMP_ADD_CARRY); #else return this->BuildBinaryRTL(SMP_ADD_CARRY); #endif case STARS_NN_andn: // Logical AND NOT case STARS_NN_bextr: // Bit Field Extract case STARS_NN_blsi: // Extract Lowest Set Isolated Bit case STARS_NN_blsmsk: // Get Mask Up to Lowest Set Bit case STARS_NN_blsr: // Reset Lowest Set Bit case STARS_NN_bzhi: // Zero High Bits Starting with Specified Bit Position return this->BuildBinaryPlusFlagsRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_clac: // Clear AC Flag in EFLAGS Register return false; case STARS_NN_mulx: // Unsigned Multiply Without Affecting Flags return this->BuildBinaryRTL(SMP_U_MULTIPLY); case STARS_NN_pdep: // Parallel Bits Deposit case STARS_NN_pext: // Parallel Bits Extract return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_rorx: // Rotate Right Logical Without Affecting Flags return this->BuildBinaryRTL(SMP_ROTATE_RIGHT); case STARS_NN_sarx: // Shift Arithmetically Right Without Affecting Flags return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT); case STARS_NN_shlx: // Shift Logically Left Without Affecting Flags case STARS_NN_shrx: // Shift Logically Right Without Affecting Flags return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT); case STARS_NN_stac: // Set AC Flag in EFLAGS Register return false; case STARS_NN_tzcnt: // Count the Number of Trailing Zero Bits return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_xsaveopt: // Save Processor Extended States Optimized case STARS_NN_invpcid: // Invalidate Processor Context ID return false; case STARS_NN_rdseed: // Read Random Seed return this->BuildBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case STARS_NN_rdfsbase: // Read FS Segment Base case STARS_NN_rdgsbase: // Read GS Segment Base case STARS_NN_wrfsbase: // Write FS Segment Base case STARS_NN_wrgsbase: // Write GS Segment Base return false; // new AVX instructions case STARS_NN_vaddpd: // Add Packed Double-Precision Floating-Point Values case STARS_NN_vaddps: // Packed Single-FP Add case STARS_NN_vaddsd: // Add Scalar Double-Precision Floating-Point Values case STARS_NN_vaddss: // Scalar Single-FP Add return this->BuildBinary3OpndRTL(SMP_FLOATING_ADD); break; case STARS_NN_vaddsubpd: // Add /Sub packed DP FP numbers case STARS_NN_vaddsubps: // Add /Sub packed SP FP numbers return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vaesdec: // Perform One Round of an AES Decryption Flow case STARS_NN_vaesdeclast: // Perform the Last Round of an AES Decryption Flow case STARS_NN_vaesenc: // Perform One Round of an AES Encryption Flow case STARS_NN_vaesenclast: // Perform the Last Round of an AES Encryption Flow case STARS_NN_vaesimc: // Perform the AES InvMixColumn Transformation case STARS_NN_vaeskeygenassist: // AES Round Key Generation Assist return this->BuildBinaryRTL(SMP_ENCRYPTION_OPERATION); break; case STARS_NN_vandnpd: // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values case STARS_NN_vandnps: // Bitwise Logical And Not for Single-FP case STARS_NN_vandpd: // Bitwise Logical AND of Packed Double-Precision Floating-Point Values case STARS_NN_vandps: // Bitwise Logical And for Single-FP return this->BuildBinary3OpndRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vblendpd: // Blend Packed Double Precision Floating-Point Values case STARS_NN_vblendps: // Blend Packed Single Precision Floating-Point Values case STARS_NN_vblendvpd: // Variable Blend Packed Double Precision Floating-Point Values case STARS_NN_vblendvps: // Variable Blend Packed Single Precision Floating-Point Values return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_vbroadcastf128: // Broadcast 128 Bits of Floating-Point Data case STARS_NN_vbroadcasti128: // Broadcast 128 Bits of Integer Data case STARS_NN_vbroadcastsd: // Broadcast Double-Precision Floating-Point Element case STARS_NN_vbroadcastss: // Broadcast Single-Precision Floating-Point Element return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vcmppd: // Compare Packed Double-Precision Floating-Point Values case STARS_NN_vcmpps: // Packed Single-FP Compare case STARS_NN_vcmpsd: // Compare Scalar Double-Precision Floating-Point Values case STARS_NN_vcmpss: // Scalar Single-FP Compare return false; break; case STARS_NN_vcomisd: // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS case STARS_NN_vcomiss: // Scalar Ordered Single-FP Compare and Set EFLAGS return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_vcvtdq2pd: // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values case STARS_NN_vcvtdq2ps: // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_vcvtpd2dq: // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_vcvtpd2ps: // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values case STARS_NN_vcvtph2ps: // Convert 16-bit FP Values to Single-Precision FP Values return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vcvtps2dq: // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_vcvtps2pd: // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values case STARS_NN_vcvtps2ph: // Convert Single-Precision FP value to 16-bit FP value return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vcvtsd2si: // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_vcvtsd2ss: // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vcvtsi2sd: // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value case STARS_NN_vcvtsi2ss: // Scalar signed INT32 to Single-FP conversion return this->BuildBinary3OpndRTL(SMP_CONVERT_INT_TO_FP); break; case STARS_NN_vcvtss2sd: // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vcvtss2si: // Scalar Single-FP to signed INT32 conversion return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_vcvttpd2dq: // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_vcvttps2dq: // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers case STARS_NN_vcvttsd2si: // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer case STARS_NN_vcvttss2si: // Scalar Single-FP to signed INT32 conversion (truncate) return this->BuildBinaryRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_vdivpd: // Divide Packed Double-Precision Floating-Point Values case STARS_NN_vdivps: // Packed Single-FP Divide case STARS_NN_vdivsd: // Divide Scalar Double-Precision Floating-Point Values case STARS_NN_vdivss: // Scalar Single-FP Divide return this->BuildBinary3OpndRTL(SMP_FLOATING_DIVIDE); break; case STARS_NN_vdppd: // Dot Product of Packed Double Precision Floating-Point Values case STARS_NN_vdpps: // Dot Product of Packed Single Precision Floating-Point Values return false; break; case STARS_NN_vextractf128: // Extract Packed Floating-Point Values case STARS_NN_vextracti128: // Extract Packed Integer Values case STARS_NN_vextractps: // Extract Packed Floating-Point Values return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vfmadd132pd: // Fused Multiply-Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfmadd132ps: // Fused Multiply-Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfmadd132sd: // Fused Multiply-Add of Scalar Double-Precision Floating-Point Values case STARS_NN_vfmadd132ss: // Fused Multiply-Add of Scalar Single-Precision Floating-Point Values case STARS_NN_vfmadd213pd: // Fused Multiply-Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfmadd213ps: // Fused Multiply-Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfmadd213sd: // Fused Multiply-Add of Scalar Double-Precision Floating-Point Values case STARS_NN_vfmadd213ss: // Fused Multiply-Add of Scalar Single-Precision Floating-Point Values case STARS_NN_vfmadd231pd: // Fused Multiply-Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfmadd231ps: // Fused Multiply-Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfmadd231sd: // Fused Multiply-Add of Scalar Double-Precision Floating-Point Values case STARS_NN_vfmadd231ss: // Fused Multiply-Add of Scalar Single-Precision Floating-Point Values case STARS_NN_vfmaddsub132pd: // Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfmaddsub132ps: // Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfmaddsub213pd: // Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfmaddsub213ps: // Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfmaddsub231pd: // Fused Multiply-Alternating Add/Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfmaddsub231ps: // Fused Multiply-Alternating Add/Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfmsub132pd: // Fused Multiply-Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfmsub132ps: // Fused Multiply-Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfmsub132sd: // Fused Multiply-Subtract of Scalar Double-Precision Floating-Point Values case STARS_NN_vfmsub132ss: // Fused Multiply-Subtract of Scalar Single-Precision Floating-Point Values case STARS_NN_vfmsub213pd: // Fused Multiply-Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfmsub213ps: // Fused Multiply-Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfmsub213sd: // Fused Multiply-Subtract of Scalar Double-Precision Floating-Point Values case STARS_NN_vfmsub213ss: // Fused Multiply-Subtract of Scalar Single-Precision Floating-Point Values case STARS_NN_vfmsub231pd: // Fused Multiply-Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfmsub231ps: // Fused Multiply-Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfmsub231sd: // Fused Multiply-Subtract of Scalar Double-Precision Floating-Point Values case STARS_NN_vfmsub231ss: // Fused Multiply-Subtract of Scalar Single-Precision Floating-Point Values case STARS_NN_vfmsubadd132pd: // Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfmsubadd132ps: // Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfmsubadd213pd: // Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfmsubadd213ps: // Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfmsubadd231pd: // Fused Multiply-Alternating Subtract/Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfmsubadd231ps: // Fused Multiply-Alternating Subtract/Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmadd132pd: // Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfnmadd132ps: // Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmadd132sd: // Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values case STARS_NN_vfnmadd132ss: // Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values case STARS_NN_vfnmadd213pd: // Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfnmadd213ps: // Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmadd213sd: // Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values case STARS_NN_vfnmadd213ss: // Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values case STARS_NN_vfnmadd231pd: // Fused Negative Multiply-Add of Packed Double-Precision Floating-Point Values case STARS_NN_vfnmadd231ps: // Fused Negative Multiply-Add of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmadd231sd: // Fused Negative Multiply-Add of Scalar Double-Precision Floating-Point Values case STARS_NN_vfnmadd231ss: // Fused Negative Multiply-Add of Scalar Single-Precision Floating-Point Values case STARS_NN_vfnmsub132pd: // Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfnmsub132ps: // Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmsub132sd: // Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values case STARS_NN_vfnmsub132ss: // Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values case STARS_NN_vfnmsub213pd: // Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfnmsub213ps: // Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmsub213sd: // Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values case STARS_NN_vfnmsub213ss: // Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values case STARS_NN_vfnmsub231pd: // Fused Negative Multiply-Subtract of Packed Double-Precision Floating-Point Values case STARS_NN_vfnmsub231ps: // Fused Negative Multiply-Subtract of Packed Single-Precision Floating-Point Values case STARS_NN_vfnmsub231sd: // Fused Negative Multiply-Subtract of Scalar Double-Precision Floating-Point Values case STARS_NN_vfnmsub231ss: // Fused Negative Multiply-Subtract of Scalar Single-Precision Floating-Point Values return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vgatherdps: // Gather Packed SP FP Values Using Signed Dword Indices case STARS_NN_vgatherdpd: // Gather Packed DP FP Values Using Signed Dword Indices case STARS_NN_vgatherqps: // Gather Packed SP FP Values Using Signed Qword Indices case STARS_NN_vgatherqpd: // Gather Packed DP FP Values Using Signed Qword Indices return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vhaddpd: // Add horizontally packed DP FP numbers case STARS_NN_vhaddps: // Add horizontally packed SP FP numbers return this->BuildBinaryRTL(SMP_FLOATING_ADD); break; case STARS_NN_vhsubpd: // Sub horizontally packed DP FP numbers case STARS_NN_vhsubps: // Sub horizontally packed SP FP numbers return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT); break; case STARS_NN_vinsertf128: // Insert Packed Floating-Point Values case STARS_NN_vinserti128: // Insert Packed Integer Values case STARS_NN_vinsertps: // Insert Packed Single Precision Floating-Point Value return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vlddqu: // Load Unaligned Packed Integer Values return false; break; case STARS_NN_vldmxcsr: // Load Streaming SIMD Extensions Technology Control/Status Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vmaskmovdqu: // Store Selected Bytes of Double Quadword with NT Hint case STARS_NN_vmaskmovpd: // Conditionally Load Packed Double-Precision Floating-Point Values case STARS_NN_vmaskmovps: // Conditionally Load Packed Single-Precision Floating-Point Values return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vmaxpd: // Return Maximum Packed Double-Precision Floating-Point Values case STARS_NN_vmaxps: // Packed Single-FP Maximum case STARS_NN_vmaxsd: // Return Maximum Scalar Double-Precision Floating-Point Value case STARS_NN_vmaxss: // Scalar Single-FP Maximum case STARS_NN_vminpd: // Return Minimum Packed Double-Precision Floating-Point Values case STARS_NN_vminps: // Packed Single-FP Minimum case STARS_NN_vminsd: // Return Minimum Scalar Double-Precision Floating-Point Value case STARS_NN_vminss: // Scalar Single-FP Minimum return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vmovapd: // Move Aligned Packed Double-Precision Floating-Point Values case STARS_NN_vmovaps: // Move Aligned Four Packed Single-FP case STARS_NN_vmovd: // Move 32 bits case STARS_NN_vmovddup: // Move One Double-FP and Duplicate case STARS_NN_vmovdqa: // Move Aligned Double Quadword case STARS_NN_vmovdqu: // Move Unaligned Double Quadword case STARS_NN_vmovhlps: // Move High to Low Packed Single-FP case STARS_NN_vmovhpd: // Move High Packed Double-Precision Floating-Point Values case STARS_NN_vmovhps: // Move High Packed Single-FP case STARS_NN_vmovlhps: // Move Low to High Packed Single-FP case STARS_NN_vmovlpd: // Move Low Packed Double-Precision Floating-Point Values case STARS_NN_vmovlps: // Move Low Packed Single-FP case STARS_NN_vmovmskpd: // Extract Packed Double-Precision Floating-Point Sign Mask case STARS_NN_vmovmskps: // Move Mask to Register case STARS_NN_vmovntdq: // Store Double Quadword Using Non-Temporal Hint case STARS_NN_vmovntdqa: // Load Double Quadword Non-Temporal Aligned Hint case STARS_NN_vmovntpd: // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint case STARS_NN_vmovntps: // Move Aligned Four Packed Single-FP Non Temporal #if (IDA_SDK_VERSION < 700) // Incredibly, these opcodes were removed in IDA Pro 7.0 case STARS_NN_vmovntsd: // Move Non-Temporal Scalar Double-Precision Floating-Point case STARS_NN_vmovntss: // Move Non-Temporal Scalar Single-Precision Floating-Point #endif case STARS_NN_vmovq: // Move 64 bits case STARS_NN_vmovsd: // Move Scalar Double-Precision Floating-Point Values case STARS_NN_vmovshdup: // Move Packed Single-FP High and Duplicate case STARS_NN_vmovsldup: // Move Packed Single-FP Low and Duplicate case STARS_NN_vmovss: // Move Scalar Single-FP case STARS_NN_vmovupd: // Move Unaligned Packed Double-Precision Floating-Point Values case STARS_NN_vmovups: // Move Unaligned Four Packed Single-FP return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vmpsadbw: // Compute Multiple Packed Sums of Absolute Difference return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vmulpd: // Multiply Packed Double-Precision Floating-Point Values case STARS_NN_vmulps: // Packed Single-FP Multiply case STARS_NN_vmulsd: // Multiply Scalar Double-Precision Floating-Point Values case STARS_NN_vmulss: // Scalar Single-FP Multiply return this->BuildBinary3OpndRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_vorpd: // Bitwise Logical OR of Double-Precision Floating-Point Values case STARS_NN_vorps: // Bitwise Logical OR for Single-FP Data case STARS_NN_vpabsb: // Packed Absolute Value Byte case STARS_NN_vpabsd: // Packed Absolute Value Doubleword case STARS_NN_vpabsw: // Packed Absolute Value Word case STARS_NN_vpackssdw: // Pack with Signed Saturation (Dword->Word) case STARS_NN_vpacksswb: // Pack with Signed Saturation (Word->Byte) case STARS_NN_vpackusdw: // Pack with Unsigned Saturation case STARS_NN_vpackuswb: // Pack with Unsigned Saturation (Word->Byte) return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vpaddb: // Packed Add Byte case STARS_NN_vpaddd: // Packed Add Dword case STARS_NN_vpaddq: // Add Packed Quadword Integers case STARS_NN_vpaddsb: // Packed Add with Saturation (Byte) case STARS_NN_vpaddsw: // Packed Add with Saturation (Word) case STARS_NN_vpaddusb: // Packed Add Unsigned with Saturation (Byte) case STARS_NN_vpaddusw: // Packed Add Unsigned with Saturation (Word) case STARS_NN_vpaddw: // Packed Add Word return this->BuildBinaryRTL(SMP_FLOATING_ADD); break; case STARS_NN_vpalignr: // Packed Align Right case STARS_NN_vpand: // Bitwise Logical And case STARS_NN_vpandn: // Bitwise Logical And Not case STARS_NN_vpavgb: // Packed Average (Byte) case STARS_NN_vpavgw: // Packed Average (Word) return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vpblendd: // Blend Packed Dwords case STARS_NN_vpblendvb: // Variable Blend Packed Bytes case STARS_NN_vpblendw: // Blend Packed Words return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_vpbroadcastb: // Broadcast a Byte Integer case STARS_NN_vpbroadcastd: // Broadcast a Dword Integer case STARS_NN_vpbroadcastq: // Broadcast a Qword Integer case STARS_NN_vpbroadcastw: // Broadcast a Word Integer case STARS_NN_vpclmulqdq: // Carry-Less Multiplication Quadword case STARS_NN_vpcmpeqb: // Packed Compare for Equal (Byte) case STARS_NN_vpcmpeqd: // Packed Compare for Equal (Dword) case STARS_NN_vpcmpeqq: // Compare Packed Qword Data for Equal case STARS_NN_vpcmpeqw: // Packed Compare for Equal (Word) case STARS_NN_vpcmpestri: // Packed Compare Explicit Length Strings, Return Index case STARS_NN_vpcmpestrm: // Packed Compare Explicit Length Strings, Return Mask case STARS_NN_vpcmpgtb: // Packed Compare for Greater Than (Byte) case STARS_NN_vpcmpgtd: // Packed Compare for Greater Than (Dword) case STARS_NN_vpcmpgtq: // Compare Packed Data for Greater Than case STARS_NN_vpcmpgtw: // Packed Compare for Greater Than (Word) case STARS_NN_vpcmpistri: // Packed Compare Implicit Length Strings, Return Index case STARS_NN_vpcmpistrm: // Packed Compare Implicit Length Strings, Return Mask case STARS_NN_vperm2f128: // Permute Floating-Point Values case STARS_NN_vperm2i128: // Permute Integer Values case STARS_NN_vpermd: // Full Doublewords Element Permutation case STARS_NN_vpermilpd: // Permute Double-Precision Floating-Point Values case STARS_NN_vpermilps: // Permute Single-Precision Floating-Point Values case STARS_NN_vpermpd: // Permute Double-Precision Floating-Point Elements case STARS_NN_vpermps: // Permute Single-Precision Floating-Point Elements case STARS_NN_vpermq: // Qwords Element Permutation case STARS_NN_vpextrb: // Extract Byte case STARS_NN_vpextrd: // Extract Dword case STARS_NN_vpextrq: // Extract Qword case STARS_NN_vpextrw: // Extract Word case STARS_NN_vpgatherdd: // Gather Packed Dword Values Using Signed Dword Indices case STARS_NN_vpgatherdq: // Gather Packed Qword Values Using Signed Dword Indices case STARS_NN_vpgatherqd: // Gather Packed Dword Values Using Signed Qword Indices case STARS_NN_vpgatherqq: // Gather Packed Qword Values Using Signed Qword Indices return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vphaddd: // Packed Horizontal Add Doubleword case STARS_NN_vphaddsw: // Packed Horizontal Add and Saturate case STARS_NN_vphaddw: // Packed Horizontal Add Word return this->BuildBinaryRTL(SMP_FLOATING_ADD); break; case STARS_NN_vphminposuw: // Packed Horizontal Word Minimum return false; break; case STARS_NN_vphsubd: // Packed Horizontal Subtract Doubleword case STARS_NN_vphsubsw: // Packed Horizontal Subtract and Saturate case STARS_NN_vphsubw: // Packed Horizontal Subtract Word return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT); break; case STARS_NN_vpinsrb: // Insert Byte case STARS_NN_vpinsrd: // Insert Dword case STARS_NN_vpinsrq: // Insert Qword case STARS_NN_vpinsrw: // Insert Word return false; break; case STARS_NN_vpmaddubsw: // Multiply and Add Packed Signed and Unsigned Bytes case STARS_NN_vpmaddwd: // Packed Multiply and Add return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vpmaskmovd: // Conditionally Store Dword Values Using Mask case STARS_NN_vpmaskmovq: // Conditionally Store Qword Values Using Mask return false; break; case STARS_NN_vpmaxsb: // Maximum of Packed Signed Byte Integers case STARS_NN_vpmaxsd: // Maximum of Packed Signed Dword Integers case STARS_NN_vpmaxsw: // Packed Signed Integer Word Maximum return this->BuildBinaryRTL(SMP_MAX_S); break; case STARS_NN_vpmaxub: // Packed Unsigned Integer Byte Maximum case STARS_NN_vpmaxud: // Maximum of Packed Unsigned Dword Integers case STARS_NN_vpmaxuw: // Maximum of Packed Word Integers return this->BuildBinaryRTL(SMP_MAX_U); break; case STARS_NN_vpminsb: // Minimum of Packed Signed Byte Integers case STARS_NN_vpminsd: // Minimum of Packed Signed Dword Integers case STARS_NN_vpminsw: // Packed Signed Integer Word Minimum return this->BuildBinaryRTL(SMP_MIN_S); break; case STARS_NN_vpminub: // Packed Unsigned Integer Byte Minimum case STARS_NN_vpminud: // Minimum of Packed Unsigned Dword Integers case STARS_NN_vpminuw: // Minimum of Packed Word Integers return this->BuildBinaryRTL(SMP_MIN_U); break; case STARS_NN_vpmovmskb: // Move Byte Mask to Integer return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vpmovsxbd: // Packed Move with Sign Extend case STARS_NN_vpmovsxbq: // Packed Move with Sign Extend case STARS_NN_vpmovsxbw: // Packed Move with Sign Extend case STARS_NN_vpmovsxdq: // Packed Move with Sign Extend case STARS_NN_vpmovsxwd: // Packed Move with Sign Extend case STARS_NN_vpmovsxwq: // Packed Move with Sign Extend return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); break; case STARS_NN_vpmovzxbd: // Packed Move with Zero Extend case STARS_NN_vpmovzxbq: // Packed Move with Zero Extend case STARS_NN_vpmovzxbw: // Packed Move with Zero Extend case STARS_NN_vpmovzxdq: // Packed Move with Zero Extend case STARS_NN_vpmovzxwd: // Packed Move with Zero Extend case STARS_NN_vpmovzxwq: // Packed Move with Zero Extend return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND); break; case STARS_NN_vpmuldq: // Multiply Packed Signed Dword Integers case STARS_NN_vpmulhrsw: // Packed Multiply High with Round and Scale case STARS_NN_vpmulhuw: // Packed Multiply High Unsigned case STARS_NN_vpmulhw: // Packed Multiply High case STARS_NN_vpmulld: // Multiply Packed Signed Dword Integers and Store Low Result case STARS_NN_vpmullw: // Packed Multiply Low case STARS_NN_vpmuludq: // Multiply Packed Unsigned Doubleword Integers case STARS_NN_vpor: // Bitwise Logical Or case STARS_NN_vpsadbw: // Packed Sum of Absolute Differences return this->BuildBinaryRTL(SMP_FLOATING_MULTIPLY); break; case STARS_NN_vpshufb: // Packed Shuffle Bytes case STARS_NN_vpshufd: // Shuffle Packed Doublewords case STARS_NN_vpshufhw: // Shuffle Packed High Words case STARS_NN_vpshuflw: // Shuffle Packed Low Words return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_vpsignb: // Packed SIGN Byte case STARS_NN_vpsignd: // Packed SIGN Doubleword case STARS_NN_vpsignw: // Packed SIGN Word return false; break; case STARS_NN_vpslld: // Packed Shift Left Logical (Dword) case STARS_NN_vpslldq: // Shift Double Quadword Left Logical case STARS_NN_vpsllq: // Packed Shift Left Logical (Qword) case STARS_NN_vpsllvd: // Variable Bit Shift Left Logical (Dword) case STARS_NN_vpsllvq: // Variable Bit Shift Left Logical (Qword) case STARS_NN_vpsllw: // Packed Shift Left Logical (Word) case STARS_NN_vpsrad: // Packed Shift Right Arithmetic (Dword) case STARS_NN_vpsravd: // Variable Bit Shift Right Arithmetic case STARS_NN_vpsraw: // Packed Shift Right Arithmetic (Word) case STARS_NN_vpsrld: // Packed Shift Right Logical (Dword) case STARS_NN_vpsrldq: // Shift Double Quadword Right Logical (Qword) case STARS_NN_vpsrlq: // Packed Shift Right Logical (Qword) case STARS_NN_vpsrlvd: // Variable Bit Shift Right Logical (Dword) case STARS_NN_vpsrlvq: // Variable Bit Shift Right Logical (Qword) case STARS_NN_vpsrlw: // Packed Shift Right Logical (Word) return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vpsubb: // Packed Subtract Byte case STARS_NN_vpsubd: // Packed Subtract Dword case STARS_NN_vpsubq: // Subtract Packed Quadword Integers case STARS_NN_vpsubsb: // Packed Subtract with Saturation (Byte) case STARS_NN_vpsubsw: // Packed Subtract with Saturation (Word) case STARS_NN_vpsubusb: // Packed Subtract Unsigned with Saturation (Byte) case STARS_NN_vpsubusw: // Packed Subtract Unsigned with Saturation (Word) case STARS_NN_vpsubw: // Packed Subtract Word return this->BuildBinaryRTL(SMP_FLOATING_SUBTRACT); break; case STARS_NN_vptest: // Logical Compare return false; break; case STARS_NN_vpunpckhbw: // Unpack High Packed Data (Byte->Word) case STARS_NN_vpunpckhdq: // Unpack High Packed Data (Dword->Qword) case STARS_NN_vpunpckhqdq: // Unpack High Packed Data (Qword->Xmmword) case STARS_NN_vpunpckhwd: // Unpack High Packed Data (Word->Dword) case STARS_NN_vpunpcklbw: // Unpack Low Packed Data (Byte->Word) case STARS_NN_vpunpckldq: // Unpack Low Packed Data (Dword->Qword) case STARS_NN_vpunpcklqdq: // Unpack Low Packed Data (Qword->Xmmword) case STARS_NN_vpunpcklwd: // Unpack Low Packed Data (Word->Dword) return this->BuildBinaryRTL(SMP_INTERLEAVE); break; case STARS_NN_vpxor: // Bitwise Logical Exclusive Or case STARS_NN_vrcpps: // Packed Single-FP Reciprocal case STARS_NN_vrcpss: // Scalar Single-FP Reciprocal return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vroundpd: // Round Packed Double Precision Floating-Point Values case STARS_NN_vroundps: // Round Packed Single Precision Floating-Point Values case STARS_NN_vroundsd: // Round Scalar Double Precision Floating-Point Values case STARS_NN_vroundss: // Round Scalar Single Precision Floating-Point Values return this->BuildUnary2OpndRTL(SMP_CONVERT_FP_TO_INT); break; case STARS_NN_vrsqrtps: // Packed Single-FP Square Root Reciprocal case STARS_NN_vrsqrtss: // Scalar Single-FP Square Root Reciprocal return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_vshufpd: // Shuffle Packed Double-Precision Floating-Point Values case STARS_NN_vshufps: // Shuffle Single-FP return this->BuildBinaryRTL(SMP_SHUFFLE); break; case STARS_NN_vsqrtpd: // Compute Square Roots of Packed Double-Precision Floating-Point Values case STARS_NN_vsqrtps: // Packed Single-FP Square Root case STARS_NN_vsqrtsd: // Compute Square Rootof Scalar Double-Precision Floating-Point Value case STARS_NN_vsqrtss: // Scalar Single-FP Square Root return this->BuildUnary2OpndRTL(SMP_UNARY_FLOATING_ARITHMETIC); break; case STARS_NN_vstmxcsr: // Store Streaming SIMD Extensions Technology Control/Status Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); break; case STARS_NN_vsubpd: // Subtract Packed Double-Precision Floating-Point Values case STARS_NN_vsubps: // Packed Single-FP Subtract case STARS_NN_vsubsd: // Subtract Scalar Double-Precision Floating-Point Values case STARS_NN_vsubss: // Scalar Single-FP Subtract return this->BuildBinary3OpndRTL(SMP_FLOATING_SUBTRACT); break; case STARS_NN_vtestpd: // Packed Double-Precision Floating-Point Bit Test case STARS_NN_vtestps: // Packed Single-Precision Floating-Point Bit Test case STARS_NN_vucomisd: // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS case STARS_NN_vucomiss: // Scalar Unordered Single-FP Compare and Set EFLAGS return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); break; case STARS_NN_vunpckhpd: // Unpack and Interleave High Packed Double-Precision Floating-Point Values case STARS_NN_vunpckhps: // Unpack High Packed Single-FP Data case STARS_NN_vunpcklpd: // Unpack and Interleave Low Packed Double-Precision Floating-Point Values case STARS_NN_vunpcklps: // Unpack Low Packed Single-FP Data return this->BuildBinary3OpndRTL(SMP_INTERLEAVE); break; case STARS_NN_vxorpd: // Bitwise Logical OR of Double-Precision Floating-Point Values case STARS_NN_vxorps: // Bitwise Logical XOR for Single-FP Data return this->BuildBinary3OpndRTL(SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vzeroall: // Zero All YMM Registers case STARS_NN_vzeroupper: // Zero Upper Bits of YMM Registers NopRT = new SMPRegTransfer; NopRT->SetParentInst(this); NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // Transactional Synchronization Extensions case STARS_NN_xabort: // Transaction Abort case STARS_NN_xbegin: // Transaction Begin case STARS_NN_xend: // Transaction End case STARS_NN_xtest: // Test If In Transactional Execution return false; break; // Virtual PC synthetic instructions case STARS_NN_vmgetinfo: // Virtual PC - Get VM Information case STARS_NN_vmsetinfo: // Virtual PC - Set VM Information case STARS_NN_vmdxdsbl: // Virtual PC - Disable Direct Execution case STARS_NN_vmdxenbl: // Virtual PC - Enable Direct Execution case STARS_NN_vmcpuid: // Virtual PC - Virtualized CPU Information case STARS_NN_vmhlt: // Virtual PC - Halt case STARS_NN_vmsplaf: // Virtual PC - Spin Lock Acquisition Failed case STARS_NN_vmpushfd: // Virtual PC - Push virtualized flags register case STARS_NN_vmpopfd: // Virtual PC - Pop virtualized flags register case STARS_NN_vmcli: // Virtual PC - Clear Interrupt Flag case STARS_NN_vmsti: // Virtual PC - Set Interrupt Flag case STARS_NN_vmiretd: // Virtual PC - Return From Interrupt case STARS_NN_vmsgdt: // Virtual PC - Store Global Descriptor Table case STARS_NN_vmsidt: // Virtual PC - Store Interrupt Descriptor Table case STARS_NN_vmsldt: // Virtual PC - Store Local Descriptor Table case STARS_NN_vmstr: // Virtual PC - Store Task Register case STARS_NN_vmsdte: // Virtual PC - Store to Descriptor Table Entry case STARS_NN_vpcext: // Virtual PC - ISA extension return false; break; // AMD FMA4 case STARS_NN_vfmaddsubps: // Multiply with Alternating Add/Subtract of Packed Single-Precision Floating-Point case STARS_NN_vfmaddsubpd: // Multiply with Alternating Add/Subtract of Packed Double-Precision Floating-Point case STARS_NN_vfmsubaddps: // Multiply with Alternating Subtract/Add of Packed Single-Precision Floating-Point case STARS_NN_vfmsubaddpd: // Multiply with Alternating Subtract/Add of Packed Double-Precision Floating-Point return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_BINARY_FLOATING_ARITHMETIC); break; case STARS_NN_vfmaddps: // Multiply and Add Packed Single-Precision Floating-Point case STARS_NN_vfmaddpd: // Multiply and Add Packed Double-Precision Floating-Point case STARS_NN_vfmaddss: // Multiply and Add Scalar Single-Precision Floating-Point case STARS_NN_vfmaddsd: // Multiply and Add Scalar Double-Precision Floating-Point return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_FLOATING_ADD); break; case STARS_NN_vfmsubps: // Multiply and Subtract Packed Single-Precision Floating-Point case STARS_NN_vfmsubpd: // Multiply and Subtract Packed Double-Precision Floating-Point case STARS_NN_vfmsubss: // Multiply and Subtract Scalar Single-Precision Floating-Point case STARS_NN_vfmsubsd: // Multiply and Subtract Scalar Double-Precision Floating-Point return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_FLOATING_SUBTRACT); break; case STARS_NN_vfnmaddps: // Negative Multiply and Add Packed Single-Precision Floating-Point case STARS_NN_vfnmaddpd: // Negative Multiply and Add Packed Double-Precision Floating-Point case STARS_NN_vfnmaddss: // Negative Multiply and Add Scalar Single-Precision Floating-Point case STARS_NN_vfnmaddsd: // Negative Multiply and Add Double Single-Precision Floating-Point case STARS_NN_vfnmsubps: // Negative Multiply and Subtract Packed Single-Precision Floating-Point case STARS_NN_vfnmsubpd: // Negative Multiply and Subtract Packed Double-Precision Floating-Point case STARS_NN_vfnmsubss: // Negative Multiply and Subtract Scalar Single-Precision Floating-Point case STARS_NN_vfnmsubsd: // Negative Multiply and Subtract Double Single-Precision Floating-Point return this->BuildMultAddOrSub4OpndRTL(SMP_FLOATING_MULTIPLY, SMP_FLOATING_NEGATE_AND_ADD); break; // Intel Memory Protection Extensions (MPX) case STARS_NN_bndmk: // Make Bounds case STARS_NN_bndcl: // Check Lower Bound case STARS_NN_bndcu: // Check Upper Bound case STARS_NN_bndcn: // Check Upper Bound case STARS_NN_bndmov: // Move Bounds case STARS_NN_bndldx: // Load Extended Bounds Using Address Translation case STARS_NN_bndstx: // Store Extended Bounds Using Address Translation return false; break; // New xstate instructions case STARS_NN_xrstors: // Restore Processor Extended States Supervisor case STARS_NN_xsavec: // Save Processor Extended States with Compaction case STARS_NN_xsaves: // Save Processor Extended States Supervisor return false; break; // PREFETCHWT1 support case STARS_NN_prefetchwt1: // Prefetch Vector Data Into Caches with Intent to Write and T1 Hint return false; break; // Memory instructions case STARS_NN_clflushopt: // Flush a Cache Line Optimized case STARS_NN_clwb: // Cache Line Write Back case STARS_NN_pcommit: // Persistent Commit (deprecated by Intel) return false; break; // Protection Key Rights for User Pages case STARS_NN_rdpkru: // Read Protection Key Rights for User Pages case STARS_NN_wrpkru: // Write Data to User Page Key Register return false; break; // AVX comparison pseudo-ops case STARS_NN_vcmpeqpd: // Compare Packed Double-Precision Floating-Point Values - Equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); case STARS_NN_vcmpltpd: // Compare Packed Double-Precision Floating-Point Values - Less-than (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); case STARS_NN_vcmplepd: // Compare Packed Double-Precision Floating-Point Values - Less-than-or-equal (ordered, signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); case STARS_NN_vcmpunordpd: // Compare Packed Double-Precision Floating-Point Values - Unordered (non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); case STARS_NN_vcmpneqpd: // Compare Packed Double-Precision Floating-Point Values - Not-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); case STARS_NN_vcmpnltpd: // Compare Packed Double-Precision Floating-Point Values - Not-less-than (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); case STARS_NN_vcmpnlepd: // Compare Packed Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered, signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); case STARS_NN_vcmpordpd: // Compare Packed Double-Precision Floating-Point Values - Ordered (non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); case STARS_NN_vcmpeq_uqpd: // Compare Packed Double-Precision Floating-Point Values - Equal (unordered: non-signaling) case STARS_NN_vcmpngepd: // Compare Packed Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered, signaling) case STARS_NN_vcmpngtpd: // Compare Packed Double-Precision Floating-Point Values - Not-greater-than (unordered: signaling) case STARS_NN_vcmpfalsepd: // Compare Packed Double-Precision Floating-Point Values - False (ordered, non-signaling) case STARS_NN_vcmpneq_oqpd: // Compare Packed Double-Precision Floating-Point Values - Not-equal (ordered: non-signaling) case STARS_NN_vcmpgepd: // Compare Packed Double-Precision Floating-Point Values - Greater-than-or-equal (ordered, signaling) case STARS_NN_vcmpgtpd: // Compare Packed Double-Precision Floating-Point Values - Greater-than (ordered, signaling) case STARS_NN_vcmptruepd: // Compare Packed Double-Precision Floating-Point Values - True (unordered, non-signaling) case STARS_NN_vcmpeq_ospd: // Compare Packed Double-Precision Floating-Point Values - Equal (ordered: signaling) case STARS_NN_vcmplt_oqpd: // Compare Packed Double-Precision Floating-Point Values - Less-than (ordered: non-signaling) case STARS_NN_vcmple_oqpd: // Compare Packed Double-Precision Floating-Point Values - Less-than-or-equal (ordered, non-signaling) case STARS_NN_vcmpunord_spd: // Compare Packed Double-Precision Floating-Point Values - Unordered (signaling) case STARS_NN_vcmpneq_uspd: // Compare Packed Double-Precision Floating-Point Values - Not-equal (unordered: signaling) case STARS_NN_vcmpnlt_uqpd: // Compare Packed Double-Precision Floating-Point Values - Not-less-than (unordered: non-signaling) case STARS_NN_vcmpnle_uqpd: // Compare Packed Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered, non-signaling) case STARS_NN_vcmpord_spd: // Compare Packed Double-Precision Floating-Point Values - Ordered (signaling) case STARS_NN_vcmpeq_uspd: // Compare Packed Double-Precision Floating-Point Values - Equal (unordered: signaling) case STARS_NN_vcmpnge_uqpd: // Compare Packed Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered, non-signaling) case STARS_NN_vcmpngt_uqpd: // Compare Packed Double-Precision Floating-Point Values - Not-greater-than (unordered, non-signaling) case STARS_NN_vcmpfalse_ospd: // Compare Packed Double-Precision Floating-Point Values - False (ordered, signaling) case STARS_NN_vcmpneq_ospd: // Compare Packed Double-Precision Floating-Point Values - Not-equal (ordered: signaling) case STARS_NN_vcmpge_oqpd: // Compare Packed Double-Precision Floating-Point Values - Greater-than-or-equal (ordered: non-signaling) case STARS_NN_vcmpgt_oqpd: // Compare Packed Double-Precision Floating-Point Values - Greater-than (ordered, non-signaling) case STARS_NN_vcmptrue_uspd: // Compare Packed Double-Precision Floating-Point Values - True (unordered, signaling) case STARS_NN_vcmpeqps: // Packed Single-FP Compare - Equal (ordered, non-signaling) case STARS_NN_vcmpltps: // Packed Single-FP Compare - Less-than (ordered: signaling) case STARS_NN_vcmpleps: // Packed Single-FP Compare - Less-than-or-equal (ordered, signaling) case STARS_NN_vcmpunordps: // Packed Single-FP Compare - Unordered (non-signaling) case STARS_NN_vcmpneqps: // Packed Single-FP Compare - Not-equal (unordered, non-signaling) case STARS_NN_vcmpnltps: // Packed Single-FP Compare - Not-less-than (unordered, signaling) case STARS_NN_vcmpnleps: // Packed Single-FP Compare - Not-less-than-or-equal (unordered, signaling) case STARS_NN_vcmpordps: // Packed Single-FP Compare - Ordered (non-signaling) case STARS_NN_vcmpeq_uqps: // Packed Single-FP Compare - Equal (unordered, non-signaling) case STARS_NN_vcmpngeps: // Packed Single-FP Compare - Not-greater-than-or-equal (unordered, signaling) case STARS_NN_vcmpngtps: // Packed Single-FP Compare - Not-greater-than (unordered, signaling) case STARS_NN_vcmpfalseps: // Packed Single-FP Compare - False (ordered, non-signaling) case STARS_NN_vcmpneq_oqps: // Packed Single-FP Compare - Not-equal (ordered: non-signaling) case STARS_NN_vcmpgeps: // Packed Single-FP Compare - Greater-than-or-equal (ordered: signaling) case STARS_NN_vcmpgtps: // Packed Single-FP Compare - Greater-than (ordered: signaling) case STARS_NN_vcmptrueps: // Packed Single-FP Compare - True (unordered: non-signaling) case STARS_NN_vcmpeq_osps: // Packed Single-FP Compare - Equal (ordered: signaling) case STARS_NN_vcmplt_oqps: // Packed Single-FP Compare - Less-than (ordered: non-signaling) case STARS_NN_vcmple_oqps: // Packed Single-FP Compare - Less-than-or-equal (ordered: non-signaling) case STARS_NN_vcmpunord_sps: // Packed Single-FP Compare - Unordered (signaling) case STARS_NN_vcmpneq_usps: // Packed Single-FP Compare - Not-equal (unordered: signaling) case STARS_NN_vcmpnlt_uqps: // Packed Single-FP Compare - Not-less-than (unordered: non-signaling) case STARS_NN_vcmpnle_uqps: // Packed Single-FP Compare - Not-less-than-or-equal (unordered: non-signaling) case STARS_NN_vcmpord_sps: // Packed Single-FP Compare - Ordered (signaling) case STARS_NN_vcmpeq_usps: // Packed Single-FP Compare - Equal (unordered: signaling) case STARS_NN_vcmpnge_uqps: // Packed Single-FP Compare - Not-greater-than-or-equal (unordered: non-signaling) case STARS_NN_vcmpngt_uqps: // Packed Single-FP Compare - Not-greater-than (unordered: non-signaling) case STARS_NN_vcmpfalse_osps: // Packed Single-FP Compare - False (ordered: signaling) case STARS_NN_vcmpneq_osps: // Packed Single-FP Compare - Not-equal (ordered: signaling) case STARS_NN_vcmpge_oqps: // Packed Single-FP Compare - Greater-than-or-equal (ordered: non-signaling) case STARS_NN_vcmpgt_oqps: // Packed Single-FP Compare - Greater-than (ordered: non-signaling) case STARS_NN_vcmptrue_usps: // Packed Single-FP Compare - True (unordered: signaling) return false; break; case STARS_NN_vcmpeqsd: // Compare Scalar Double-Precision Floating-Point Values - Equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpltsd: // Compare Scalar Double-Precision Floating-Point Values - Less-than (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmplesd: // Compare Scalar Double-Precision Floating-Point Values - Less-than-or-equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpunordsd: // Compare Scalar Double-Precision Floating-Point Values - Unordered (non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpneqsd: // Compare Scalar Double-Precision Floating-Point Values - Not-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpnltsd: // Compare Scalar Double-Precision Floating-Point Values - Not-less-than (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpnlesd: // Compare Scalar Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpordsd: // Compare Scalar Double-Precision Floating-Point Values - Ordered (non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpeq_uqsd: // Compare Scalar Double-Precision Floating-Point Values - Equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpngesd: // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpngtsd: // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpfalsesd: // Compare Scalar Double-Precision Floating-Point Values - False (ordered: non-signaling) return false; break; case STARS_NN_vcmpneq_oqsd: // Compare Scalar Double-Precision Floating-Point Values - Not-equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpgesd: // Compare Scalar Double-Precision Floating-Point Values - Greater-than-or-equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_vcmpgtsd: // Compare Scalar Double-Precision Floating-Point Values - Greater-than (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_vcmptruesd: // Compare Scalar Double-Precision Floating-Point Values - True (unordered: non-signaling) return false; break; case STARS_NN_vcmpeq_ossd: // Compare Scalar Double-Precision Floating-Point Values - Equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmplt_oqsd: // Compare Scalar Double-Precision Floating-Point Values - Less-than (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmple_oqsd: // Compare Scalar Double-Precision Floating-Point Values - Less-than-or-equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpunord_ssd: // Compare Scalar Double-Precision Floating-Point Values - Unordered (signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpneq_ussd: // Compare Scalar Double-Precision Floating-Point Values - Not-equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpnlt_uqsd: // Compare Scalar Double-Precision Floating-Point Values - Not-less-than (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_vcmpnle_uqsd: // Compare Scalar Double-Precision Floating-Point Values - Not-less-than-or-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_vcmpord_ssd: // Compare Scalar Double-Precision Floating-Point Values - Ordered (signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpeq_ussd: // Compare Scalar Double-Precision Floating-Point Values - Equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpnge_uqsd: // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than-or-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpngt_uqsd: // Compare Scalar Double-Precision Floating-Point Values - Not-greater-than (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpfalse_ossd: // Compare Scalar Double-Precision Floating-Point Values - False (ordered: signaling) return false; break; case STARS_NN_vcmpneq_ossd: // Compare Scalar Double-Precision Floating-Point Values - Not-equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpge_oqsd: // Compare Scalar Double-Precision Floating-Point Values - Greater-than-or-equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_vcmpgt_oqsd: // Compare Scalar Double-Precision Floating-Point Values - Greater-than (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_vcmptrue_ussd: // Compare Scalar Double-Precision Floating-Point Values - True (unordered: signaling) return false; break; case STARS_NN_vcmpeqss: // Scalar Single-FP Compare - Equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpltss: // Scalar Single-FP Compare - Less-than (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpless: // Scalar Single-FP Compare - Less-than-or-equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpunordss: // Scalar Single-FP Compare - Unordered (non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpneqss: // Scalar Single-FP Compare - Not-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpnltss: // Scalar Single-FP Compare - Not-less-than (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpnless: // Scalar Single-FP Compare - Not-less-than-or-equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpordss: // Scalar Single-FP Compare - Ordered (non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpeq_uqss: // Scalar Single-FP Compare - Equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpngess: // Scalar Single-FP Compare - Not-greater-than-or-equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpngtss: // Scalar Single-FP Compare - Not-greater-than (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpfalsess: // Scalar Single-FP Compare - False (ordered: non-signaling) return false; break; case STARS_NN_vcmpneq_oqss: // Scalar Single-FP Compare - Not-equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpgess: // Scalar Single-FP Compare - Greater-than-or-equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_vcmpgtss: // Scalar Single-FP Compare - Greater-than (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_vcmptruess: // Scalar Single-FP Compare - True (unordered: non-signaling) return true; break; case STARS_NN_vcmpeq_osss: // Scalar Single-FP Compare - Equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmplt_oqss: // Scalar Single-FP Compare - Less-than (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmple_oqss: // Scalar Single-FP Compare - Less-than-or-equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpunord_sss: // Scalar Single-FP Compare - Unordered (signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpneq_usss: // Scalar Single-FP Compare - Not-equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpnlt_uqss: // Scalar Single-FP Compare - Not-less-than (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_vcmpnle_uqss: // Scalar Single-FP Compare - Not-less-than-or-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_vcmpord_sss: // Scalar Single-FP Compare - Ordered (signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpeq_usss: // Scalar Single-FP Compare - Equal (unordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_EQ_AND_SET); break; case STARS_NN_vcmpnge_uqss: // Scalar Single-FP Compare - Not-greater-than-or-equal (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LT_AND_SET); break; case STARS_NN_vcmpngt_uqss: // Scalar Single-FP Compare - Not-greater-than (unordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_LE_AND_SET); break; case STARS_NN_vcmpfalse_osss: // Scalar Single-FP Compare - False (ordered: signaling) return false; break; case STARS_NN_vcmpneq_osss: // Scalar Single-FP Compare - Not-equal (ordered: signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_NE_AND_SET); break; case STARS_NN_vcmpge_oqss: // Scalar Single-FP Compare - Greater-than-or-equal (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GE_AND_SET); break; case STARS_NN_vcmpgt_oqss: // Scalar Single-FP Compare - Greater-than (ordered: non-signaling) return this->BuildBinary3OpndRTL(SMP_COMPARE_GT_AND_SET); break; case STARS_NN_vcmptrue_usss: // Scalar Single-FP Compare - True (unordered: signaling) return false; break; // AVX-512 instructions case STARS_NN_valignd: // Align Doubleword Vectors case STARS_NN_valignq: // Align Quadword Vectors case STARS_NN_vblendmpd: // Blend Float64 Vectors Using an OpMask Control case STARS_NN_vblendmps: // Blend Float32 Vectors Using an OpMask Control case STARS_NN_vpblendmb: // Blend Byte Vectors Using an Opmask Control case STARS_NN_vpblendmw: // Blend Word Vectors Using an Opmask Control case STARS_NN_vpblendmd: // Blend Int32 Vectors Using an OpMask Control case STARS_NN_vpblendmq: // Blend Int64 Vectors Using an OpMask Control case STARS_NN_vbroadcastf32x2: // Load with Broadcast Floating-Point Data case STARS_NN_vbroadcastf32x4: // Load with Broadcast Floating-Point Data case STARS_NN_vbroadcastf64x2: // Load with Broadcast Floating-Point Data case STARS_NN_vbroadcastf32x8: // Load with Broadcast Floating-Point Data case STARS_NN_vbroadcastf64x4: // Load with Broadcast Floating-Point Data case STARS_NN_vbroadcasti32x2: // Load Integer and Broadcast case STARS_NN_vbroadcasti32x4: // Load Integer and Broadcast case STARS_NN_vbroadcasti64x2: // Load Integer and Broadcast case STARS_NN_vbroadcasti32x8: // Load Integer and Broadcast case STARS_NN_vbroadcasti64x4: // Load Integer and Broadcast case STARS_NN_vcompresspd: // Store Sparse Packed Double-Precision Floating-Point Values into Dense Memory case STARS_NN_vcompressps: // Store Sparse Packed Single-Precision Floating-Point Values into Dense Memory case STARS_NN_vcvtpd2qq: // Convert Packed Double-Precision Floating-Point Values to Packed Quadword Integers case STARS_NN_vcvtpd2udq: // Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers case STARS_NN_vcvtpd2uqq: // Convert Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers case STARS_NN_vcvtps2udq: // Convert Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values case STARS_NN_vcvtps2qq: // Convert Packed Single Precision Floating-Point Values to Packed Singed Quadword Integer Values case STARS_NN_vcvtps2uqq: // Convert Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values case STARS_NN_vcvtqq2pd: // Convert Packed Quadword Integers to Packed Double-Precision Floating-Point Values case STARS_NN_vcvtqq2ps: // Convert Packed Quadword Integers to Packed Single-Precision Floating-Point Values case STARS_NN_vcvtsd2usi: // Convert Scalar Double-Precision Floating-Point Value to Unsigned Doubleword Integer case STARS_NN_vcvtss2usi: // Convert Scalar Single-Precision Floating-Point Value to Unsigned Doubleword Integer case STARS_NN_vcvttpd2qq: // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Quadword Integers case STARS_NN_vcvttpd2udq: // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Doubleword Integers case STARS_NN_vcvttpd2uqq: // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Unsigned Quadword Integers case STARS_NN_vcvttps2udq: // Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Unsigned Doubleword Integer Values case STARS_NN_vcvttps2qq: // Convert with Truncation Packed Single Precision Floating-Point Values to Packed Singed Quadword Integer Values case STARS_NN_vcvttps2uqq: // Convert with Truncation Packed Single Precision Floating-Point Values to Packed Unsigned Quadword Integer Values case STARS_NN_vcvttsd2usi: // Convert with Truncation Scalar Double-Precision Floating-Point Value to Unsigned Integer case STARS_NN_vcvttss2usi: // Convert with Truncation Scalar Single-Precision Floating-Point Value to Unsigned Integer case STARS_NN_vcvtudq2pd: // Convert Packed Unsigned Doubleword Integers to Packed Double-Precision Floating-Point Values case STARS_NN_vcvtudq2ps: // Convert Packed Unsigned Doubleword Integers to Packed Single-Precision Floating-Point Values case STARS_NN_vcvtuqq2pd: // Convert Packed Unsigned Quadword Integers to Packed Double-Precision Floating-Point Values case STARS_NN_vcvtuqq2ps: // Convert Packed Unsigned Quadword Integers to Packed Single-Precision Floating-Point Values case STARS_NN_vcvtusi2sd: // Convert Unsigned Integer to Scalar Double-Precision Floating-Point Value case STARS_NN_vcvtusi2ss: // Convert Unsigned Integer to Scalar Single-Precision Floating-Point Value case STARS_NN_vdbpsadbw: // Double Block Packed Sum-Absolute-Differences (SAD) on Unsigned Bytes case STARS_NN_vexpandpd: // Load Sparse Packed Double-Precision Floating-Point Values from Dense Memory case STARS_NN_vexpandps: // Load Sparse Packed Single-Precision Floating-Point Values from Dense Memory case STARS_NN_vextractf32x4: // Extract Packed Floating-Point Values case STARS_NN_vextractf64x2: // Extract Packed Floating-Point Values case STARS_NN_vextractf32x8: // Extract Packed Floating-Point Values case STARS_NN_vextractf64x4: // Extract Packed Floating-Point Values case STARS_NN_vextracti32x4: // Extract packed Integer Values case STARS_NN_vextracti64x2: // Extract packed Integer Values case STARS_NN_vextracti32x8: // Extract packed Integer Values case STARS_NN_vextracti64x4: // Extract packed Integer Values case STARS_NN_vfixupimmpd: // Fix Up Special Packed Float64 Values case STARS_NN_vfixupimmps: // Fix Up Special Packed Float32 Values case STARS_NN_vfixupimmsd: // Fix Up Special Scalar Float64 Value case STARS_NN_vfixupimmss: // Fix Up Special Scalar Float32 Value case STARS_NN_vfpclasspd: // Tests Types Of a Packed Float64 Values case STARS_NN_vfpclassps: // Tests Types Of a Packed Float32 Values case STARS_NN_vfpclasssd: // Tests Types Of a Scalar Float64 Values case STARS_NN_vfpclassss: // Tests Types Of a Scalar Float32 Values case STARS_NN_vgetexppd: // Convert Exponents of Packed DP FP Values to DP FP Values case STARS_NN_vgetexpps: // Convert Exponents of Packed SP FP Values to SP FP Values case STARS_NN_vgetexpsd: // Convert Exponents of Scalar DP FP Values to DP FP Value case STARS_NN_vgetexpss: // Convert Exponents of Scalar SP FP Values to SP FP Value case STARS_NN_vgetmantpd: // Extract Float64 Vector of Normalized Mantissas from Float64 Vector case STARS_NN_vgetmantps: // Extract Float32 Vector of Normalized Mantissas from Float32 Vector case STARS_NN_vgetmantsd: // Extract Float64 of Normalized Mantissas from Float64 Scalar case STARS_NN_vgetmantss: // Extract Float32 Vector of Normalized Mantissa from Float32 Vector case STARS_NN_vinsertf32x4: // Insert Packed Floating-Point Values case STARS_NN_vinsertf64x2: // Insert Packed Floating-Point Values case STARS_NN_vinsertf32x8: // Insert Packed Floating-Point Values case STARS_NN_vinsertf64x4: // Insert Packed Floating-Point Values case STARS_NN_vinserti32x4: // Insert Packed Integer Values case STARS_NN_vinserti64x2: // Insert Packed Integer Values case STARS_NN_vinserti32x8: // Insert Packed Integer Values case STARS_NN_vinserti64x4: // Insert Packed Integer Values case STARS_NN_vmovdqa32: // Move Aligned Packed Integer Values case STARS_NN_vmovdqa64: // Move Aligned Packed Integer Values case STARS_NN_vmovdqu8: // Move Unaligned Packed Integer Values case STARS_NN_vmovdqu16: // Move Unaligned Packed Integer Values case STARS_NN_vmovdqu32: // Move Unaligned Packed Integer Values case STARS_NN_vmovdqu64: // Move Unaligned Packed Integer Values case STARS_NN_vpabsq: // Packed Absolute Value case STARS_NN_vpandd: // Logical AND case STARS_NN_vpandq: // Logical AND case STARS_NN_vpandnd: // Logical AND NOT case STARS_NN_vpandnq: // Logical AND NOT case STARS_NN_vpbroadcastmb2q: // Broadcast Mask to Vector Register case STARS_NN_vpbroadcastmw2d: // Broadcast Mask to Vector Register case STARS_NN_vpcmpb: // Compare Packed Byte Values Into Mask case STARS_NN_vpcmpub: // Compare Packed Byte Values Into Mask case STARS_NN_vpcmpd: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpud: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpuq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpw: // Compare Packed Word Values Into Mask case STARS_NN_vpcmpuw: // Compare Packed Word Values Into Mask case STARS_NN_vpcompressd: // Store Sparse Packed Doubleword Integer Values into Dense Memory/Register case STARS_NN_vpcompressq: // Store Sparse Packed Quadword Integer Values into Dense Memory/Register case STARS_NN_vpconflictd: // Detect Conflicts Within a Vector of Packed Dword Values into Dense Memory/Register case STARS_NN_vpconflictq: // Detect Conflicts Within a Vector of Packed Qword Values into Dense Memory/Register case STARS_NN_vpermb: // Permute Packed Bytes Elements case STARS_NN_vpermw: // Permute Packed Words Elements case STARS_NN_vpermi2b: // Full Permute of Bytes From Two Tables Overwriting the Index case STARS_NN_vpermi2w: // Full Permute From Two Tables Overwriting the Index case STARS_NN_vpermi2d: // Full Permute From Two Tables Overwriting the Index case STARS_NN_vpermi2q: // Full Permute From Two Tables Overwriting the Index case STARS_NN_vpermi2ps: // Full Permute From Two Tables Overwriting the Index case STARS_NN_vpermi2pd: // Full Permute From Two Tables Overwriting the Index case STARS_NN_vpermt2b: // Full Permute of Bytes From Two Tables Overwriting a Table case STARS_NN_vpermt2w: // Full Permute from Two Tables Overwriting one Table case STARS_NN_vpermt2d: // Full Permute from Two Tables Overwriting one Table case STARS_NN_vpermt2q: // Full Permute from Two Tables Overwriting one Table case STARS_NN_vpermt2ps: // Full Permute from Two Tables Overwriting one Table case STARS_NN_vpermt2pd: // Full Permute from Two Tables Overwriting one Table case STARS_NN_vpexpandd: // Load Sparse Packed Doubleword Integer Values from Dense Memory/Register case STARS_NN_vpexpandq: // Load Sparse Packed Quadword Integer Values from Dense Memory/Register case STARS_NN_vplzcntd: // Count the Number of Leading Zero Bits for Packed Dword Values case STARS_NN_vplzcntq: // Count the Number of Leading Zero Bits for Packed Qword Values case STARS_NN_vpmadd52luq: // Packed Multiply of Unsigned 52-bit Integers and Add the Low 52-bit Products to Qword Accumulators case STARS_NN_vpmadd52huq: // Packed Multiply of Unsigned 52-bit Unsigned Integers and Add High 52-bit Products to 64-bit Accumulators case STARS_NN_vpmaxsq: // Maximum of Packed Signed Integers case STARS_NN_vpmaxuq: // Maximum of Packed Unsigned Integers case STARS_NN_vpminsq: // Minimum of Packed Signed Integers case STARS_NN_vpminuq: // Minimum of Packed Unsigned Integers case STARS_NN_vpmovm2b: // Convert a Mask Register to a Vector Register case STARS_NN_vpmovm2w: // Convert a Mask Register to a Vector Register case STARS_NN_vpmovm2d: // Convert a Mask Register to a Vector Register case STARS_NN_vpmovm2q: // Convert a Mask Register to a Vector Register case STARS_NN_vpmovb2m: // Convert a Vector Register to a Mask case STARS_NN_vpmovw2m: // Convert a Vector Register to a Mask case STARS_NN_vpmovd2m: // Convert a Vector Register to a Mask case STARS_NN_vpmovq2m: // Convert a Vector Register to a Mask case STARS_NN_vpmovqb: // Down Convert QWord to Byte case STARS_NN_vpmovsqb: // Down Convert QWord to Byte case STARS_NN_vpmovusqb: // Down Convert QWord to Byte case STARS_NN_vpmovqw: // Down Convert QWord to Word case STARS_NN_vpmovsqw: // Down Convert QWord to Word case STARS_NN_vpmovusqw: // Down Convert QWord to Word case STARS_NN_vpmovqd: // Down Convert QWord to DWord case STARS_NN_vpmovsqd: // Down Convert QWord to DWord case STARS_NN_vpmovusqd: // Down Convert QWord to DWord case STARS_NN_vpmovdb: // Down Convert DWord to Byte case STARS_NN_vpmovsdb: // Down Convert DWord to Byte case STARS_NN_vpmovusdb: // Down Convert DWord to Byte case STARS_NN_vpmovdw: // Down Convert DWord to Word case STARS_NN_vpmovsdw: // Down Convert DWord to Word case STARS_NN_vpmovusdw: // Down Convert DWord to Word case STARS_NN_vpmovwb: // Down Convert Word to Byte case STARS_NN_vpmovswb: // Down Convert Word to Byte case STARS_NN_vpmovuswb: // Down Convert Word to Byte case STARS_NN_vpmullq: // Multiply Packed Integers and Store Low Result case STARS_NN_vpmultishiftqb: // Select Packed Unaligned Bytes from Quadword Sources case STARS_NN_vpord: // Bitwise Logical Or case STARS_NN_vporq: // Bitwise Logical Or case STARS_NN_vprold: // Bit Rotate Left case STARS_NN_vprolvd: // Bit Rotate Left case STARS_NN_vprolq: // Bit Rotate Left case STARS_NN_vprolvq: // Bit Rotate Left case STARS_NN_vprord: // Bit Rotate Right case STARS_NN_vprorvd: // Bit Rotate Right case STARS_NN_vprorq: // Bit Rotate Right case STARS_NN_vprorvq: // Bit Rotate Right case STARS_NN_vpscatterdd: // Scatter Packed Dword with Signed Dword case STARS_NN_vpscatterdq: // Scatter Packed Qword with Signed Qword Indices case STARS_NN_vpscatterqd: // Scatter Packed Dword with Signed Dword case STARS_NN_vpscatterqq: // Scatter Packed Qword with Signed Qword Indices case STARS_NN_vpsraq: // Bit Shift Arithmetic Right case STARS_NN_vpsllvw: // Variable Bit Shift Left Logical case STARS_NN_vpsrlvw: // Variable Bit Shift Right Logical case STARS_NN_vptestnmb: // Logical NAND and Set case STARS_NN_vptestnmw: // Logical NAND and Set case STARS_NN_vptestnmd: // Logical NAND and Set case STARS_NN_vptestnmq: // Logical NAND and Set case STARS_NN_vshuff32x4: // Shuffle Packed Values at 128-bit Granularity case STARS_NN_vshuff64x2: // Shuffle Packed Values at 128-bit Granularity case STARS_NN_vshufi32x4: // Shuffle Packed Values at 128-bit Granularity case STARS_NN_vshufi64x2: // Shuffle Packed Values at 128-bit Granularity case STARS_NN_vpternlogd: // Bitwise Ternary Logic case STARS_NN_vpternlogq: // Bitwise Ternary Logic case STARS_NN_vptestmb: // Logical AND and Set Mask case STARS_NN_vptestmw: // Logical AND and Set Mask case STARS_NN_vptestmd: // Logical AND and Set Mask case STARS_NN_vptestmq: // Logical AND and Set Mask case STARS_NN_vpsravw: // Variable Bit Shift Right Arithmetic case STARS_NN_vpsravq: // Variable Bit Shift Right Arithmetic case STARS_NN_vpxord: // Exclusive Or case STARS_NN_vpxorq: // Exclusive Or case STARS_NN_vrangepd: // Range Restriction Calculation For Packed Pairs of Float64 Values case STARS_NN_vrangeps: // Range Restriction Calculation For Packed Pairs of Float32 Values case STARS_NN_vrangesd: // Range Restriction Calculation From a pair of Scalar Float64 Values case STARS_NN_vrangess: // Range Restriction Calculation From a Pair of Scalar Float32 Values case STARS_NN_vrcp14pd: // Compute Approximate Reciprocals of Packed Float64 Values case STARS_NN_vrcp14sd: // Compute Approximate Reciprocal of Scalar Float64 Value case STARS_NN_vrcp14ps: // Compute Approximate Reciprocals of Packed Float32 Values case STARS_NN_vrcp14ss: // Compute Approximate Reciprocal of Scalar Float32 Value case STARS_NN_vreducepd: // Perform Reduction Transformation on Packed Float64 Values case STARS_NN_vreducesd: // Perform a Reduction Transformation on a Scalar Float64 Value case STARS_NN_vreduceps: // Perform Reduction Transformation on Packed Float32 Values case STARS_NN_vreducess: // Perform a Reduction Transformation on a Scalar Float32 Value case STARS_NN_vrndscalepd: // Round Packed Float64 Values To Include A Given Number Of Fraction Bits case STARS_NN_vrndscalesd: // Round Scalar Float64 Value To Include A Given Number Of Fraction Bits case STARS_NN_vrndscaleps: // Round Packed Float32 Values To Include A Given Number Of Fraction Bits case STARS_NN_vrndscaless: // Round Scalar Float32 Value To Include A Given Number Of Fraction Bits case STARS_NN_vrsqrt14pd: // Compute Approximate Reciprocals of Square Roots of Packed Float64 Values case STARS_NN_vrsqrt14sd: // Compute Approximate Reciprocal of Square Root of Scalar Float64 Value case STARS_NN_vrsqrt14ps: // Compute Approximate Reciprocals of Square Roots of Packed Float32 Values case STARS_NN_vrsqrt14ss: // Compute Approximate Reciprocal of Square Root of Scalar Float32 Value case STARS_NN_vscalefpd: // Scale Packed Float64 Values With Float64 Values case STARS_NN_vscalefsd: // Scale Scalar Float64 Values With Float64 Values case STARS_NN_vscalefps: // Scale Packed Float32 Values With Float32 Values case STARS_NN_vscalefss: // Scale Scalar Float32 Value With Float32 Value case STARS_NN_vscatterdps: // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices case STARS_NN_vscatterdpd: // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices case STARS_NN_vscatterqps: // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices case STARS_NN_vscatterqpd: // Scatter Packed Single: Packed Double with Signed Dword and Qword Indices case STARS_NN_vexp2pd: // Approximation to the Exponential 2^x of Packed Double-Precision Floating-Point Values with Less Than 2^-23 Relative Error case STARS_NN_vexp2ps: // Approximation to the Exponential 2^x of Packed Single-Precision Floating-Point Values with Less Than 2^-23 Relative Error case STARS_NN_vrcp28pd: // Approximation to the Reciprocal of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error case STARS_NN_vrcp28sd: // Approximation to the Reciprocal of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error case STARS_NN_vrcp28ps: // Approximation to the Reciprocal of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error case STARS_NN_vrcp28ss: // Approximation to the Reciprocal of Scalar Single-Precision Floating-Point Value with Less Than 2^-28 Relative Error case STARS_NN_vrsqrt28pd: // Approximation to the Reciprocal Square Root of Packed Double-Precision Floating-Point Values with Less Than 2^-28 Relative Error case STARS_NN_vrsqrt28sd: // Approximation to the Reciprocal Square Root of Scalar Double-Precision Floating-Point Value with Less Than 2^-28 Relative Error case STARS_NN_vrsqrt28ps: // Approximation to the Reciprocal Square Root of Packed Single-Precision Floating-Point Values with Less Than 2^-28 Relative Error case STARS_NN_vrsqrt28ss: // Approximation to the Reciprocal Square Root of Scalar Single-Precision Floating-Point Value with Less Than 2^-28 Relative Error case STARS_NN_vgatherpf0dps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint case STARS_NN_vgatherpf0qps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint case STARS_NN_vgatherpf0dpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint case STARS_NN_vgatherpf0qpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint case STARS_NN_vgatherpf1dps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint case STARS_NN_vgatherpf1qps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint case STARS_NN_vgatherpf1dpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint case STARS_NN_vgatherpf1qpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint case STARS_NN_vscatterpf0dps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write case STARS_NN_vscatterpf0qps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write case STARS_NN_vscatterpf0dpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write case STARS_NN_vscatterpf0qpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T0 Hint with Intent to Write case STARS_NN_vscatterpf1dps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write case STARS_NN_vscatterpf1qps: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write case STARS_NN_vscatterpf1dpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write case STARS_NN_vscatterpf1qpd: // Sparse Prefetch Packed SP/DP Data Values with Signed Dword: Signed Qword Indices Using T1 Hint with Intent to Write return false; break; // AVX-512 comparison pseudo-ops case STARS_NN_vpcmpltd: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpled: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpneqd: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnltd: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnled: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpequd: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpltud: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpleud: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnequd: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnltud: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnleud: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpltq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpleq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpneqq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnltq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnleq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpequq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpltuq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpleuq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnequq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnltuq: // Compare Packed Integer Values into Mask case STARS_NN_vpcmpnleuq: // Compare Packed Integer Values into Mask return false; break; // Opmask instructions case STARS_NN_kaddw: // ADD Two Masks case STARS_NN_kaddb: // ADD Two Masks case STARS_NN_kaddq: // ADD Two Masks case STARS_NN_kaddd: // ADD Two Masks case STARS_NN_kandw: // Bitwise Logical AND Masks case STARS_NN_kandb: // Bitwise Logical AND Masks case STARS_NN_kandq: // Bitwise Logical AND Masks case STARS_NN_kandd: // Bitwise Logical AND Masks case STARS_NN_kandnw: // Bitwise Logical AND NOT Masks case STARS_NN_kandnb: // Bitwise Logical AND NOT Masks case STARS_NN_kandnq: // Bitwise Logical AND NOT Masks case STARS_NN_kandnd: // Bitwise Logical AND NOT Masks case STARS_NN_kmovw: // Move from and to Mask Registers case STARS_NN_kmovb: // Move from and to Mask Registers case STARS_NN_kmovq: // Move from and to Mask Registers case STARS_NN_kmovd: // Move from and to Mask Registers case STARS_NN_kunpckbw: // Unpack for Mask Registers case STARS_NN_kunpckwd: // Unpack for Mask Registers case STARS_NN_kunpckdq: // Unpack for Mask Registers case STARS_NN_knotw: // NOT Mask Register case STARS_NN_knotb: // NOT Mask Register case STARS_NN_knotq: // NOT Mask Register case STARS_NN_knotd: // NOT Mask Register case STARS_NN_korw: // Bitwise Logical OR Masks case STARS_NN_korb: // Bitwise Logical OR Masks case STARS_NN_korq: // Bitwise Logical OR Masks case STARS_NN_kord: // Bitwise Logical OR Masks case STARS_NN_kortestw: // OR Masks And Set Flags case STARS_NN_kortestb: // OR Masks And Set Flags case STARS_NN_kortestq: // OR Masks And Set Flags case STARS_NN_kortestd: // OR Masks And Set Flags case STARS_NN_kshiftlw: // Shift Left Mask Registers case STARS_NN_kshiftlb: // Shift Left Mask Registers case STARS_NN_kshiftlq: // Shift Left Mask Registers case STARS_NN_kshiftld: // Shift Left Mask Registers case STARS_NN_kshiftrw: // Shift Right Mask Registers case STARS_NN_kshiftrb: // Shift Right Mask Registers case STARS_NN_kshiftrq: // Shift Right Mask Registers case STARS_NN_kshiftrd: // Shift Right Mask Registers case STARS_NN_kxnorw: // Bitwise Logical XNOR Masks case STARS_NN_kxnorb: // Bitwise Logical XNOR Masks case STARS_NN_kxnorq: // Bitwise Logical XNOR Masks case STARS_NN_kxnord: // Bitwise Logical XNOR Masks case STARS_NN_ktestw: // Packed Bit Test Masks and Set Flags case STARS_NN_ktestb: // Packed Bit Test Masks and Set Flags case STARS_NN_ktestq: // Packed Bit Test Masks and Set Flags case STARS_NN_ktestd: // Packed Bit Test Masks and Set Flags case STARS_NN_kxorw: // Bitwise Logical XOR Masks case STARS_NN_kxorb: // Bitwise Logical XOR Masks case STARS_NN_kxorq: // Bitwise Logical XOR Masks case STARS_NN_kxord: // Bitwise Logical XOR Masks return false; break; // SHA Extensions case STARS_NN_sha1rnds4: // Perform Four Rounds of SHA1 Operation case STARS_NN_sha1nexte: // Calculate SHA1 State Variable E after Four Rounds case STARS_NN_sha1msg1: // Perform an Intermediate Calculation for the Next Four SHA1 Message Dwords case STARS_NN_sha1msg2: // Perform a Final Calculation for the Next Four SHA1 Message Dwords case STARS_NN_sha256rnds2: // Perform Two Rounds of SHA256 Operation case STARS_NN_sha256msg1: // Perform an Intermediate Calculation for the Next Four SHA256 Message Dwords case STARS_NN_sha256msg2: // Perform a Final Calculation for the Next Four SHA256 Message Dwords return false; break; // Intel Software Guard Extensions case STARS_NN_encls: // Execute an Enclave System Function of Specified Leaf Number case STARS_NN_enclu: // Execute an Enclave User Function of Specified Leaf Number return false; break; // AMD XOP case STARS_NN_vfrczpd: // Extract Fraction Packed Double-Precision Floating-Point case STARS_NN_vfrczps: // Extract Fraction Packed Single-Precision Floating-Point case STARS_NN_vfrczsd: // Extract Fraction Scalar Double-Precision Floating-Point case STARS_NN_vfrczss: // Extract Fraction Scalar Single-Precision Floating Point case STARS_NN_vpcmov: // Vector Conditional Moves case STARS_NN_vpcomb: // Compare Vector Signed Bytes case STARS_NN_vpcomd: // Compare Vector Signed Doublewords case STARS_NN_vpcomq: // Compare Vector Signed Quadwords case STARS_NN_vpcomub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomuq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomuw: // Compare Vector Unsigned Words case STARS_NN_vpcomw: // Compare Vector Signed Words case STARS_NN_vpermil2pd: // Permute Two-Source Double-Precision Floating-Point Values case STARS_NN_vpermil2ps: // Permute Two-Source Single-Precision Floating-Point Values case STARS_NN_vphaddbd: // Packed Horizontal Add Signed Byte to Signed Doubleword case STARS_NN_vphaddbq: // Packed Horizontal Add Signed Byte to Signed Quadword case STARS_NN_vphaddbw: // Packed Horizontal Add Signed Byte to Signed Word case STARS_NN_vphadddq: // Packed Horizontal Add Signed Doubleword to Signed Quadword case STARS_NN_vphaddubd: // Packed Horizontal Add Unsigned Byte to Doubleword case STARS_NN_vphaddubq: // Packed Horizontal Add Unsigned Byte to Quadword case STARS_NN_vphaddubw: // Packed Horizontal Add Unsigned Byte to Word case STARS_NN_vphaddudq: // Packed Horizontal Add Unsigned Doubleword to Quadword case STARS_NN_vphadduwd: // Packed Horizontal Add Unsigned Word to Doubleword case STARS_NN_vphadduwq: // Packed Horizontal Add Unsigned Word to Quadword case STARS_NN_vphaddwd: // Packed Horizontal Add Signed Word to Signed Doubleword case STARS_NN_vphaddwq: // Packed Horizontal Add Signed Word to Signed Quadword case STARS_NN_vphsubbw: // Packed Horizontal Subtract Signed Byte to Signed Word case STARS_NN_vphsubdq: // Packed Horizontal Subtract Signed Doubleword to Signed Quadword case STARS_NN_vphsubwd: // Packed Horizontal Subtract Signed Word to Signed Doubleword case STARS_NN_vpmacsdd: // Packed Multiply Accumulate Signed Doubleword to Signed Doubleword case STARS_NN_vpmacsdqh: // Packed Multiply Accumulate Signed High Doubleword to Signed Quadword case STARS_NN_vpmacsdql: // Packed Multiply Accumulate Signed Low Doubleword to Signed Quadword case STARS_NN_vpmacssdd: // Packed Multiply Accumulate Signed Doubleword to Signed Doubleword with Saturation case STARS_NN_vpmacssdqh: // Packed Multiply Accumulate Signed High Doubleword to Signed Quadword with Saturation case STARS_NN_vpmacssdql: // Packed Multiply Accumulate Signed Low Doubleword to Signed Quadword with Saturation case STARS_NN_vpmacsswd: // Packed Multiply Accumulate Signed Word to Signed Doubleword with Saturation case STARS_NN_vpmacssww: // Packed Multiply Accumulate Signed Word to Signed Word with Saturation case STARS_NN_vpmacswd: // Packed Multiply Accumulate Signed Word to Signed Doubleword case STARS_NN_vpmacsww: // Packed Multiply Accumulate Signed Word to Signed Word case STARS_NN_vpmadcsswd: // Packed Multiply: Add and Accumulate Signed Word to Signed Doubleword with Saturation case STARS_NN_vpmadcswd: // Packed Multiply Add and Accumulate Signed Word to Signed Doubleword case STARS_NN_vpperm: // Packed Permute Bytes case STARS_NN_vprotb: // Packed Rotate Bytes case STARS_NN_vprotd: // Packed Rotate Doublewords case STARS_NN_vprotq: // Packed Rotate Quadwords case STARS_NN_vprotw: // Packed Rotate Words case STARS_NN_vpshab: // Packed Shift Arithmetic Bytes case STARS_NN_vpshad: // Packed Shift Arithmetic Doublewords case STARS_NN_vpshaq: // Packed Shift Arithmetic Quadwords case STARS_NN_vpshaw: // Packed Shift Arithmetic Words case STARS_NN_vpshlb: // Packed Shift Logical Bytes case STARS_NN_vpshld: // Packed Shift Logical Doublewords case STARS_NN_vpshlq: // Packed Shift Logical Quadwords case STARS_NN_vpshlw: // Packed Shift Logical Words return false; break; // AMP XOP comparison pseudo-ops case STARS_NN_vpcomltb: // Compare Vector Signed Bytes case STARS_NN_vpcomleb: // Compare Vector Signed Bytes case STARS_NN_vpcomgtb: // Compare Vector Signed Bytes case STARS_NN_vpcomgeb: // Compare Vector Signed Bytes case STARS_NN_vpcomeqb: // Compare Vector Signed Bytes case STARS_NN_vpcomneqb: // Compare Vector Signed Bytes case STARS_NN_vpcomfalseb: // Compare Vector Signed Bytes case STARS_NN_vpcomtrueb: // Compare Vector Signed Bytes case STARS_NN_vpcomltw: // Compare Vector Signed Words case STARS_NN_vpcomlew: // Compare Vector Signed Words case STARS_NN_vpcomgtw: // Compare Vector Signed Words case STARS_NN_vpcomgew: // Compare Vector Signed Words case STARS_NN_vpcomeqw: // Compare Vector Signed Words case STARS_NN_vpcomneqw: // Compare Vector Signed Words case STARS_NN_vpcomfalsew: // Compare Vector Signed Words case STARS_NN_vpcomtruew: // Compare Vector Signed Words case STARS_NN_vpcomltd: // Compare Vector Signed Doublewords case STARS_NN_vpcomled: // Compare Vector Signed Doublewords case STARS_NN_vpcomgtd: // Compare Vector Signed Doublewords case STARS_NN_vpcomged: // Compare Vector Signed Doublewords case STARS_NN_vpcomeqd: // Compare Vector Signed Doublewords case STARS_NN_vpcomneqd: // Compare Vector Signed Doublewords case STARS_NN_vpcomfalsed: // Compare Vector Signed Doublewords case STARS_NN_vpcomtrued: // Compare Vector Signed Doublewords case STARS_NN_vpcomltq: // Compare Vector Signed Quadwords case STARS_NN_vpcomleq: // Compare Vector Signed Quadwords case STARS_NN_vpcomgtq: // Compare Vector Signed Quadwords case STARS_NN_vpcomgeq: // Compare Vector Signed Quadwords case STARS_NN_vpcomeqq: // Compare Vector Signed Quadwords case STARS_NN_vpcomneqq: // Compare Vector Signed Quadwords case STARS_NN_vpcomfalseq: // Compare Vector Signed Quadwords case STARS_NN_vpcomtrueq: // Compare Vector Signed Quadwords case STARS_NN_vpcomltub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomleub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomgtub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomgeub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomequb: // Compare Vector Unsigned Bytes case STARS_NN_vpcomnequb: // Compare Vector Unsigned Bytes case STARS_NN_vpcomfalseub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomtrueub: // Compare Vector Unsigned Bytes case STARS_NN_vpcomltuw: // Compare Vector Unsigned Words case STARS_NN_vpcomleuw: // Compare Vector Unsigned Words case STARS_NN_vpcomgtuw: // Compare Vector Unsigned Words case STARS_NN_vpcomgeuw: // Compare Vector Unsigned Words case STARS_NN_vpcomequw: // Compare Vector Unsigned Words case STARS_NN_vpcomnequw: // Compare Vector Unsigned Words case STARS_NN_vpcomfalseuw: // Compare Vector Unsigned Words case STARS_NN_vpcomtrueuw: // Compare Vector Unsigned Words case STARS_NN_vpcomltud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomleud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomgtud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomgeud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomequd: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomnequd: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomfalseud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomtrueud: // Compare Vector Unsigned Doublewords case STARS_NN_vpcomltuq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomleuq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomgtuq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomgeuq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomequq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomnequq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomfalseuq: // Compare Vector Unsigned Quadwords case STARS_NN_vpcomtrueuq: // Compare Vector Unsigned Quadwords return false; break; // AMD Excavator case STARS_NN_monitorx: // Setup Monitor Address case STARS_NN_mwaitx: // Monitor Wait with Timeout return false; break; // AMD Zen case STARS_NN_clzero: // Zero out 64 byte cache return false; break; // Intel Processor Trace case STARS_NN_ptwrite: // Write Data to a Processor Trace Packet return false; break; // new Intel AVX-512 instructions (December 2016) case STARS_NN_v4fmaddps: // Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations) case STARS_NN_v4fnmaddps: // Packed Single-Precision Floating-Point Fused Multiply-Add (4-iterations) case STARS_NN_v4fmaddss: // Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations) case STARS_NN_v4fnmaddss: // Scalar Single-Precision Floating-Point Fused Multiply-Add (4-iterations) case STARS_NN_vp4dpwssd: // Dot Product of Signed Words with Dword Accumulation (4-iterations) case STARS_NN_vp4dpwssds: // Dot Product of Signed Words with Dword Accumulation and Saturation (4-iterations) case STARS_NN_vpopcntd: // Return the Count of Number of Bits Set to 1 in DWORD case STARS_NN_vpopcntq: // Return the Count of Number of Bits Set to 1 in QWORD return false; break; // Read Processor ID case STARS_NN_rdpid: // Read Processor ID return false; break; // Invoke VM function case STARS_NN_vmfunc: // Invoke VM function return false; break; // Control-flow Enforcement case STARS_NN_incsspd: // Increment Shadow Stack Pointer (by 4) case STARS_NN_incsspq: // Increment Shadow Stack Pointer (by 8) case STARS_NN_rdsspd: // Read (low 32 bits of) Shadow Stack Pointer case STARS_NN_rdsspq: // Read Shadow Stack Pointer case STARS_NN_saveprevssp: // Save Previous Shadow Stack Pointer case STARS_NN_rstorssp: // Restore saved Shadow Stack Pointer case STARS_NN_wrssd: // Write (4 bytes) to shadow stack case STARS_NN_wrssq: // Write (8 bytes) to shadow stack case STARS_NN_wrussd: // Write (4 bytes) to User Shadow Stack case STARS_NN_wrussq: // Write (8 bytes) to User Shadow Stack case STARS_NN_setssbsy: // Mark Shadow Stack Busy case STARS_NN_clrssbsy: // Clear Shadow Stack Busy Flag case STARS_NN_endbr64: // Terminate an Indirect Branch in 64-bit Mode case STARS_NN_endbr32: // Terminate an Indirect Branch in 32-bit and Compatibility Mode return false; break; default: SMP_msg("ERROR: Unknown instruction opcode at %llx : %s\n", (unsigned long long) this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr())); return false; break; } // end switch on opcode return true; } // end SMPInstr::BuildRTL() // Iterate through all reg transfers and call SyncRTLDefUse for each. void SMPInstr::SyncAllRTs(bool UseFP, STARS_sval_t FPDelta) { for (std::size_t index = 0; index < this->RTL.GetCount(); ++index) { this->SyncRTLDefUse(this->RTL.GetRT(index), UseFP, FPDelta); } return; } // end of SMPInstr:SyncAllRTs() // Ensure that each operand of the RTL is found in the appropriate DEF or USE list. void SMPInstr::SyncRTLDefUse(SMPRegTransfer *CurrRT, bool UseFP, STARS_sval_t FPDelta) { // The ExtraKills are almost never represented in the DEF // lists. When they are, they are added in MDFixupDefUseLists(), so we ignore them here. // The only DEFs should come from left operands of SMP_ASSIGN operators, i.e. the effects // of register transfers. STARSOpndTypePtr LeftOp, RightOp; set<DefOrUse, LessDefUse>::iterator CurrDef, CurrUse; bool DebugFlag = false; #if SMP_VERBOSE_DEBUG_BUILD_RTL DebugFlag |= (0 == strcmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName())); #endif #if SMP_VERBOSE_DEBUG_BUILD_RTL if (DebugFlag) { SMP_msg("SyncRTLDefUse entered. Dump of USE list:\n"); this->Uses.Dump(); } #endif LeftOp = CurrRT->GetLeftOperand(); if (SMP_ASSIGN == CurrRT->GetOperator()) { assert(! LeftOp->IsVoidOp()); assert(! LeftOp->IsImmedOp()); LeftOp->CleanOpndEncoding(); CurrDef = this->Defs.FindRef(LeftOp); if (CurrDef == this->GetLastDef() && !LeftOp->MatchesReg(MD_INSTRUCTION_POINTER_REG)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL SMP_msg("WARNING: DEF not found for SMP_ASSIGN in %s ; added op:", DisAsmText.GetDisAsm(this->GetAddr())); PrintOperand(LeftOp); SMP_msg("\n"); #endif this->Defs.SetRef(LeftOp, CurrRT->GetOperatorType()); } } else { // not SMP_ASSIGN; left operand should be a USE if (! ((nullptr == LeftOp) || LeftOp->IsVoidOp())) { CurrUse = this->Uses.FindRef(LeftOp); if (CurrUse == this->GetLastUse()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: USE not found for "); PrintOperand(LeftOp); SMP_msg(" in %s ; added\n", DisAsmText.GetDisAsm(this->GetAddr())); #endif this->Uses.SetRef(LeftOp); } } } if (!CurrRT->HasRightSubTree()) { RightOp = CurrRT->GetRightOperand(); // right operand should be a USE if (!((nullptr == RightOp) || RightOp->IsVoidOp())) { RightOp->CleanOpndEncoding(); CurrUse = this->Uses.FindRef(RightOp); if (CurrUse == this->GetLastUse()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE SMP_msg("WARNING: USE not found for "); PrintOperand(RightOp); SMP_msg(" in %s ; added\n", DisAsmText.GetDisAsm(this->GetAddr())); #endif this->Uses.SetRef(RightOp); } } } else { // recurse into right subtree this->SyncRTLDefUse(CurrRT->GetRightTree(), UseFP, FPDelta); } // Guard operands can only be USEs. SMPGuard *GuardExpr = CurrRT->GetGuard(); if (NULL != GuardExpr) { LeftOp = GuardExpr->GetLeftOperand(); if ((!((nullptr == LeftOp) || LeftOp->IsVoidOp())) && (!LeftOp->IsImmedOp())) { LeftOp->CleanOpndEncoding(); CurrUse = this->Uses.FindRef(LeftOp); if (CurrUse == this->GetLastUse()) { this->Uses.SetRef(LeftOp); } } RightOp = GuardExpr->GetRightOperand(); if ((!((nullptr == RightOp) || RightOp->IsVoidOp())) && (!RightOp->IsImmedOp())) { RightOp->CleanOpndEncoding(); CurrUse = this->Uses.FindRef(RightOp); if (CurrUse == this->GetLastUse()) { this->Uses.SetRef(RightOp); } } } return; } // end of SMPInstr::SyncRTLDefUse() // Get rid of unnecessary SIB byte encodings void SMPInstr::CleanSIBEncoding(STARSOpndTypePtr &RTLOp) { if ((nullptr != RTLOp) && RTLOp->IsMemOp()) { int BaseReg; int IndexReg; uint16_t ScaleFactor; STARS_ea_t offset; MDExtractAddressFields(RTLOp, BaseReg, IndexReg, ScaleFactor, offset); if (RTLOp->HasSIBByte()) { if ((IndexReg == STARS_x86_R_none) && (BaseReg != STARS_x86_R_none)) { // No need for a SIB byte if just base reg or base reg + offset. RTLOp->ClearSIB(); RTLOp->SetReg((STARS_regnum_t) BaseReg); } } if ((0 == offset) && RTLOp->IsMemDisplacementOp()) { RTLOp->SetTypeToMemNoDisplacement(); } } return; } // end of SMPInstr::CleanSIBEncoding() // Update the memory source operands to have the new type from profiling info. void SMPInstr::UpdateMemLoadTypes(SMPOperandType newType) { bool MemSrc = false; STARSOpndTypePtr Opnd; set<DefOrUse, LessDefUse>::iterator UseIter; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { Opnd = UseIter->GetOp(); MemSrc = Opnd->IsMemOp(); if (MemSrc) { SMPOperandType type = UseIter->GetType(); assert(newType == (NUMERIC|PROF_BASE)); if (type == UNINIT) { this->SetUseType(Opnd, newType); break; } else if (type >= POINTER) { this->SetUseType(Opnd, (SMPOperandType)(UNKNOWN|PROF_BASE)); break; } } } return ; } // end of SMPInstr::UpdateMemLoadTypes() // Return true if we have register DefOp += ImmOp. bool SMPInstr::MDIsAddImmediateToReg(STARSOpndTypePtr &DefOp, STARSOpndTypePtr &ImmOp) { bool FoundAddImmed = false; bool FoundImmed = false; bool FoundRegUse = false; if (STARS_NN_add == this->GetIDAOpcode()) { set<DefOrUse, LessDefUse>::iterator UseIter = this->GetFirstUse(); while (UseIter != this->GetLastUse()) { STARSOpndTypePtr UseOp = UseIter->GetOp(); if (UseOp->IsImmedOp()) { ImmOp = UseOp; FoundImmed = true; } else if (UseOp->IsRegOp()) { set<DefOrUse, LessDefUse>::iterator DefIter = this->GetFirstNonFlagsDef(); STARSOpndTypePtr TempDefOp = DefIter->GetOp(); if (!TempDefOp->IsRegOp()) { return false; } if (MDLessReg(UseOp->GetReg(), TempDefOp->GetReg()) || MDLessReg(TempDefOp->GetReg(), UseOp->GetReg())) { return false; } // If we make it here, we have the same register DEFed as we found USEd. DefOp = TempDefOp; FoundRegUse = true; } ++UseIter; } FoundAddImmed = (FoundImmed && FoundRegUse); } return FoundAddImmed; } // end of SMPInstr::MDIsAddImmediateToReg()