// // SMPInstr.cpp // // This module performs the instruction level analyses needed for the // SMP project (Software Memory Protection). // #include <cstring> #include <pro.h> #include <assert.h> #include <ida.hpp> #include <idp.hpp> #include <allins.hpp> #include <auto.hpp> #include <bytes.hpp> #include <funcs.hpp> #include <intel.hpp> #include <loader.hpp> #include <lines.hpp> #include <name.hpp> #include "SMPStaticAnalyzer.h" #include "SMPDataFlowAnalysis.h" #include "SMPInstr.h" #include "SMPProgram.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_CALL_TRASHES_REGS 1 // Add DEFs of caller-saved regs to CALL instructions #define SMP_BASEREG_POINTER_TYPE 1 // Initialize Base Register USEs to type POINTER? // Make the CF_CHG1 .. CF_CHG6 and CF_USE1..CF_USE6 macros more usable // by allowing us to pick them up with an array index. static ulong DefMacros[UA_MAXOP] = {CF_CHG1, CF_CHG2, CF_CHG3, CF_CHG4, CF_CHG5, CF_CHG6}; static ulong UseMacros[UA_MAXOP] = {CF_USE1, CF_USE2, CF_USE3, CF_USE4, CF_USE5, CF_USE6}; // Text to be printed in each optimizing annotation explaining why // the annotation was emitted. static char *OptExplanation[LAST_TYPE_CATEGORY + 1] = { "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM", "Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr", "AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest", "NumericSources", "StackMemoryTracking", "NumericSources", "NumericMemDest", "NeverMemDest", "SafeIfNoIndexing" }; static 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_NEGATE", "SMP_S_COMPARE", "SMP_U_COMPARE", "SMP_LESS_THAN", "SMP_GREATER_THAN", "SMP_LESS_EQUAL", "SMP_GREATER_EQUAL", "SMP_EQUAL", "SMP_NOT_EQUAL", "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" }; // ***************************************************************** // Class SMPGuard // ***************************************************************** // Constructor SMPGuard::SMPGuard(void) { this->LeftOperand.type = o_void; this->RightOperand.type = o_void; return; } // Debug print void SMPGuard::Dump(void) { msg("GUARD: "); PrintOperand(this->LeftOperand); msg(" %s ", OperatorText[this->GuardOp]); PrintOperand(this->RightOperand); msg(":"); return; } // end of SMPGuard::Dump() // ***************************************************************** // Class SMPRegTransfer // ***************************************************************** // Constructor SMPRegTransfer::SMPRegTransfer(void) { this->LeftOperand.type = o_void; this->RightOperand.type = o_void; this->RTop.type = UNINIT; this->RightSubTree = false; this->RightRT = NULL; this->Guard = NULL; return; } // Destructor SMPRegTransfer::~SMPRegTransfer() { #if 0 msg("Destroying SMPRegTransfer.\n"); #endif if (NULL != this->RightRT) delete this->RightRT; if (NULL != this->Guard) delete this->Guard; return; } // Debug print void SMPRegTransfer::Dump(void) { if (NULL != this->Guard) this->Guard->Dump(); // Left operand if (o_void != this->LeftOperand.type) PrintOperand(this->LeftOperand); // Then the operator msg(" %s ", OperatorText[this->GetOperator()]); // then the right operand or subtree if (this->HasRightSubTree()) this->GetRightTree()->Dump(); else if (o_void != this->RightOperand.type) PrintOperand(this->RightOperand); return; } // ***************************************************************** // Class SMPRTL // ***************************************************************** // Constructor SMPRTL::SMPRTL() { this->ExtraKills.clear(); this->RTCount = 0; return; } // Destructor SMPRTL::~SMPRTL() { for (size_t index = 0; index < this->RTCount; ++index) { delete (this->RTvector[index]); } this->ExtraKills.clear(); return; } // Get methods SMPRegTransfer *SMPRTL::GetRT(size_t index) { 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) { size_t index; if (0 < this->RTCount) { msg("RTL: "); for (index = 0; index < this->RTCount; ++index) { this->RTvector[index]->Dump(); } for (index = 0; index < this->ExtraKills.size(); ++index) { msg(" KILL: "); PrintOperand(this->ExtraKills.at(index)); } msg("\n"); } return; } // end of SMPRTL::Dump() // ***************************************************************** // Class SMPInstr // ***************************************************************** // Constructor for instruction. SMPInstr::SMPInstr(ea_t addr) { this->address = addr; this->analyzed = false; this->JumpTarget = false; this->BlockTerm = false; this->TailCall = false; this->Interrupt = false; this->DeadRegsString[0] = '\0'; this->DefsFlags = false; this->UsesFlags = false; this->TypeInferenceComplete = false; this->CategoryInferenceComplete = false; this->AddSubSourceType = UNINIT; this->BasicBlock = NULL; return; } // Is the instruction the type that terminates a basic block? bool SMPInstr::IsBasicBlockTerminator() const { return ((type == JUMP) || (type == COND_BRANCH) || (type == INDIR_JUMP) || (type == RETURN)); } // Is the destination operand a memory reference? bool SMPInstr::HasDestMemoryOperand(void) { bool MemDest = false; op_t Opnd; for (int i = 0; i < UA_MAXOP; ++i) { Opnd = SMPcmd.Operands[i]; optype_t CurrType = Opnd.type; if (this->features & DefMacros[i]) { // DEF MemDest = ((CurrType == o_mem) || (CurrType == o_phrase) || (CurrType == o_displ)); if (MemDest) break; } } return MemDest; } // end of SMPInstr::HasDestMemoryOperand() // Is a source operand a memory reference? bool SMPInstr::HasSourceMemoryOperand(void) { bool MemSrc = false; op_t Opnd; for (int i = 0; i < UA_MAXOP; ++i) { Opnd = SMPcmd.Operands[i]; optype_t CurrType = Opnd.type; if (this->features & UseMacros[i]) { // USE MemSrc = ((CurrType == o_mem) || (CurrType == o_phrase) || (CurrType == o_displ)); if (MemSrc) break; } } return MemSrc; } // end of SMPInstr::HasSourceMemoryOperand() // Get the first memory operand in the DEF list. op_t SMPInstr::MDGetMemDefOp(void) { set<DefOrUse, LessDefUse>::iterator DefIter; op_t MemOp; MemOp.type = o_void; for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { optype_t DefType = DefIter->GetOp().type; if ((DefType >= o_mem) && (DefType <= o_displ)) { MemOp = DefIter->GetOp(); break; } } return MemOp; } // end of SMPInstr::MDGetMemDefOp() // Get the first memory operand in the USE list. op_t SMPInstr::MDGetMemUseOp(void) { set<DefOrUse, LessDefUse>::iterator UseIter; op_t MemOp; MemOp.type = o_void; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { optype_t UseType = UseIter->GetOp().type; if ((UseType >= o_mem) && (UseType <= o_displ)) { MemOp = UseIter->GetOp(); break; } } return MemOp; } // end of SMPInstr::MDGetMemUseOp() // Does the instruction whose flags are in F 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(flags_t F) const { bool SecondOpImm = (SMPcmd.Operands[1].type == o_imm); uval_t TempImm; if (SecondOpImm) { TempImm = SMPcmd.Operands[1].value; } return (SecondOpImm && IsImmedNumeric(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. void SMPInstr::SetAddSubSourceType(void) { set<DefOrUse, LessDefUse>::iterator UseIter, DefIter; bool MemSrc = this->HasSourceMemoryOperand(); #if 0 // First, ensure that we are dealing with a register source. if (MemSrc) { this->AddSubSourceType = UNINIT; return; } #endif // The USE and DEF lists will have the flags and the destination // operand in common for register adds and subtracts. The USE-only // operand is the one we are concerned with. for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { op_t UseOp = UseIter->GetOp(); if (MemSrc) { if ((UseOp.type >= o_mem) && (UseOp.type <= o_displ)) { // Found the memory USE. this->AddSubSourceType = UseIter->GetType(); #if SMP_VERBOSE_DEBUG_INFER_TYPES msg("Set AddSubSourceType to %d at %x: %s\n", UseIter->GetType(), this->address, this->GetDisasm()); #endif break; } } else if (this->GetLastDef() == this->FindDef(UseOp)) { // Found the USE that is not a DEF this->AddSubSourceType = UseIter->GetType(); #if SMP_VERBOSE_DEBUG_INFER_TYPES msg("Set AddSubSourceType to %d at %x: %s\n", UseIter->GetType(), this->address, this->GetDisasm()); #endif break; } } 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) { AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType())); } return AllNumeric; } // end of SMPInstr::AllDefsNumeric() // DEBUG print operands for Inst. void SMPInstr::PrintOperands(void) const { op_t Opnd; for (int i = 0; i < UA_MAXOP; ++i) { Opnd = SMPcmd.Operands[i]; PrintOneOperand(Opnd, this->features, i); } msg(" \n"); return; } // end of SMPInstr::PrintOperands() // Complete DEBUG printing. void SMPInstr::Dump(void) { msg("%x %d SMPitype: %d %s\n", this->address, this->SMPcmd.size, (int) this->type, this->GetDisasm()); msg("USEs: "); this->Uses.Dump(); msg("DEFs: "); this->Defs.Dump(); this->RTL.Dump(); #if SMP_VERBOSE_DUMP this->PrintOperands(); #endif 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[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) { op_t DefOpnd = CurrDef->GetOp(); if (DefOpnd.is_reg(X86_FLAGS_REG)) // don't print flags as a destination continue; if (o_reg == DefOpnd.type) { ushort DestReg = DefOpnd.reg; if (0 == RegDestCount) { qstrncpy(DestList, RegNames[DestReg], 1 + strlen(RegNames[DestReg])); } else { qstrncat(DestList, " ", MAXSTR); qstrncat(DestList, RegNames[DestReg], MAXSTR); } ++RegDestCount; } } if (0 >= RegDestCount) { msg("WARNING: No destination registers: %s\n", this->GetDisasm()); } else { qstrncat(DestList, " ZZ ", MAXSTR); } return DestList; } // end of SMPInstr::DestString() // Equality operator for SMPInstr. Key field is address. int SMPInstr::operator==(const SMPInstr &rhs) const { if (this->address != rhs.GetAddr()) return 0; else return 1; } // Inequality operator for SMPInstr. Key field is address. int SMPInstr::operator!=(const SMPInstr &rhs) const { return (this->address != rhs.GetAddr()); } // Less than operator for sorting SMPInstr lists. Key field is address. int SMPInstr::operator<(const SMPInstr &rhs) const { return (this->address < rhs.GetAddr()); } // Less than or equal operator for sorting SMPInstr lists. Key field is address. int SMPInstr::operator<=(const SMPInstr &rhs) const { return (this->address <= rhs.GetAddr()); } #define MD_FIRST_ENTER_INSTR NN_enterw #define MD_LAST_ENTER_INSTR NN_enterq // Is this instruction the 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. op_t ESPOp; ESPOp.type = o_reg; ESPOp.reg = R_sp; if ((SMPcmd.itype == NN_sub) || (SMPcmd.itype == 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. // PHASE ORDERING: Should we use the Operands[] instead of the USE list? **!!** set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { if (o_imm == CurrUse->GetOp().type) { signed long TempImm = (signed long) CurrUse->GetOp().value; if (((0 > TempImm) && (SMPcmd.itype == NN_add)) || ((0 < TempImm) && (SMPcmd.itype == NN_sub))) { return true; } } else if ((o_reg == CurrUse->GetOp().type) && (!CurrUse->GetOp().is_reg(R_sp)) // skip the ESP operand && (SMPcmd.itype == NN_sub)) { // sub esp,reg: alloca() ? return true; } } } } else if ((SMPcmd.itype >= MD_FIRST_ENTER_INSTR) && (SMPcmd.itype <= MD_LAST_ENTER_INSTR)) { return true; } return false; } // end of SMPInstr::MDIsFrameAllocInstr() #define MD_FIRST_LEAVE_INSTR NN_leavew #define MD_LAST_LEAVE_INSTR 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, 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(); if ((SMPcmd.itype >= MD_FIRST_LEAVE_INSTR) && (SMPcmd.itype <= MD_LAST_LEAVE_INSTR)) return true; else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand()) { // 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 && (this->SMPcmd.itype == NN_mov) && (FirstDef->GetOp().is_reg(R_sp)) && (FirstUse->GetOp().is_reg(R_bp))) return true; else if ((this->SMPcmd.itype == NN_add) && (FirstDef->GetOp().is_reg(R_sp))) { set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse; if (SecondUse == this->Uses.GetLastRef()) return false; // no more USEs ... strange for ADD instruction if (SecondUse->GetOp().is_imm((uval_t) LocalVarsSize)) return true; else if (SecondUse->GetOp().type == o_imm) { signed long TempImm = (signed long) this->SMPcmd.Operands[1].value; if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc return false; else { 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; ushort opcode = this->SMPcmd.itype; if (NN_nop == opcode) IsNop = true; else if (NN_mov == opcode) { if ((o_reg == this->SMPcmd.Operands[0].type) && this->SMPcmd.Operands[1].is_reg(this->SMPcmd.Operands[0].reg)) { // We have a register to register move with source == destination. IsNop = true; } } else if (NN_lea == opcode) { if ((o_reg == this->SMPcmd.Operands[0].type) && (o_displ == this->SMPcmd.Operands[1].type) && (0 == this->SMPcmd.Operands[1].addr)) { // We are looking for 6-byte no-ops like lea esi,[esi+0] ushort destreg = this->SMPcmd.Operands[0].reg; if ((this->SMPcmd.Operands[1].hasSIB) && (destreg == (ushort) sib_base(this->SMPcmd.Operands[1])) && (R_sp == sib_index(this->SMPcmd.Operands[1]))) { // 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->SMPcmd.Operands[1].reg) { IsNop = true; } } } return IsNop; } // end of SMPInstr::MDIsNop() // MACHINE DEPENDENT: Is instruction a return instruction? bool SMPInstr::MDIsReturnInstr(void) const { return ((SMPcmd.itype == NN_retn) || (SMPcmd.itype == NN_retf)); } // MACHINE DEPENDENT: Is instruction a POP instruction? #define FIRST_POP_INST NN_pop #define LAST_POP_INST NN_popfq bool SMPInstr::MDIsPopInstr(void) const { return ((SMPcmd.itype >= FIRST_POP_INST) && (SMPcmd.itype <= LAST_POP_INST)); } // MACHINE DEPENDENT: Is instruction a PUSH instruction? #define FIRST_PUSH_INST NN_push #define LAST_PUSH_INST NN_pushfq bool SMPInstr::MDIsPushInstr(void) const { return ((SMPcmd.itype >= FIRST_PUSH_INST) && (SMPcmd.itype <= LAST_PUSH_INST)); } // MACHINE DEPENDENT: Is instruction an ENTER instruction? bool SMPInstr::MDIsEnterInstr(void) const { return ((SMPcmd.itype >= MD_FIRST_ENTER_INSTR) && (SMPcmd.itype <= MD_LAST_ENTER_INSTR)); } // MACHINE DEPENDENT: Is instruction a LEAVE instruction? bool SMPInstr::MDIsLeaveInstr(void) const { return ((SMPcmd.itype >= MD_FIRST_LEAVE_INSTR) && (SMPcmd.itype <= MD_LAST_LEAVE_INSTR)); } #define MD_FIRST_COND_MOVE_INSTR NN_cmova #define MD_LAST_COND_MOVE_INSTR NN_fcmovnu // MACHINE DEPENDENT: Is instruction a conditional move? bool SMPInstr::MDIsConditionalMoveInstr(void) const { return ((SMPcmd.itype >= MD_FIRST_COND_MOVE_INSTR) && (SMPcmd.itype <= MD_LAST_COND_MOVE_INSTR)); } // 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) { op_t CurrOp = CurrUse->GetOp(); if (CurrOp.is_reg(R_bp) || CurrOp.is_reg(R_si) || CurrOp.is_reg(R_di) || CurrOp.is_reg(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) { // OptType 3 indicates a move instruction if ((this->OptType == 3) && (this->GetFirstDef()->GetOp().type == o_reg) && (!(this->GetFirstDef()->GetOp().is_reg(R_sp))) && (!(this->HasSourceMemoryOperand()))) { // reg to reg move if (UseFP) { if (this->GetFirstUse()->GetOp().is_reg(R_bp)) // Move of base pointer EBP into a general register return true; else if ((this->GetFirstUse()->GetOp().is_reg(R_sp)) && !(this->GetFirstDef()->GetOp().is_reg(R_bp))) // Move of ESP into something besides a base pointer return true; } else if (this->GetFirstUse()->GetOp().is_reg(R_sp)) { // Move of ESP into a register; no base pointer used in this function return true; } } return false; } // end of SMPInstr::MDIsStackPointerCopy() // Is instruction a branch (conditional or unconditional) to a // code target that is not in the current chunk? bool SMPInstr::IsBranchToFarChunk(void) { func_t *CurrChunk = get_fchunk(this->address); bool FarBranch = false; if ((JUMP | COND_BRANCH) & this->GetDataFlowType()) { // Instruction is a direct branch, conditional or unconditional if (this->NumUses() > 0) { set<DefOrUse, LessDefUse>::iterator CurrUse; for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) { op_t JumpTarget = CurrUse->GetOp(); if ((o_near == JumpTarget.type) || (o_far == JumpTarget.type)) { // Branches to a code address func_t *TargetChunk = get_fchunk(JumpTarget.addr); // Is target address within the same chunk as the branch? FarBranch = (NULL == TargetChunk) || (CurrChunk->startEA != TargetChunk->startEA); } } } } return FarBranch; } // end of SMPInstr::IsBranchToFarChunk() set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseSSA(op_t CurrOp, int SSASub) { return this->Uses.SetSSANum(CurrOp, SSASub); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefSSA(op_t CurrOp, int SSASub) { return this->Defs.SetSSANum(CurrOp, SSASub); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetUseType(op_t CurrOp, SMPOperandType CurrType) { return this->Uses.SetType(CurrOp, CurrType); }; set<DefOrUse, LessDefUse>::iterator SMPInstr::SetDefType(op_t CurrOp, SMPOperandType CurrType) { return this->Defs.SetType(CurrOp, CurrType); }; // Analyze the instruction and its operands. void SMPInstr::Analyze(void) { if (this->analyzed) return; // Fill cmd structure with disassembly of instr ua_ana0(this->address); // Get the instr disassembly text. (void) generate_disasm_line(this->address, this->disasm, sizeof(this->disasm) - 1); // Remove interactive color-coding tags. tag_remove(this->disasm, this->disasm, 0); // Copy cmd to member variable SMPcmd. this->SMPcmd = cmd; // Get the canonical features into member variables features. this->features = cmd.get_canon_feature(); // Record what type of instruction this is, simplified for the needs // of data flow and type analysis. this->type = DFACategory[cmd.itype]; // Record optimization category. this->OptType = OptCategory[cmd.itype]; this->Interrupt = ((NN_int == cmd.itype) || (NN_into == cmd.itype) || (NN_int3 == cmd.itype)); // Build the DEF and USE lists for the instruction. this->BuildSMPDefUseLists(); // Fix up machine dependent quirks in the def and use lists. this->MDFixupDefUseLists(); // Determine whether the instruction is a jump target by looking // at its cross references and seeing if it has "TO" code xrefs. xrefblk_t xrefs; for (bool ok = xrefs.first_to(this->address, XREF_FAR); ok; ok = xrefs.next_to()) { if ((xrefs.from != 0) && (xrefs.iscode)) { this->JumpTarget = true; break; } } this->analyzed = true; return; } // end of SMPInstr::Analyze() // Analyze the floating point NOP marker instruction at the top of the function. void SMPInstr::AnalyzeMarker(void) { if (this->analyzed) return; // Fill member variable SMPcmd structure with disassembly of instr (void) memset(&(this->SMPcmd), 0, sizeof(this->SMPcmd)); this->SMPcmd.itype = NN_fnop; this->SMPcmd.size = 1; this->SMPcmd.ea = this->address; // Get the instr disassembly text. qstrncpy(this->disasm, "\tfnop\t; Top of function SSA marker for SMP", sizeof(this->disasm) - 1); // Record what type of instruction this is, simplified for the needs // of data flow and type analysis. this->type = DFACategory[this->SMPcmd.itype]; // Record optimization category. this->OptType = OptCategory[this->SMPcmd.itype]; this->analyzed = true; return; } // end of SMPInstr::AnalyzeMarker() // Fill the Defs and Uses private data members. void SMPInstr::BuildSMPDefUseLists(void) { size_t OpNum; bool DebugFlag = (0x804837b == this->GetAddr()); this->Defs.clear(); this->Uses.clear(); // Start with the Defs. for (OpNum = 0; OpNum < UA_MAXOP; ++OpNum) { if (this->features & DefMacros[OpNum]) { // DEF op_t TempOp = this->SMPcmd.Operands[OpNum]; if (MDKnownOperandType(TempOp)) { if (DebugFlag) { msg("DEBUG: Setting DEF for: "); PrintOperand(TempOp); msg("\n"); } if (o_reg == TempOp.type) { // We want to map AH, AL, and AX to EAX, etc. throughout our data flow // analysis and type inference systems. TempOp.reg = MDCanonicalizeSubReg(TempOp.reg); } this->Defs.SetRef(TempOp); } } } // end for (OpNum = 0; ...) // 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 < UA_MAXOP; ++OpNum) { if (this->features & UseMacros[OpNum]) { // USE op_t TempOp = this->SMPcmd.Operands[OpNum]; if (MDKnownOperandType(TempOp)) { if (DebugFlag) { msg("DEBUG: Setting USE for: "); PrintOperand(TempOp); msg("\n"); } if (o_reg == TempOp.type) { // We want to map AH, AL, and AX to EAX, etc. throughout our data flow // analysis and type inference systems. TempOp.reg = MDCanonicalizeSubReg(TempOp.reg); } this->Uses.SetRef(TempOp); } } } // end for (OpNum = 0; ...) return; } // end of SMPInstr::BuildSMPDefUseLists() // If DefReg is not already in the DEF list, add a DEF for it. void SMPInstr::MDAddRegDef(ushort DefReg, bool Shown) { op_t TempDef; TempDef.type = o_reg; TempDef.reg = DefReg; if (Shown) TempDef.set_showed(); else TempDef.clr_showed(); this->Defs.SetRef(TempDef); return; } // end of SMPInstr::MDAddRegDef() // If UseReg is not already in the USE list, add a USE for it. void SMPInstr::MDAddRegUse(ushort UseReg, bool Shown) { op_t TempUse; TempUse.type = o_reg; TempUse.reg = UseReg; if (Shown) TempUse.set_showed(); else TempUse.clr_showed(); this->Uses.SetRef(TempUse); 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. size_t OpNum; SMPOperandType RefType; int BaseReg; int IndexReg; ushort ScaleFactor; ea_t displacement; bool UseFP = true; bool HasIndexReg = false; bool SingleAddressReg = false; bool leaInst = (NN_lea == this->SMPcmd.itype); bool DebugFlag = (this->GetAddr() == 0x804837b); if (DebugFlag) { 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 for (OpNum = 0; OpNum < UA_MAXOP; ++OpNum) { op_t Opnd = SMPcmd.Operands[OpNum]; if ((Opnd.type == o_phrase) || (Opnd.type == o_displ) || (Opnd.type == o_mem)) { MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement); SingleAddressReg = ((0 == displacement) && ((R_none == BaseReg) || (R_none == IndexReg))); if (R_none != IndexReg) { op_t IndexOpnd = Opnd; // Init to current operand field values IndexOpnd.type = o_reg; // Change type and reg fields IndexOpnd.reg = IndexReg; IndexOpnd.hasSIB = 0; IndexOpnd.set_showed(); // We want to map AH, AL, and AX to EAX, etc. throughout our data flow // analysis and type inference systems. IndexOpnd.reg = MDCanonicalizeSubReg(IndexOpnd.reg); if (0 == ScaleFactor) this->Uses.SetRef(IndexOpnd); else { // scaling == shift ==> NUMERIC HasIndexReg = true; this->Uses.SetRef(IndexOpnd, NUMERIC); } } if (R_none != BaseReg) { op_t BaseOpnd = Opnd; // Init to current operand field values BaseOpnd.type = o_reg; // Change type and reg fields BaseOpnd.reg = BaseReg; BaseOpnd.hasSIB = 0; BaseOpnd.set_showed(); // We want to map AH, AL, and AX to EAX, etc. throughout our data flow // analysis and type inference systems. BaseOpnd.reg = MDCanonicalizeSubReg(BaseOpnd.reg); RefType = UNINIT; #if SMP_BASEREG_POINTER_TYPE // R_sp and 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 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.is_reg(R_sp) || (UseFP && BaseOpnd.is_reg(R_bp)) || leaInst || (!HasIndexReg && !SingleAddressReg)) { ; } else { RefType = POINTER; } #endif this->Uses.SetRef(BaseOpnd, RefType); } // end if R_none != BaseReg } // end if (o_phrase or o_displ operand) } // end for (all operands) // 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 = (0 != (this->SMPcmd.auxpref & aux_rep)); bool HasRepnePrefix = (0 != (this->SMPcmd.auxpref & aux_repne)); if (HasRepPrefix && HasRepnePrefix) msg("REP and REPNE both present at %x %s\n", this->GetAddr(), this->GetDisasm()); if (HasRepPrefix || HasRepnePrefix) { // All repeating instructions use ECX as the countdown register. op_t BaseOpnd; BaseOpnd.type = o_reg; // Change type and reg fields BaseOpnd.reg = R_cx; BaseOpnd.hasSIB = 0; BaseOpnd.clr_showed(); this->Defs.SetRef(BaseOpnd); this->Uses.SetRef(BaseOpnd); } if ((this->SMPcmd.itype == NN_cmps) || (this->SMPcmd.itype == NN_scas) || (this->SMPcmd.itype == NN_movs) || (this->SMPcmd.itype == 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. op_t BaseOpnd; BaseOpnd.type = o_reg; // Change type and reg fields BaseOpnd.hasSIB = 0; BaseOpnd.clr_showed(); if ((this->SMPcmd.itype == NN_cmps) || (this->SMPcmd.itype == NN_movs)) { BaseOpnd.reg = R_si; this->Defs.SetRef(BaseOpnd); this->Uses.SetRef(BaseOpnd); } BaseOpnd.reg = R_di; this->Defs.SetRef(BaseOpnd); this->Uses.SetRef(BaseOpnd); } // Now, handle special instruction categories that have implicit operands. if (NN_cmpxchg == this->SMPcmd.itype) { // x86 Compare and Exchange conditionally sets EAX. We must keep data flow analysis // sound by declaring that EAX is always a DEF. this->MDAddRegDef(R_ax, false); } // end if NN_cmpxchg else if (this->MDIsPopInstr() || this->MDIsPushInstr() || this->MDIsReturnInstr()) { // IDA does not include the stack pointer in the DEFs or USEs. this->MDAddRegDef(R_sp, false); this->MDAddRegUse(R_sp, false); if (!this->MDIsReturnInstr()) { // We always reference [esp+0] or [esp-4], so add it to the DEF or USE list. op_t StackOp; StackOp.type = o_displ; StackOp.reg = R_sp; StackOp.hasSIB = 0; StackOp.dtyp = dt_dword; if (this->MDIsPopInstr()) { StackOp.addr = 0; // [ESP+0] this->Uses.SetRef(StackOp); // USE } else { StackOp.addr = (ea_t) -4; // [ESP-4] this->Defs.SetRef(StackOp); // DEF } } } #if SMP_CALL_TRASHES_REGS else if ((this->type == CALL) || (this->type == INDIR_CALL)) { // We want to add the caller-saved registers to the USEs and DEFs lists this->MDAddRegDef(R_ax, false); this->MDAddRegDef(R_cx, false); this->MDAddRegDef(R_dx, false); if (this->MDIsInterruptCall()) { this->MDAddRegUse(R_ax, false); this->MDAddRegUse(R_cx, false); this->MDAddRegUse(R_dx, false); } } #endif else if (this->MDIsEnterInstr() || this->MDIsLeaveInstr()) { // Entire function prologue or epilogue microcoded. this->MDAddRegDef(R_sp, false); this->MDAddRegUse(R_sp, false); this->MDAddRegDef(R_bp, false); this->MDAddRegUse(R_bp, false); } else if (this->SMPcmd.itype == NN_maskmovq) { this->MDAddRegUse(R_di, false); } else if (8 == this->GetOptType()) { // This category implicitly writes to EDX:EAX. this->MDAddRegDef(R_dx, false); this->MDAddRegDef(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 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 < UA_MAXOP; ++OpNum) { op_t TempUse = SMPcmd.Operands[OpNum]; if (!TempUse.showed()) { // hidden operand if (TempUse.is_reg(R_ax)) { // not R_al, so it is not 8 bits if ((NN_div == this->SMPcmd.itype) || (NN_idiv == this->SMPcmd.itype)) { this->MDAddRegUse(R_dx, false); } this->MDAddRegDef(R_ax, false); this->MDAddRegDef(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[this->SMPcmd.itype]) || (15 == SMPTypeCategory[this->SMPcmd.itype])) { } #endif #if 0 // Not true for LOOP instructions that use only the ECX counter register. if (this->type == COND_BRANCH) { assert(SMPUsesFlags[this->SMPcmd.itype]); } #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. if (this->type == RETURN) { this->MDAddRegUse(R_ax, false); } // Next, add the flags register to the DEFs and USEs for those instructions that // are marked as defining or using flags. if (!this->DefsFlags && SMPDefsFlags[this->SMPcmd.itype]) { this->MDAddRegDef(X86_FLAGS_REG, false); this->DefsFlags = true; } if (!this->UsesFlags && SMPUsesFlags[this->SMPcmd.itype]) { this->MDAddRegUse(X86_FLAGS_REG, false); this->UsesFlags = true; } #if 1 if (this->MDIsNop()) { // Clear the DEFs and USEs for no-ops. this->Defs.clear(); this->Uses.clear(); } #endif if (DebugFlag) { msg("DEBUG after MDFixupDefUseLists:\n"); this->Dump(); } return; } // end of SMPInstr::MDFixupDefUseLists() // 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. bool SMPInstr::MDFindPointerUse(op_t MemOp, bool UseFP) { bool changed = false; int BaseReg; int IndexReg; ushort ScaleFactor; ea_t offset; set<DefOrUse, LessDefUse>::iterator UseIter; if (NN_lea == this->SMPcmd.itype) return false; // lea instruction really has no memory operands if (NN_fnop == this->SMPcmd.itype) return false; // SSA marker instruction MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor, offset); if ((R_sp == BaseReg) || (R_sp == IndexReg)) return false; // stack accesses will get STACKPTR type in SetImmedTypes() if (UseFP && ((R_bp == BaseReg) || (R_bp == IndexReg))) return false; if (IsImmedGlobalAddress(offset)) return false; // handled in SetImmedTypes() // At this point, we must have a base address in a register. if ((0 < ScaleFactor) || (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 (R_none != BaseReg) { op_t BaseOp; BaseOp.type = o_reg; BaseOp.reg = MDCanonicalizeSubReg(BaseReg); UseIter = this->FindUse(BaseOp); assert(UseIter != this->GetLastUse()); if (UNINIT == UseIter->GetType()) { changed = true; UseIter = this->SetUseType(BaseOp, POINTER); assert(UseIter != this->GetLastUse()); } } } else if (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 (R_none != IndexReg) { op_t IndexOp; IndexOp.type = o_reg; IndexOp.reg = MDCanonicalizeSubReg(IndexReg); UseIter = this->FindUse(IndexOp); assert(UseIter != this->GetLastUse()); if (UNINIT == UseIter->GetType()) { changed = true; UseIter = this->SetUseType(IndexOp, POINTER); assert(UseIter != 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. op_t IndexOp; IndexOp.type = o_reg; IndexOp.reg = MDCanonicalizeSubReg(IndexReg); op_t BaseOp; BaseOp.type = o_reg; BaseOp.reg = MDCanonicalizeSubReg(BaseReg); UseIter = this->FindUse(BaseOp); assert(UseIter != this->GetLastUse()); if (IsNumeric(UseIter->GetType())) { UseIter = this->FindUse(IndexOp); assert(UseIter != this->GetLastUse()); if (UNINIT == UseIter->GetType()) { // Set to POINTER or PROF_POINTER changed = true; UseIter = this->SetUseType(IndexOp, POINTER); assert(UseIter != this->GetLastUse()); } } else { // BaseReg was not NUMERIC if (UNINIT == UseIter->GetType()) { // BaseReg is UNINIT UseIter = this->FindUse(IndexOp); assert(UseIter != this->GetLastUse()); if (IsNumeric(UseIter->GetType())) { changed = true; UseIter = this->SetUseType(BaseOp, POINTER); assert(UseIter != this->GetLastUse()); } } } } return changed; } // end of SMPInstr::MDFindPointerUse() // Are all DEFs typed to something besides UNINIT? bool SMPInstr::AllDEFsTyped(void) { bool FoundUNINIT = false; set<DefOrUse, LessDefUse>::iterator DefIter; for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) { if (IsEqType(UNINIT, DefIter->GetType())) { FoundUNINIT = true; break; } } return (!FoundUNINIT); } // end of SMPInstr::AllDEFsTyped() // Are all USEs typed to something besides UNINIT? bool SMPInstr::AllUSEsTyped(void) { bool FoundUNINIT = false; set<DefOrUse, LessDefUse>::iterator UseIter; for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) { if (IsEqType(UNINIT, UseIter->GetType())) { FoundUNINIT = true; break; } } return (!FoundUNINIT); } // end of SMPInstr::AllUSEsTyped() // 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. void SMPInstr::SetImmedTypes(bool UseFP) { set<DefOrUse, LessDefUse>::iterator CurrUse; set<DefOrUse, LessDefUse>::iterator CurrDef; op_t UseOp; op_t DefOp; uval_t ImmVal; bool DebugFlag = false; #if SMP_VERBOSE_DEBUG_BUILD_RTL DebugFlag = DebugFlag || (this->address == 0x805cd52) || (this->address == 0x805cd56); DebugFlag |= (0 == strncmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName(), 15)); #endif CurrUse = this->GetFirstUse(); while (CurrUse != this->GetLastUse()) { UseOp = CurrUse->GetOp(); if (DebugFlag) { msg("SetImmedTypes USE: "); PrintOperand(UseOp); msg("\n"); } if (o_imm == UseOp.type) { ImmVal = UseOp.value; if (IsImmedGlobalAddress((ea_t) ImmVal)) { if (DebugFlag) msg("Setting to GLOBALPTR\n"); CurrUse = this->SetUseType(UseOp, GLOBALPTR); } else if (this->Interrupt || IsImmedCodeAddress((ea_t) ImmVal)) { if (DebugFlag) msg("Setting to CODEPTR\n"); CurrUse = this->SetUseType(UseOp, CODEPTR); } else { // NUMERIC if (DebugFlag) msg("Setting to NUMERIC\n"); CurrUse = this->SetUseType(UseOp, NUMERIC); } } else if (o_reg == UseOp.type) { if (UseOp.is_reg(X86_FLAGS_REG)) { if (DebugFlag) msg("Setting flags reg to NUMERIC\n"); CurrUse = this->SetUseType(UseOp, NUMERIC); } #if 1 else if (UseOp.is_reg(R_sp) || (UseFP && UseOp.is_reg(R_bp))) { if (DebugFlag) msg("Setting reg to STACKPTR\n"); CurrUse = this->SetUseType(UseOp, STACKPTR); } #endif } #if 0 // could these registers have pointers in them? else if ((o_trreg == UseOp.type) ||(o_dbreg == UseOp.type) || (o_crreg == UseOp.type)) { if (DebugFlag) msg("Setting special reg to NUMERIC\n"); CurrUse = this->SetUseType(UseOp, NUMERIC); } #endif else if ((o_fpreg == UseOp.type) || (o_mmxreg == UseOp.type) || (o_xmmreg == UseOp.type)) { if (DebugFlag) msg("Setting floating point reg to NUMERIC\n"); CurrUse = this->SetUseType(UseOp, NUMERIC); } else if ((o_mem == UseOp.type) || (o_phrase == UseOp.type) || (o_displ == UseOp.type)) { // 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 (DebugFlag) { msg("SetImmedTypes DEF: "); PrintOperand(DefOp); msg("\n"); } if (DebugFlag) msg("FuncName: %s\n", this->BasicBlock->GetFunc()->GetFuncName()); if (o_reg == DefOp.type) { if (DefOp.is_reg(X86_FLAGS_REG)) { if (DebugFlag) msg("Setting flags reg DEF to NUMERIC\n"); CurrDef = this->SetDefType(DefOp, NUMERIC); // No need to propagate this DEF type, as all flags will become NUMERIC. } #if 1 else if (DefOp.is_reg(R_sp) || (DefOp.is_reg(R_bp) && UseFP)) { if (DebugFlag) msg("Setting reg DEF to STACKPTR\n"); 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 ((o_fpreg == DefOp.type) || (o_mmxreg == DefOp.type) || (o_xmmreg == DefOp.type)) { if (DebugFlag) msg("Setting floating point reg DEF to NUMERIC\n"); 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 ((o_trreg == DefOp.type) || (o_dbreg == DefOp.type) || (o_crreg == DefOp.type)) { if (DebugFlag) msg("Setting special reg DEF to NUMERIC\n"); CurrDef = this->SetDefType(DefOp, NUMERIC); } #endif else if ((o_mem == DefOp.type) || (o_phrase == DefOp.type) || (o_displ == DefOp.type)) { // 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() // 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; int SSANum; int TypeCategory = SMPTypeCategory[this->SMPcmd.itype]; set<DefOrUse, LessDefUse>::iterator CurrDef; set<DefOrUse, LessDefUse>::iterator CurrUse; op_t DefOp, UseOp; bool DebugFlag = false; bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer(); #if SMP_VERBOSE_DEBUG_INFER_TYPES DebugFlag |= (0 == strcmp("__libc_csu_fini", this->BasicBlock->GetFunc()->GetFuncName())); #endif if (DebugFlag) { msg("opcode: %d TypeCategory: %d\n", this->SMPcmd.itype, TypeCategory); } // If we are already finished with all types, return false. if (this->TypeInferenceComplete) return false; if (this->AllDEFsTyped() && this->AllUSEsTyped()) { this->TypeInferenceComplete = true; 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(); if (DebugFlag) { msg("DFAType: %d CategoryInferenceComplete: %d\n", DFAType, this->CategoryInferenceComplete); } if ((DFAType >= JUMP) && (DFAType <= INDIR_CALL)) { // All USEs are either the flags (NUMERIC) or the target address (CODEPTR). // The exception is the USE list for interrupt calls, which includes // the caller-saved regs. CurrUse = this->GetFirstUse(); while (CurrUse != this->GetLastUse()) { UseOp = CurrUse->GetOp(); if (UseOp.is_reg(X86_FLAGS_REG)) CurrUse = this->SetUseType(UseOp, NUMERIC); else if ((CurrUse->GetType() != CODEPTR) && (!(this->MDIsInterruptCall() && (o_reg == UseOp.type)))) { CurrUse = this->SetUseType(UseOp, CODEPTR); } ++CurrUse; } this->TypeInferenceComplete = true; return true; } // First, see if we can infer something about DEFs and USEs just from the // type category of the instruction. if (!this->CategoryInferenceComplete) { 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->CategoryInferenceComplete = true; 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. case 15: // Result type is always NUMERIC. CurrDef = this->GetFirstDef(); while (CurrDef != this->GetLastDef()) { if (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. **!!** if ((o_reg == DefOp.type) || (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) { if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, NUMERIC, this->GetAddr(), SSANum); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, NUMERIC, SSANum); } } } ++CurrDef; } this->CategoryInferenceComplete = true; 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.is_reg(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. **!!** if ((o_reg == DefOp.type) || (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) { if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, CurrUse->GetType(), this->GetAddr(), SSANum); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, CurrUse->GetType(), SSANum); } } } ++CurrDef; } this->CategoryInferenceComplete = true; changed = true; this->TypeInferenceComplete = true; } break; case 6: // Result is always POINTER DefOp = this->GetFirstDef()->GetOp(); SSANum = this->GetFirstDef()->GetSSANum(); CurrDef = this->SetDefType(DefOp, POINTER); this->CategoryInferenceComplete = true; changed = true; // Be conservative and only propagate register DEFs and SAFE stack locs. We // can improve this in the future. **!!** if ((o_reg == DefOp.type) || (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) { if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, POINTER, this->GetAddr(), SSANum); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, POINTER, SSANum); } } break; default: msg("ERROR: Unknown type category for %s\n", this->GetDisasm()); this->CategoryInferenceComplete = true; break; } // end switch on TypeCategory } // end if (!CategoryInference) // Walk the RTL and infer types based on operators and operands. if (DebugFlag) { msg("RTcount: %d\n", this->RTL.GetCount()); } for (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; changed |= this->InferOperatorType(CurrRT); if (DebugFlag) { msg("returned from InferOperatorType\n"); } } // 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; bool LeftPointer, RightPointer; 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 = UNINIT; op_t UseOp, DefOp, LeftOp, RightOp; SMPoperator CurrOp = CurrRT->GetOperator(); bool DebugFlag = false; #if SMP_VERBOSE_DEBUG_INFER_TYPES #if 0 DebugFlag |= (0 == strcmp("strtok", this->BasicBlock->GetFunc()->GetFuncName())); #endif DebugFlag = DebugFlag || ((this->address == 0x805cd52) || (this->address == 0x805cd56)); #endif #if SMP_VERBOSE_DEBUG_INFER_TYPES if (DebugFlag) { msg("Entered InferOperatorType for CurrOp: %d\n", CurrOp); } #endif switch (CurrOp) { case SMP_NULL_OPERATOR: break; case SMP_CALL: // CALL instruction if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(CODEPTR); 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()) { msg("WARNING: call target is type %d, setting to CODEPTR at %x in %s\n", CurrUse->GetType(), this->GetAddr(), this->GetDisasm()); CurrUse = this->SetUseType(UseOp, CODEPTR); } } break; case SMP_INPUT: // input from port if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(UNKNOWN); // Leave DEF as UNINIT and infer later updated = true; } break; case SMP_OUTPUT: // output to port case SMP_SIGN_EXTEND: case SMP_ZERO_EXTEND: break; case SMP_ADDRESS_OF: // take effective address if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(POINTER); // Left operand is having its address taken, but we cannot infer what its // type is. updated = true; } break; 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_ADD_CARRY: // add with carry case SMP_SUBTRACT_BORROW: // subtract with borrow case SMP_U_MULTIPLY: case SMP_S_MULTIPLY: case SMP_U_DIVIDE: case SMP_S_DIVIDE: case SMP_U_REMAINDER: case SMP_BITWISE_NOT: // unary operator case SMP_BITWISE_XOR: case SMP_NEGATE: // unary negation case SMP_S_COMPARE: // signed compare (subtraction-based) case SMP_U_COMPARE: // unsigned compare (AND-based) 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_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 if (UNINIT == CurrRT->GetOperatorType()) { CurrRT->SetOperatorType(NUMERIC); updated = true; } // Left operand should be NUMERIC if it exists. UseOp = CurrRT->GetLeftOperand(); if (UseOp.type != o_void) { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { msg("WARNING: Adding missing USE of "); PrintOperand(UseOp); msg(" in %s\n", this->GetDisasm()); 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 updated |= this->InferOperatorType(CurrRT->GetRightTree()); } else { UseOp = CurrRT->GetRightOperand(); if (UseOp.type != o_void) { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { msg("WARNING: Adding missing USE of "); PrintOperand(UseOp); msg(" in %s\n", this->GetDisasm()); this->Uses.SetRef(UseOp, NUMERIC, -1); updated = true; } else if (UNINIT == CurrUse->GetType()) { CurrUse = this->SetUseType(UseOp, NUMERIC); updated = true; } } } break; case SMP_INCREMENT: case SMP_DECREMENT: // The type of the right operand is propagated to the operator, or vice // versa, whichever receives a type first. assert(!CurrRT->HasRightSubTree()); UseOp = CurrRT->GetLeftOperand(); assert(o_void != UseOp.type); CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { msg("WARNING: Adding missing USE of "); PrintOperand(UseOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); 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()); 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_BITWISE_AND: case SMP_BITWISE_OR: // Extract the current types of right and left operands and the operator. LeftOp = CurrRT->GetLeftOperand(); CurrUse = this->Uses.FindRef(LeftOp); assert(CurrUse != this->GetLastUse()); // found it LeftType = CurrUse->GetType(); if (CurrRT->HasRightSubTree()) { RightType = CurrRT->GetRightTree()->GetOperatorType(); } else { RightOp = CurrRT->GetRightOperand(); if (o_void == RightOp.type) { msg("ERROR: void operand in %s\n", this->GetDisasm()); return false; } else { CurrUse = this->Uses.FindRef(RightOp); if (CurrUse == this->GetLastUse()) { msg("WARNING: Adding missing USE of "); PrintOperand(RightOp); msg(" in %s\n", this->GetDisasm()); 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 to infer the operand types. if ((UNINIT == CurrRT->GetOperatorType()) && ((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 == CurrRT->GetOperatorType()) { // Infer operator type from left and right operands. if (LeftNumeric && RightNumeric) { CurrRT->SetOperatorType(NUMERIC); 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); updated = true; break; } else if (RightNumeric && (UNINIT != LeftType) && ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp))) { CurrRT->SetOperatorType(LeftType); updated = true; break; } } else if (LeftPointer && RightPointer) { // Arithmetic on two pointers if ((SMP_ADD == CurrOp) || (SMP_ADD_CARRY == CurrOp)) { CurrRT->SetOperatorType(UNKNOWN); updated = true; } else { // bitwise AND or OR of two pointers msg("WARNING: hash of two pointers at %x in %s\n", this->GetAddr(), this->GetDisasm()); // 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); updated = true; } else { // bitwise AND or OR of pointer and pointer difference msg("WARNING: hash of PTROFFSET and POINTER at %x in %s\n", this->GetAddr(), this->GetDisasm()); // hash operation? leave operator as UNINIT } break; } } // end if UNINIT operator type else { // operator has type other than UNINIT if (UNINIT == LeftType) { 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()); 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; } } } break; case SMP_SUBTRACT: // 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()) { RightType = CurrRT->GetRightTree()->GetOperatorType(); } else { RightOp = CurrRT->GetRightOperand(); if (o_void == RightOp.type) { msg("ERROR: void operand in %s\n", this->GetDisasm()); return false; } else { RightUse = this->Uses.FindRef(RightOp); if (RightUse == this->GetLastUse()) { msg("WARNING: Adding missing USE of "); PrintOperand(RightOp); msg(" in %s\n", this->GetDisasm()); 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. if (UNINIT == OperType) { CurrRT->SetOperatorType(NUMERIC); updated = true; } else if (NUMERIC != OperType) { msg("ERROR: SMP_SUBTRACT from NUMERIC should be NUMERIC operator."); msg(" Operator type is %d in: %s\n", OperType, this->GetDisasm()); } #if 0 if (!RightNumeric) { // Right operand is being used as a NUMERIC, so propagate NUMERIC to it. if (CurrRT->HasRightSubTree()) { CurrRT->GetRightTree()->SetOperatorType(NUMERIC); } 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); updated = true; } else if (RightType == PTROFFSET) { // We assume B - (B - A) == A **!!** CurrRT->SetOperatorType(POINTER); msg("WARNING: PTR - PTROFFSET produces PTR in %s\n", this->GetDisasm()); updated = true; } else if (RightNumeric) { // pointer minus NUMERIC keeps same pointer type CurrRT->SetOperatorType(LeftType); updated = true; } } else { // we have an operator type for the SMP_SUBTRACT bool OperatorPointer = IsDataPtr(OperType); if (CurrRT->HasRightSubTree()) { // Must need to iterate through the right tree again, as the operator // has been typed. if (UNINIT == RightType) { if (OperatorPointer) { // PTR := PTR - ?? ==> ?? is NUMERIC CurrRT->GetRightTree()->SetOperatorType(NUMERIC); updated = true; } else if (OperType == PTROFFSET) { // PTROFFSET := PTR - ?? ==> ?? is PTR CurrRT->GetRightTree()->SetOperatorType(LeftType); updated = true; } } updated |= this->InferOperatorType(CurrRT->GetRightTree()); break; } else { // right operand; propagate operator type if needed if (UNINIT == RightType) { if (OperatorPointer) { // PTR := PTR - ?? ==> ?? is NUMERIC 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; } break; } } } // end if OperType is UNINIT ... else ... } // end if LeftNumeric ... else if LeftPointer ... else if (UNINIT == LeftType) { if (UNINIT != OperType) { 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()) { RightType = CurrRT->GetRightTree()->GetOperatorType(); } else { UseOp = CurrRT->GetRightOperand(); if (o_void == UseOp.type) { msg("ERROR: void operand for SMP_ASSIGN in %s\n", this->GetDisasm()); return false; } else { CurrUse = this->Uses.FindRef(UseOp); if (CurrUse == this->GetLastUse()) { msg("WARNING: Adding missing USE of "); PrintOperand(UseOp); msg(" in %s\n", this->GetDisasm()); this->Uses.SetRef(UseOp); updated = true; break; } else { RightType = CurrUse->GetType(); } } } // We keep it simple by only trying to propagate one step at a time, from // the right operand or tree up to the SMP_ASSIGN operator, then from // the operator to the left (DEF) operand, or from left up to operator // and down the right, depending on where the existing types are. if (DebugFlag) { msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType, OperType, RightType); } if ((UNINIT == RightType) && (UNINIT == LeftType)) { // We will only try to solve the right hand side on this iteration. if (CurrRT->HasRightSubTree()) { updated |= this->InferOperatorType(CurrRT->GetRightTree()); } break; } else if (UNINIT == OperType) { // UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT. 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); updated = true; } } else { CurrRT->SetOperatorType(LeftType); updated = true; } break; } else if (UNINIT == LeftType) { // SMP_ASSIGN operator has type, so propagate it. LeftType = OperType; CurrDef = this->SetDefType(DefOp, 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())) { // Be conservative and only propagate register DEFs and SAFE stack locs. // We can improve this in the future. **!!** if ((o_reg == DefOp.type) || (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) { int SSANum = CurrDef->GetSSANum(); if (this->BasicBlock->IsLocalName(DefOp)) { (void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType, this->GetAddr(), SSANum); } else { // global name this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false (void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType, SSANum); } } } break; } else if (UNINIT == RightType) { // SMP_ASSIGN operator has type, so propagate it. if (CurrRT->HasRightSubTree()) { CurrRT->GetRightTree()->SetOperatorType(OperType); 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()) { msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ", CurrUse->GetType(), OperType, this->address); PrintOperand(CurrUse->GetOp()); msg("\n"); } } CurrUse = this->SetUseType(UseOp, OperType); updated = true; } break; } break; default: msg("Unknown operator in %s\n", this->GetDisasm()); break; } // end switch on operator return updated; } // end of SMPInstr::InferOperatorType() // Handle x86 opcode SIB byte annotations. void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) { int BaseReg; int IndexReg; ea_t displacement; ushort ScaleFactor; MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement); if (BaseReg == R_sp) { // ESP cannot be IndexReg // ESP-relative constant offset qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK %d displ %s\n", this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm); } else if (UseFP && ((IndexReg == R_bp) || (BaseReg == R_bp))) { // EBP-relative constant offset qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK %d displ %s\n", this->SMPcmd.ea, this->SMPcmd.size, offset, this->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) { op_t Opnd; ea_t offset; int BaseReg; int IndexReg; ushort ScaleFactor; #if 0 if (this->address == 0x80925f4) { msg("PROBLEM INSTRUCTION: \n"); this->PrintOperands(); } #endif for (int i = 0; i < UA_MAXOP; ++i) { Opnd = SMPcmd.Operands[i]; if ((Opnd.type == o_displ) || (Opnd.type == o_phrase)) MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset); if (Opnd.type == o_displ) { if (Opnd.hasSIB) { MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP); } else { // no SIB if (BaseReg == R_sp) { // ESP-relative constant offset qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK %d displ %s\n", SMPcmd.ea, SMPcmd.size, offset, disasm); } else if (UseFP && (BaseReg == R_bp)) { // EBP-relative constant offset qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK %d displ %s\n", SMPcmd.ea, SMPcmd.size, offset, disasm); } } // end if (Opnd.hasSIB) ... else ... } // end if (Opnd.type == o_displ) else if (Opnd.type == o_phrase) { offset = 0; // mmStrata thinks [esp] is [esp+0] if (Opnd.hasSIB) { MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP); } else { // Something like [ecx]; is it [esp] or [ebp] ? if (BaseReg == R_sp) { // ESP-relative constant offset qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK %d displ %s\n", SMPcmd.ea, SMPcmd.size, offset, disasm); } else if (UseFP && (BaseReg == R_bp)) { // EBP-relative constant offset qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK %d displ %s\n", SMPcmd.ea, SMPcmd.size, offset, 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)) { if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) { qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK 0 displ %s\n", SMPcmd.ea, SMPcmd.size, disasm); } else { qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK 0 displ %s\n", SMPcmd.ea, SMPcmd.size, disasm); } } return; } // end of SMPInstr::AnnotateStackConstants() // Emit all annotations for the instruction in the absence of RTL type inference. void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) { ea_t addr = this->address; flags_t InstrFlags = getFlags(addr); bool MemDest = this->HasDestMemoryOperand(); bool MemSrc = this->HasSourceMemoryOperand(); bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags); ++OptCount[OptType]; // keep count for debugging info #if SMP_DEBUG_MEM if (MemDest || MemSrc) { 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 msg("OptType 0: %x %s\n", 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 && this->MDIsPushInstr()) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n", addr, -3, disasm); } else { SDTInstrumentation = true; } break; } case 1: // nothing for SDT to do { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; break; } case 4: // INC, DEC, etc.: no SDT work unless MemDest { if (MemDest || MemSrc) { SDTInstrumentation = true; break; // treat as category 0 } qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n", addr, -1, disasm); ++AnnotationCount[OptType]; break; } case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work. { if (MemDest || MemSrc) { SDTInstrumentation = true; break; // treat as category 0 } if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1 qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; } else { SDTInstrumentation = true; } break; } case 6: // Only OS code should include these; problem for SDT { if (MemDest) { SDTInstrumentation = true; break; // treat as category 0 } qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n", addr, -OptType, disasm); ++AnnotationCount[OptType]; break; } case 8: // Implicitly writes to EDX:EAX, always numeric. { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n", addr, -2, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; 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. msg("Floating point MemDest: %s \n", disasm); #endif SDTInstrumentation = true; break; // treat as category 0 } qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; break; } default: // 2,3,7: Optimization possibilities depend on operands { #if SMP_DEBUG2 if (OptType == 3) { // MOV instr class if (MemDest) { msg("MemDest on MOV: %s\n", disasm); } else if (!SecondSrcOperandNum) { msg("MOV: not 2nd op numeric: %s\n", disasm); this->PrintOperands(); } } #endif SDTInstrumentation = true; if (MemDest) { #if SMP_DEBUG_XOR if (OptType == 2) msg("MemDest on OptType 2: %s\n", disasm); #endif break; // treat as category 0 } if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n", addr, -2, this->DestString(OptType), OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; } break; } } // end switch (OptType) // 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. if (SDTInstrumentation) { this->AnnotateStackConstants(UseFP, AnnotFile); if (strlen(this->DeadRegsString) > 0) { // 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. qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n", addr, this->SMPcmd.size, this->DeadRegsString, disasm); } } 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) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeReturn %s\n", this->address, -4, disasm); } // Emit all annotations for the instruction using RTL type inference. void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) { ea_t addr = this->address; flags_t InstrFlags = getFlags(addr); int TypeGroup = SMPTypeCategory[this->SMPcmd.itype]; bool NumericDEFs = this->AllDefsNumeric(); // all DEFs are NUMERIC or CODEPTR bool MemDest = this->HasDestMemoryOperand(); bool MemSrc = this->HasSourceMemoryOperand(); bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags); ++OptCount[this->OptType]; // keep count for debugging info // Emit appropriate optimization annotations. bool SDTInstrumentation = false; switch (TypeGroup) { case 0: // SDT will have to handle these case 11: // PUSH/POP **!!** What if we push/pop NUMERIC type? Optimize? // mmStrata wants to suppress warnings on the PUSH // instructions that precede the LocalVarsAllocInstr // (i.e. the PUSHes of callee-saved regs). if (!AllocSeen && this->MDIsPushInstr()) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n", addr, -3, disasm); } else { SDTInstrumentation = true; } break; case 1: // nothing for SDT to do case 14: if (MemDest) { msg("ERROR: MemDest in Type Category 1 or 14: %x %s\n", addr, disasm); SDTInstrumentation = true; break; } qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; break; case 4: // INC, DEC, etc.: no SDT work unless MemDest if (MemDest || MemSrc) { // pretty conservative here? SDTInstrumentation = true; break; // treat as category 0 } qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n", addr, -1, disasm); ++AnnotationCount[OptType]; 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 this->SetAddSubSourceType(); if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1 qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; } else if (IsEqType(NUMERIC, this->AddSubSourceType) && !this->MDIsFrameAllocInstr() && (this->SMPcmd.itype != NN_adc) && (this->SMPcmd.itype != NN_sbb)) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL 2ndSrcNumeric %s \n", addr, -1, disasm); ++AnnotationCount[OptType]; } else if (NumericDEFs) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n", addr, -2, this->DestString(OptType), disasm); ++AnnotationCount[OptType]; } else { SDTInstrumentation = true; } break; case 6: // Only OS code should include these; problem for SDT if (MemDest) { SDTInstrumentation = true; break; // treat as category 0 } qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n", addr, -OptType, disasm); ++AnnotationCount[OptType]; break; case 8: // Implicitly writes to EDX:EAX, always numeric. qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n", addr, -2, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; SDTInstrumentation = true; break; case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0) if (MemDest) { SDTInstrumentation = true; #if 0 if (NumericDEFs) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n", addr, -2, this->DestString(OptType), disasm); ++AnnotationCount[OptType]; } #endif } else { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; } 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 qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n", addr, -2, this->DestString(OptType), disasm); ++AnnotationCount[OptType]; } 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 qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[TypeGroup], disasm); ++AnnotationCount[OptType]; } else SDTInstrumentation = true; break; 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 qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr, -1, OptExplanation[TypeGroup], disasm); ++AnnotationCount[OptType]; } break; default: // 2,3,7: Optimization possibilities depend on operands SDTInstrumentation = true; if (MemDest) { break; // treat as category 0 } if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) { qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n", addr, -2, this->DestString(OptType), OptExplanation[OptType], disasm); ++AnnotationCount[OptType]; } else if (NumericDEFs) { // NUMERIC move instruction qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n", addr, -2, this->DestString(OptType), disasm); ++AnnotationCount[OptType]; } break; } // end switch (OptType) // 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. if (SDTInstrumentation) { this->AnnotateStackConstants(UseFP, AnnotFile); if (strlen(this->DeadRegsString) > 0) { // 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. qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n", addr, this->SMPcmd.size, this->DeadRegsString, disasm); } } return; } // end of SMPInstr::EmitTypeAnnotations() // Build the RTL for an instruction with a unary opcode bool SMPInstr::BuildUnaryRTL(SMPoperator UnaryOp) { size_t OpNum; bool DestFound = false; SMPRegTransfer *TempRT = NULL; op_t VoidOp; VoidOp.type = o_void; op_t FPRegOp; FPRegOp.type = o_fpreg; // floating point register stack FPRegOp.reg = 0; op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = 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->SetLeftOperand(FPRegOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetLeftOperand(FPRegOp); RightRT->SetOperator(UnaryOp); RightRT->SetRightOperand(VoidOp); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); } else if ((NN_clc == this->SMPcmd.itype) || (NN_cld == this->SMPcmd.itype) || (NN_cmc == this->SMPcmd.itype) || (NN_stc == this->SMPcmd.itype) || (NN_std == this->SMPcmd.itype)) { // Flags register is implicit destination. DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; if (NN_cmc == this->SMPcmd.itype) { // 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 < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; 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) { msg("ERROR: Could not find unary operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); } #endif return DestFound; } // end of SMPInstr::BuildUnaryRTL() // Build the RTL for an instruction with a binary arithmetic opcode bool SMPInstr::BuildBinaryRTL(SMPoperator BinaryOp) { size_t OpNum; bool DestFound = false; bool SourceFound = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; op_t VoidOp; VoidOp.type = o_void; op_t FPRegOp; FPRegOp.type = o_fpreg; // floating point register stack FPRegOp.reg = 0; // Handle special cases first if (SMP_BINARY_FLOATING_ARITHMETIC == BinaryOp) { // Use of the floating register stack top is implicit DestFound = true; TempRT = new SMPRegTransfer; 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 < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { // See comments just below for floating point sources. FP stores // are analogous to FP loads. if (!MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL msg("WARNING: Skipping DEF operand: "); PrintOperand(TempOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); #endif } } else if (DestFound && (SMP_BINARY_FLOATING_ARITHMETIC != BinaryOp)) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL msg("ERROR: Found two DEF operands: "); PrintOperand(TempOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); #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 || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) { SourceFound = true; RightRT->SetRightOperand(TempOp); } } if (!(this->features & UseMacros[OpNum])) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); #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) { msg("ERROR: Could not find binary DEF operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); } else { msg("ERROR: Could not find binary operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); this->PrintOperands(); } #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound); } // end of SMPInstr::BuildBinaryRTL() // Build the RTL for a load-effective-address instruction. bool SMPInstr::BuildLeaRTL(void) { size_t OpNum; bool DestFound = false; bool SourceFound = false; bool MemSrc = this->HasSourceMemoryOperand(); op_t DefOp; SMPRegTransfer *AssignRT = NULL; int BaseReg; int IndexReg; ushort ScaleFactor; ea_t offset; bool ScaledIndexReg; for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF DefOp = TempOp; DestFound = true; assert(o_reg == DefOp.type); } else { // USE if (!SourceFound && MDKnownOperandType(TempOp)) { if ((TempOp.type >= o_mem) && (TempOp.type <= o_displ)) { SourceFound = true; MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset); } else { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL msg("WARNING: Skipping USE operand: "); PrintOperand(TempOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); #endif } } if (!(this->features & UseMacros[OpNum])) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); #endif } } // end if DEF ... else ... } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { #if SMP_DEBUG_BUILD_RTL if (!DestFound) { msg("ERROR: Could not find lea DEF operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); } else { msg("ERROR: Could not find lea USE operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); 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->SetLeftOperand(DefOp); AssignRT->SetOperator(SMP_ASSIGN); ScaledIndexReg = ((ScaleFactor > 0) && (IndexReg != R_none)); op_t BaseOp, IndexOp, OffsetOp, ScaleOp; BaseOp.type = o_reg; BaseOp.reg = (ushort) BaseReg; IndexOp.type = o_reg; IndexOp.reg = (ushort) IndexReg; OffsetOp.type = o_imm; OffsetOp.value = (uval_t) offset; ScaleOp.type = o_imm; ScaleOp.value = (uval_t) ScaleFactor; if (ScaledIndexReg) { // First, build the subtree to scale the IndexReg. SMPRegTransfer *MultRT = new SMPRegTransfer; 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->SetLeftOperand(OffsetOp); AddOffRT->SetOperator(SMP_ADD); AddOffRT->SetRightTree(MultRT); // Add a BaseReg, if any. if (R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; 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 (R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; 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 (R_none != IndexReg) { SMPRegTransfer *AddOffRT = new SMPRegTransfer; AddOffRT->SetLeftOperand(OffsetOp); AddOffRT->SetOperator(SMP_ADD); AddOffRT->SetRightOperand(IndexOp); // Add BaseReg, if any. if (R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; 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 (R_none != BaseReg) { SMPRegTransfer *AddBaseRT = new SMPRegTransfer; 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? msg("ERROR: No BaseReg, no IndexReg at %x for %s\n", this->address, this->GetDisasm()); AssignRT->SetRightOperand(OffsetOp); } } } // end if nonzero offset else { // no offset if ((R_none == BaseReg) || (R_none == IndexReg)) { msg("WARNING: lea used as move at %x for %s\n", this->address, this->GetDisasm()); if (R_none != BaseReg) AssignRT->SetRightOperand(BaseOp); else { assert(R_none != IndexReg); AssignRT->SetRightOperand(IndexOp); } } else { // we have a BaseReg and an IndexReg, unscaled, no offset SMPRegTransfer *AddBaseRT = new SMPRegTransfer; 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) { size_t OpNum; bool DestFound = false; bool SourceFound = false; bool CountFound = false; SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; SMPRegTransfer *LowerRightRT = new SMPRegTransfer; op_t VoidOp; VoidOp.type = o_void; op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; for (OpNum = 0; !(DestFound && SourceFound && CountFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; 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 msg("ERROR: Could not find double-shift operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #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); } // 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) { size_t OpNum; bool DestFound = false; bool SourceFound = false; bool HiddenEAXUse = false; SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; op_t VoidOp; VoidOp.type = o_void; op_t FPRegOp; FPRegOp.type = o_fpreg; // floating point register stack FPRegOp.reg = 0; op_t Immed1Op; Immed1Op.type = o_imm; // immediate 1 for increment or decrement FPRegOp.value = 1; // Detect the cases in which EDX:EDX is the destination and EAX is a hidden operand. // See detailed comments on the multiply and divide instructions in MDFixupDefUseLists(). for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (!TempOp.showed()) { // hidden operand if (TempOp.is_reg(R_ax)) { // not R_al, so it is not 8 bits // This for always has a hidden use of EDX:EAX HiddenEAXUse = true; } } } for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } } else { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; RightRT->SetRightOperand(TempOp); } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { assert(NULL != RightRT); if (DestFound && (NULL != TempRT)) delete TempRT; else delete RightRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find mul/div operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { this->RTL.push_back(TempRT); if (HiddenEAXUse) { // Need another effect for EDX, which was implicit. // Make a deep copy from existing effect and change EAX dest to EDX. // For divisions, we also change EAX source to EDX. SMPRegTransfer *EDXRT = new SMPRegTransfer; SMPRegTransfer *EDXRightRT = new SMPRegTransfer; op_t EDXOp; EDXRT->SetOperator(SMP_ASSIGN); EDXOp = TempRT->GetLeftOperand(); assert(EDXOp.is_reg(R_ax)); EDXOp.reg = R_dx; EDXRT->SetLeftOperand(EDXOp); op_t SourceOp = RightRT->GetLeftOperand(); if ((NN_div == this->SMPcmd.itype) || (NN_idiv == this->SMPcmd.itype)) { // 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.is_reg(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); } } return (DestFound && SourceFound); } // 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) { size_t OpNum; bool DestFound = false; bool SourceFound = false; SMPRegTransfer *TempRT = NULL; op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; SMPRegTransfer *RightRT = new SMPRegTransfer; SMPRegTransfer *FlagsRightRT = new SMPRegTransfer; for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; 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 msg("ERROR: Could not find binary operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound); } // end of SMPInstr::BuildBinaryPlusFlagsRTL() #define SMP_FIRST_SET_OPCODE NN_seta #define SMP_LAST_SET_OPCODE NN_setz // Build the RTL for an instruction of form dest := unary_operator(source), dest != source bool SMPInstr::BuildUnary2OpndRTL(SMPoperator UnaryOp) { size_t OpNum; bool DestFound = false; bool SourceFound = false; SMPRegTransfer *TempRT = NULL; SMPRegTransfer *RightRT = new SMPRegTransfer; op_t VoidOp; VoidOp.type = o_void; op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; // Handle special cases first. if ((SMP_FIRST_SET_OPCODE <= this->SMPcmd.itype) && (SMP_LAST_SET_OPCODE >= this->SMPcmd.itype)) { // Set instructions implicitly use the flags register. SourceFound = true; RightRT->SetLeftOperand(FlagsOp); } for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetRightOperand(VoidOp); RightRT->SetOperator(UnaryOp); TempRT->SetRightTree(RightRT); } } else { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; RightRT->SetLeftOperand(TempOp); } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { if (!DestFound) delete RightRT; // never linked in to TempRT if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find binary operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { this->RTL.push_back(TempRT); } return (DestFound && SourceFound); } // end of SMPInstr::BuildUnary2OpndRTL() // Build the RTL for an instruction of form dest := source, dest != source bool SMPInstr::BuildMoveRTL(SMPoperator GuardOp) { size_t OpNum; bool DestFound = false; bool SourceFound = false; bool MemSrc = this->HasSourceMemoryOperand(); bool MemDest = this->HasDestMemoryOperand(); bool HasRepeatPrefix = (0 != (this->SMPcmd.auxpref & aux_rep)) || (0 != (this->SMPcmd.auxpref & aux_repne)); SMPRegTransfer *TempRT = new SMPRegTransfer; op_t VoidOp; VoidOp.type = o_void; op_t EAXOp; EAXOp.type = o_reg; EAXOp.reg = R_ax; op_t ALOp; ALOp.type = o_reg; ALOp.reg = R_al; op_t CountOp; CountOp.type = o_reg; CountOp.reg = R_cx; op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; op_t FPRegOp; FPRegOp.type = o_fpreg; // floating point register stack FPRegOp.reg = 0; op_t ZeroOp; ZeroOp.type = o_imm; // immediate zero ZeroOp.value = 0; #if SMP_DEBUG_BUILD_RTL if (MemSrc && MemDest && (NN_movs != this->SMPcmd.itype)) { if (NN_stos != this->SMPcmd.itype) { msg("ERROR: MemDest and MemSrc in move at %x for %s\n", this->GetAddr(), this->GetDisasm()); } else { // IDA incorrectly lists [EDI] as both DEF and USE, because reg EDI // is both DEF and USE. msg("WARNING: MemDest and MemSrc in move at %x for %s\n", this->GetAddr(), this->GetDisasm()); } this->PrintOperands(); } #endif // First, handle special cases with implicit operands if (NN_lahf == this->SMPcmd.itype) { // load AH from flags TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(EAXOp); TempRT->SetRightOperand(FlagsOp); this->RTL.push_back(TempRT); return true; } if (NN_sahf == this->SMPcmd.itype) { // store AH to flags TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(FlagsOp); TempRT->SetRightOperand(EAXOp); this->RTL.push_back(TempRT); return true; } if ((NN_movs == this->SMPcmd.itype) || (NN_stos == this->SMPcmd.itype)) { // The ESI and EDI registers get incremented or decremented, depending // on the direction flag DF, for MOVS; only EDI for STOS. // This is true with or without a repeat prefix. op_t ESIOp, EDIOp; ESIOp.type = o_reg; ESIOp.reg = R_si; EDIOp.type = o_reg; EDIOp.reg = R_di; op_t ESIMemOp, EDIMemOp; // [esi] and [edi] ESIMemOp.type = o_phrase; ESIMemOp.reg = R_si; ESIMemOp.hasSIB = 0; EDIMemOp.type = o_phrase; EDIMemOp.reg = R_di; EDIMemOp.hasSIB = 0; if (NN_movs == this->SMPcmd.itype) { this->RTL.ExtraKills.push_back(ESIOp); this->RTL.ExtraKills.push_back(EDIOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(EDIMemOp); TempRT->SetRightOperand(ESIMemOp); DestFound = true; SourceFound = true; } else { // NN_stos this->RTL.ExtraKills.push_back(EDIOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(EDIMemOp); TempRT->SetRightOperand(ALOp); // default in case we don't find source later DestFound = 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 ((NN_fld == this->SMPcmd.itype) || (NN_fbld == this->SMPcmd.itype) || (NN_fild == this->SMPcmd.itype)) { // Loads implicitly use the floating point stack top as destination. TempRT->SetLeftOperand(FPRegOp); TempRT->SetOperator(SMP_ASSIGN); DestFound = true; } else if ((NN_fst == this->SMPcmd.itype) || (NN_fstp == this->SMPcmd.itype) || (NN_fbstp == this->SMPcmd.itype) || (NN_fist == this->SMPcmd.itype) || (NN_fistp == this->SMPcmd.itype)) { // 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 ((NN_fstp == this->SMPcmd.itype) || (NN_fbstp == this->SMPcmd.itype) || (NN_fistp == this->SMPcmd.itype)) { this->RTL.ExtraKills.push_back(FPRegOp); } } for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (!DestFound && MDKnownOperandType(TempOp)) { // See comments just below for floating point sources. FP stores // are analogous to FP loads. if (!MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) { 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 || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) { SourceFound = true; TempRT->SetRightOperand(TempOp); } } if (this->features & UseMacros[OpNum]) { ; #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE msg("WARNING: Operand neither DEF nor USE: "); PrintOperand(TempOp); msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm()); #endif } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find move operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { // If the move is conditional, set the guard expression. if (SMP_NULL_OPERATOR != GuardOp) { SMPGuard *Guard1 = new SMPGuard; Guard1->SetLeftOperand(FlagsOp); Guard1->SetOperator(GuardOp); Guard1->SetRightOperand(ZeroOp); TempRT->SetGuard(Guard1); 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()); } } this->RTL.push_back(TempRT); // Now, create the repeat prefix effects if (HasRepeatPrefix) { // Must be MOVS or STOS // The repeat causes USE and DEF of ECX as a counter SMPRegTransfer *CounterRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; 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 (DestFound && SourceFound); } // end of SMPInstr::BuildMoveRTL() // Build the RTL for a compare string instruction, possibly with repeat prefix. bool SMPInstr::BuildCompareStringRTL(void) { size_t OpNum; bool Src1Found = false; bool Src2Found = false; bool HasRepeatPrefix = (0 != (this->SMPcmd.auxpref & aux_rep)) || (0 != (this->SMPcmd.auxpref & aux_repne)); op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; op_t CountOp; CountOp.type = o_reg; CountOp.reg = R_cx; op_t VoidOp; VoidOp.type = o_void; SMPRegTransfer *TempRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; 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 (this->features & DefMacros[OpNum]) // DEF msg("CMPS 1st opnd is DEF\n"); else if (this->features & UseMacros[OpNum]) // USE msg("CMPS 1st opnd is USE\n"); else msg("CMPS 1st opnd neither DEF nor USE\n"); } else { Src2Found = true; RightRT->SetRightOperand(TempOp); if (this->features & DefMacros[OpNum]) // DEF msg("CMPS 2nd opnd is DEF\n"); else if (this->features & UseMacros[OpNum]) // USE msg("CMPS 2nd opnd is USE\n"); else msg("CMPS 2nd opnd neither DEF nor USE\n"); } } } // end for (OpNum = 0; ...) if (!Src1Found || !Src2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find CMPS operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { this->RTL.push_back(TempRT); // Now, create the repeat prefix effects if (HasRepeatPrefix) { // The repeat causes USE and DEF of ECX as a counter SMPRegTransfer *CounterRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; 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) { size_t OpNum; bool Src1Found = false; bool Src2Found = false; SMPRegTransfer *TempRT = new SMPRegTransfer; // second effect, src := dest for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (MDKnownOperandType(TempOp)) { if (!Src1Found) { Src1Found = true; TempRT->SetRightOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); #if SMP_VERBOSE_DEBUG_BUILD_RTL if (this->features & DefMacros[OpNum]) // DEF msg("XCHG 1st opnd is DEF\n"); else if (this->features & UseMacros[OpNum]) // USE msg("XCHG 1st opnd is USE\n"); else msg("XCHG 1st opnd neither DEF nor USE\n"); #endif } else { Src2Found = true; TempRT->SetLeftOperand(TempOp); if (this->features & DefMacros[OpNum]) // DEF msg("XCHG 2nd opnd is DEF\n"); else if (this->features & UseMacros[OpNum]) // USE msg("XCHG 2nd opnd is USE\n"); else msg("XCHG 2nd opnd neither DEF nor USE\n"); } } } // end for (OpNum = 0; ...) if (!Src1Found || !Src2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find XCHG operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { // Create the first effect, dest := src SMPRegTransfer *FirstRT = new SMPRegTransfer; 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) { size_t OpNum; bool Src1Found = false; bool Src2Found = false; SMPRegTransfer *TempRT = new SMPRegTransfer; // second effect, src := dest for (OpNum = 0; !(Src1Found && Src2Found) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (MDKnownOperandType(TempOp)) { if (!Src1Found) { Src1Found = true; TempRT->SetRightOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); if (this->features & DefMacros[OpNum]) // DEF msg("XADD 1st opnd is DEF\n"); else if (this->features & UseMacros[OpNum]) // USE msg("XADD 1st opnd is USE\n"); else msg("XADD 1st opnd neither DEF nor USE\n"); } else { Src2Found = true; TempRT->SetLeftOperand(TempOp); if (this->features & DefMacros[OpNum]) // DEF msg("XADD 2nd opnd is DEF\n"); else if (this->features & UseMacros[OpNum]) // USE msg("XADD 2nd opnd is USE\n"); else msg("XADD 2nd opnd neither DEF nor USE\n"); } } } // end for (OpNum = 0; ...) if (!Src1Found || !Src2Found) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find XADD operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { // Create the first effect, dest := dest + src SMPRegTransfer *FirstRT = new SMPRegTransfer; SMPRegTransfer *AddRT = new SMPRegTransfer; 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) { size_t OpNum; bool DestFound = false; bool SourceFound = false; op_t DestOp; op_t SourceOp; SMPRegTransfer *TempRT = new SMPRegTransfer; for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (MDKnownOperandType(TempOp)) { if (this->features & DefMacros[OpNum]) { // DEF if (!DestFound) { DestFound = true; DestOp = TempOp; } else { msg("CMPXCHG has two DEF operands.\n"); } } else if (this->features & UseMacros[OpNum]) { // USE if (!SourceFound) { SourceFound = true; SourceOp = TempOp; } else { msg("CMPXCHG has two USE operands.\n"); } } } } // end for (OpNum = 0; ...) if (!DestFound || !SourceFound) { if (NULL != TempRT) delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find CMPXCHG operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { // Create the first effect, if (dest == EAX) dest := src SMPGuard *Guard1 = new SMPGuard; op_t EAXOp; EAXOp.type = o_reg; EAXOp.reg = R_ax; Guard1->SetLeftOperand(DestOp); Guard1->SetOperator(SMP_EQUAL); Guard1->SetRightOperand(EAXOp); SMPRegTransfer *FirstRT = new SMPRegTransfer; 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 a compare or test instruction with an implicit EFLAGS destination operand bool SMPInstr::BuildFlagsDestBinaryRTL(SMPoperator BinaryOp) { size_t OpNum; bool Source1Found = false; bool Source2Found = false; bool HasRepeatPrefix = (0 != (this->SMPcmd.auxpref & aux_rep)) || (0 != (this->SMPcmd.auxpref & aux_repne)); op_t Src1Op, Src2Op; SMPRegTransfer *TempRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; op_t VoidOp, FlagsOp; VoidOp.type = o_void; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; op_t CountOp; CountOp.type = o_reg; CountOp.reg = R_cx; for (OpNum = 0; !(Source1Found && Source2Found) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Found destination for compare or test at %x : %s\n", this->GetAddr(), this->GetDisasm()); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { if (!Source1Found) { Source1Found = true; Src1Op = TempOp; TempRT->SetLeftOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); RightRT->SetLeftOperand(TempOp); RightRT->SetOperator(BinaryOp); TempRT->SetRightTree(RightRT); } else { Source2Found = true; Src2Op = TempOp; 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. if (!Source1Found || !Source2Found) { if (!Source1Found) delete RightRT; else delete TempRT; #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find CMP/TEST/SCAS operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { this->RTL.push_back(TempRT); // Now, create the repeat prefix effects if (HasRepeatPrefix) { // Must be CMPS or SCAS // The repeat causes USE and DEF of ECX as a counter SMPRegTransfer *CounterRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; 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); } if ((NN_cmps == this->SMPcmd.itype) || (NN_scas == this->SMPcmd.itype)) { // 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. op_t ESIOp, EDIOp; ESIOp.type = o_reg; ESIOp.reg = R_si; EDIOp.type = o_reg; EDIOp.reg = R_di; if (NN_cmps == this->SMPcmd.itype) { this->RTL.ExtraKills.push_back(ESIOp); } this->RTL.ExtraKills.push_back(EDIOp); } } return (Source1Found && Source2Found); } // end of SMPInstr::BuildFlagsDestBinaryRTL() // Build the RTL for a direct or indirect call instruction bool SMPInstr::BuildCallRTL(void) { size_t OpNum; bool SourceFound = false; op_t VoidOp; VoidOp.type = o_void; SMPRegTransfer *TempRT = NULL; for (OpNum = 0; !SourceFound && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Found destination operand for call at %x : %s\n", this->GetAddr(), this->GetDisasm()); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(VoidOp); TempRT->SetOperator(SMP_CALL); TempRT->SetRightOperand(TempOp); } } } // end for (OpNum = 0; ...) if (!SourceFound) { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find CALL operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { this->RTL.push_back(TempRT); } return SourceFound; } // end of SMPInstr::BuildCallRTL() // Build the RTL for a return instruction, with or without extra bytes popped off stack bool SMPInstr::BuildReturnRTL(void) { size_t OpNum; uval_t PopBytes = 4; // default: pop off return address for (OpNum = 0; OpNum < UA_MAXOP; ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Found destination operand for RET at %x : %s\n", this->GetAddr(), this->GetDisasm()); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { if (o_imm == TempOp.type) { PopBytes += TempOp.value; } else { #if SMP_DEBUG_BUILD_RTL if (!(this->IsTailCall())) { msg("ERROR: Found unexpected operand for return at %x : %s\n", this->GetAddr(), this->GetDisasm()); } #endif } } } } // end for (OpNum = 0; ...) this->AddToStackPointer(PopBytes); 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 // 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) // Note that k and n and immediate values so the final expression can be computed. size_t OpNum; uval_t NestingLevel = 0; uval_t AllocBytes = 0; bool AllocFound = false; bool NestingLevelFound = false; op_t StackPointerOp; // ESP StackPointerOp.type = o_reg; StackPointerOp.reg = R_sp; op_t FramePointerOp; // EBP FramePointerOp.type = o_reg; FramePointerOp.reg = R_bp; op_t Immed4Op; // 4 Immed4Op.type = o_imm; Immed4Op.value = 4; Immed4Op.dtyp = dt_dword; op_t SavedEBP; // [ESP-4], location of saved EBP SavedEBP.type = o_displ; SavedEBP.addr = (ea_t) -4; SavedEBP.dtyp = dt_dword; SavedEBP.reg = R_sp; SavedEBP.hasSIB = 0; for (OpNum = 0; !(AllocFound && NestingLevelFound) && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Found destination operand for ENTER at %x : %s\n", this->GetAddr(), this->GetDisasm()); #endif } } else { // USE if (MDKnownOperandType(TempOp)) { if (o_imm == TempOp.type) { if (!AllocFound) { AllocBytes = TempOp.value; AllocFound = true; } else { NestingLevel = TempOp.value; NestingLevelFound = true; } } else { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Found unexpected operand for ENTER at %x : %s\n", this->GetAddr(), this->GetDisasm()); #endif } } } } // end for (OpNum = 0; ...) if (!AllocFound) { #if SMP_DEBUG_BUILD_RTL msg("ERROR: Could not find allocation operand for ENTER at %x : %s\n", this->GetAddr(), this->GetDisasm()); #endif } else { SMPRegTransfer *TempRT = new SMPRegTransfer; // Add first effect: [esp-4] := ebp TempRT->SetLeftOperand(SavedEBP); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(FramePointerOp); this->RTL.push_back(TempRT); TempRT = NULL; // Add second effect: ebp := esp - 4 TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(FramePointerOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetLeftOperand(StackPointerOp); RightRT->SetOperator(SMP_SUBTRACT); RightRT->SetRightOperand(Immed4Op); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); TempRT = NULL; RightRT = NULL; // Add final effect on stack pointer AllocBytes += (4 * NestingLevel); if (0 != NestingLevel) { msg("WARNING: Nested procedures in ENTER instruction at %x : %s\n", this->GetAddr(), this->GetDisasm()); } this->AddToStackPointer(AllocBytes); } return AllocFound; } // end of SMPInstr::BuildEnterRTL() // Build the RTL for an 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 will model these two instructions with three parallel effects: // esp := ebp; ebp := [ebp+0]; esp = esp + 4; // There cannot be two definitions of esp in the list of effects, so we do: // esp := ebp + 4; ebp := [ebp+0] as our two parallel effects op_t StackPointerOp; // ESP StackPointerOp.type = o_reg; StackPointerOp.reg = R_sp; op_t FramePointerOp; // EBP FramePointerOp.type = o_reg; FramePointerOp.reg = R_bp; op_t Immed4Op; // 4 Immed4Op.type = o_imm; Immed4Op.value = 4; Immed4Op.dtyp = dt_dword; op_t SavedEBP; // [EBP+0] SavedEBP.type = o_displ; SavedEBP.addr = 0; SavedEBP.dtyp = dt_dword; SavedEBP.reg = R_bp; SavedEBP.hasSIB = 0; // Build first effect: ESP := EBP + 4 SMPRegTransfer *TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(StackPointerOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetOperator(SMP_ADD); RightRT->SetLeftOperand(FramePointerOp); RightRT->SetRightOperand(Immed4Op); TempRT->SetRightTree(RightRT); this->RTL.push_back(TempRT); TempRT = NULL; RightRT = NULL; // Build second effect: EBP := [EBP+0] TempRT = new SMPRegTransfer; 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) { op_t DestOp; DestOp.type = o_reg; op_t VoidOp; VoidOp.type = o_void; // Create the effect on EDX. SMPRegTransfer *TempRT = new SMPRegTransfer; DestOp.reg = R_dx; TempRT->SetLeftOperand(DestOp); TempRT->SetOperator(SMP_ASSIGN); SMPRegTransfer *RightRT = new SMPRegTransfer; RightRT->SetLeftOperand(VoidOp); 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; DestOp.reg = R_ax; TempRT->SetLeftOperand(DestOp); TempRT->SetOperator(SMP_ASSIGN); RightRT = new SMPRegTransfer; RightRT->SetLeftOperand(VoidOp); 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) { size_t OpNum; bool TargetFound = false; SMPRegTransfer *TempRT = NULL; op_t EIPOp, ZeroOp, FlagsOp; EIPOp.type = o_reg; EIPOp.reg = R_ip; ZeroOp.type = o_imm; ZeroOp.value = 0; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; op_t CountOp; CountOp.type = o_reg; CountOp.reg = R_cx; if (this->IsTailCall()) return this->BuildReturnRTL(); for (OpNum = 0; !TargetFound && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & UseMacros[OpNum]) { // USE if (MDKnownOperandType(TempOp)) { TargetFound = true; TempRT = new SMPRegTransfer; 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 ((NN_jcxz <= this->SMPcmd.itype) && (NN_jrcxz >= this->SMPcmd.itype)) 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) { msg("ERROR: Could not find jump target at %x for %s\n", this->GetAddr(), this->GetDisasm()); } #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(uval_t delta) { SMPRegTransfer *TempRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; op_t StackOp, DeltaOp; StackOp.type = o_reg; StackOp.reg = R_sp; StackOp.addr = 0; StackOp.hasSIB = 0; StackOp.dtyp = dt_dword; DeltaOp.type = o_imm; DeltaOp.value = 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() // Add to the stack pointer to deallocate stack space, e.g. for a pop instruction. void SMPInstr::SubFromStackPointer(uval_t delta) { SMPRegTransfer *TempRT = new SMPRegTransfer; SMPRegTransfer *RightRT = new SMPRegTransfer; op_t StackOp, DeltaOp; StackOp.type = o_reg; StackOp.reg = R_sp; StackOp.addr = 0; StackOp.hasSIB = 0; StackOp.dtyp = dt_dword; DeltaOp.type = o_imm; DeltaOp.value = 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 NN_popfw #define SMP_LAST_POP_FLAGS NN_popfq #define SMP_FIRST_POP_ALL NN_popaw #define SMP_LAST_POP_ALL NN_popaq // Build the RTL for a pop instruction bool SMPInstr::BuildPopRTL(void) { size_t OpNum, OpSize; bool DestFound = false; SMPRegTransfer *TempRT = NULL; op_t StackOp, FlagsOp; StackOp.type = o_displ; StackOp.reg = R_sp; StackOp.addr = 0; // [ESP+0] StackOp.hasSIB = 0; StackOp.dtyp = dt_dword; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; FlagsOp.dtyp = dt_dword; // Handle special cases first. if ((SMP_FIRST_POP_FLAGS <= this->SMPcmd.itype) && (SMP_LAST_POP_FLAGS >= this->SMPcmd.itype)) { TempRT = new SMPRegTransfer; 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(4); return true; } if ((SMP_FIRST_POP_ALL <= this->SMPcmd.itype) && (SMP_LAST_POP_ALL >= this->SMPcmd.itype)) { // 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. op_t RegOp; RegOp.type = o_reg; // EDI comes from [ESP+0] RegOp.reg = R_di; StackOp.addr = 0; // [ESP+0] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // ESI comes from [ESP+4] RegOp.reg = R_si; StackOp.addr = 4; // [ESP+4] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EBP comes from [ESP+8] RegOp.reg = R_bp; StackOp.addr = 8; // [ESP+8] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // Skip over saved ESP at [ESP+12] // EBX comes from [ESP+16] RegOp.reg = R_bx; StackOp.addr = 16; // [ESP+16] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EDX comes from [ESP+20] RegOp.reg = R_dx; StackOp.addr = 20; // [ESP+20] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // ECX comes from [ESP+24] RegOp.reg = R_cx; StackOp.addr = 24; // [ESP+24] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EAX comes from [ESP+28] RegOp.reg = R_ax; StackOp.addr = 28; // [ESP+28] TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->AddToStackPointer(32); return true; } // end for "pop all" instructions // If we reach this point, we have a simple POP instruction. for (OpNum = 0; !DestFound && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & DefMacros[OpNum]) { // DEF if (MDKnownOperandType(TempOp)) { DestFound = true; TempRT = new SMPRegTransfer; TempRT->SetLeftOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); StackOp.dtyp = TempOp.dtyp; // size of transfer TempRT->SetRightOperand(StackOp); this->RTL.push_back(TempRT); // Now create the stack pointer increment effect. OpSize = GetOpDataSize(TempOp); this->AddToStackPointer((uval_t) OpSize); } } } // end for (OpNum = 0; ...) #if SMP_DEBUG_BUILD_RTL if (!DestFound) { msg("ERROR: Could not find pop operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); } #endif return DestFound; } // end of SMPInstr::BuildPopRTL() #define SMP_FIRST_PUSH_FLAGS NN_pushfw #define SMP_LAST_PUSH_FLAGS NN_pushfq #define SMP_FIRST_PUSH_ALL NN_pushaw #define SMP_LAST_PUSH_ALL NN_pushaq // Build the RTL for a push instruction bool SMPInstr::BuildPushRTL(void) { size_t OpNum, OpSize; bool SourceFound = false; SMPRegTransfer *TempRT = NULL; op_t StackOp, FlagsOp; StackOp.type = o_displ; StackOp.reg = R_sp; StackOp.addr = (ea_t) -4; // [ESP-4] StackOp.hasSIB = 0; StackOp.dtyp = dt_dword; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; FlagsOp.dtyp = dt_dword; // Handle special cases first. if ((SMP_FIRST_PUSH_FLAGS <= this->SMPcmd.itype) && (SMP_LAST_PUSH_FLAGS >= this->SMPcmd.itype)) { TempRT = new SMPRegTransfer; TempRT->SetRightOperand(FlagsOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); // Now create the stack pointer increment effect. this->SubFromStackPointer(4); return true; } if ((SMP_FIRST_PUSH_ALL <= this->SMPcmd.itype) && (SMP_LAST_PUSH_ALL >= this->SMPcmd.itype)) { op_t RegOp; RegOp.type = o_reg; // EDI goes to [ESP-32] RegOp.reg = R_di; StackOp.addr = (ea_t) -32; // [ESP-32] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // ESI goes to [ESP-28] RegOp.reg = R_si; StackOp.addr = (ea_t) -28; // [ESP-28] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EBP goes to [ESP-24] RegOp.reg = R_bp; StackOp.addr = (ea_t) -24; // [ESP-24] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // ESP goes to [ESP-20] RegOp.reg = R_sp; StackOp.addr = (ea_t) -20; // [ESP-20] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EBX goes to [ESP-16] RegOp.reg = R_bx; StackOp.addr = (ea_t) -16; // [ESP-16] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EDX goes to [ESP-12] RegOp.reg = R_dx; StackOp.addr = (ea_t) -12; // [ESP-12] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // ECX goes to [ESP-8] RegOp.reg = R_cx; StackOp.addr = (ea_t) -8; // [ESP-8] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // EAX goes to [ESP-4] RegOp.reg = R_ax; StackOp.addr = (ea_t) -4; // [ESP-4] TempRT = new SMPRegTransfer; TempRT->SetRightOperand(RegOp); TempRT->SetOperator(SMP_ASSIGN); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->SubFromStackPointer(32); return true; } // end for "pop all" instructions // If we reach this point, we have a simple PUSH instruction. for (OpNum = 0; !SourceFound && (OpNum < UA_MAXOP); ++OpNum) { op_t TempOp = this->SMPcmd.Operands[OpNum]; if (this->features & UseMacros[OpNum]) { // USE if (MDKnownOperandType(TempOp)) { SourceFound = true; OpSize = GetOpDataSize(TempOp); TempRT = new SMPRegTransfer; TempRT->SetRightOperand(TempOp); TempRT->SetOperator(SMP_ASSIGN); StackOp.dtyp = TempOp.dtyp; // size of transfer StackOp.addr = (ea_t) (-((signed int) OpSize)); TempRT->SetLeftOperand(StackOp); this->RTL.push_back(TempRT); TempRT = NULL; // Now create the stack pointer increment effect. this->SubFromStackPointer((uval_t) OpSize); #if 0 this->RTL.Dump(); #endif } } } // end for (OpNum = 0; ...) #if SMP_DEBUG_BUILD_RTL if (!SourceFound) { msg("ERROR: Could not find push operand at %x for %s\n", this->GetAddr(), this->GetDisasm()); } #endif return SourceFound; } // end of SMPInstr::BuildPushRTL() // Build RTL trees from the SMPcmd info. bool SMPInstr::BuildRTL(void) { op_t FlagsOp; FlagsOp.type = o_reg; FlagsOp.reg = X86_FLAGS_REG; 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->MDIsNop()) { NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; } switch (this->SMPcmd.itype) { case NN_aaa: // ASCII Adjust after Addition case NN_aad: // ASCII Adjust AX before Division case NN_aam: // ASCII Adjust AX after Multiply case NN_aas: // ASCII Adjust AL after Subtraction return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_adc: // Add with Carry return this->BuildBinaryPlusFlagsRTL(SMP_ADD_CARRY); case NN_add: // Add return this->BuildBinaryRTL(SMP_ADD); case NN_and: // Logical AND return this->BuildBinaryRTL(SMP_BITWISE_AND); case NN_arpl: // Adjust RPL Field of Selector case NN_bound: // Check Array Index Against Bounds return false; break; case NN_bsf: // Bit Scan Forward case NN_bsr: // Bit Scan Reverse return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_bt: // Bit Test return this->BuildFlagsDestBinaryRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_btc: // Bit Test and Complement case NN_btr: // Bit Test and Reset case 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 NN_call: // Call Procedure case NN_callfi: // Indirect Call Far Procedure case NN_callni: // Indirect Call Near Procedure return this->BuildCallRTL(); case NN_cbw: // AL -> AX (with sign) case NN_cwde: // AX -> EAX (with sign) case NN_cdqe: // EAX -> RAX (with sign) return this->BuildUnaryRTL(SMP_SIGN_EXTEND); case NN_clc: // Clear Carry Flag case NN_cld: // Clear Direction Flag return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_cli: // Clear Interrupt Flag case 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. NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_cmc: // Complement Carry Flag return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_cmp: // Compare Two Operands return this->BuildFlagsDestBinaryRTL(SMP_S_COMPARE); case NN_cmps: // Compare Strings return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE); case NN_cwd: // AX -> DX:AX (with sign) case NN_cdq: // EAX -> EDX:EAX (with sign) case NN_cqo: // RAX -> RDX:RAX (with sign) return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); case NN_daa: // Decimal Adjust AL after Addition case NN_das: // Decimal Adjust AL after Subtraction return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_dec: // Decrement by 1 return this->BuildUnaryRTL(SMP_DECREMENT); case NN_div: // Unsigned Divide return this->BuildMultiplyDivideRTL(SMP_U_DIVIDE); case NN_enterw: // Make Stack Frame for Procedure Parameters case NN_enter: // Make Stack Frame for Procedure Parameters case NN_enterd: // Make Stack Frame for Procedure Parameters case NN_enterq: // Make Stack Frame for Procedure Parameters return this->BuildEnterRTL(); case NN_hlt: // Halt // Treat as a no-op NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_idiv: // Signed Divide return this->BuildMultiplyDivideRTL(SMP_S_DIVIDE); case NN_imul: // Signed Multiply return this->BuildMultiplyDivideRTL(SMP_S_MULTIPLY); case NN_in: // Input from Port return this->BuildUnary2OpndRTL(SMP_INPUT); case NN_inc: // Increment by 1 return this->BuildUnaryRTL(SMP_INCREMENT); case NN_ins: // Input Byte(s) from Port to String return false; break; case NN_int: // Call to Interrupt Procedure case NN_into: // Call to Interrupt Procedure if Overflow Flag = 1 case NN_int3: // Trap to Debugger return this->BuildCallRTL(); case NN_iretw: // Interrupt Return case NN_iret: // Interrupt Return case NN_iretd: // Interrupt Return (use32) case NN_iretq: // Interrupt Return (use64) return this->BuildReturnRTL(); case NN_ja: // Jump if Above (CF=0 & ZF=0) case NN_jae: // Jump if Above or Equal (CF=0) case NN_jb: // Jump if Below (CF=1) case NN_jbe: // Jump if Below or Equal (CF=1 | ZF=1) case NN_jc: // Jump if Carry (CF=1) return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_jcxz: // Jump if CX is 0 case NN_jecxz: // Jump if ECX is 0 case NN_jrcxz: // Jump if RCX is 0 return this->BuildJumpRTL(SMP_EQUAL); // special case in BuildJumpRTL() case NN_je: // Jump if Equal (ZF=1) return this->BuildJumpRTL(SMP_EQUAL); case NN_jg: // Jump if Greater (ZF=0 & SF=OF) return this->BuildJumpRTL(SMP_GREATER_THAN); case NN_jge: // Jump if Greater or Equal (SF=OF) return this->BuildJumpRTL(SMP_GREATER_EQUAL); case NN_jl: // Jump if Less (SF!=OF) return this->BuildJumpRTL(SMP_LESS_THAN); case NN_jle: // Jump if Less or Equal (ZF=1 | SF!=OF) return this->BuildJumpRTL(SMP_LESS_EQUAL); case NN_jna: // Jump if Not Above (CF=1 | ZF=1) case NN_jnae: // Jump if Not Above or Equal (CF=1) case NN_jnb: // Jump if Not Below (CF=0) case NN_jnbe: // Jump if Not Below or Equal (CF=0 & ZF=0) a.k.a. ja case NN_jnc: // Jump if Not Carry (CF=0) return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_jne: // Jump if Not Equal (ZF=0) return this->BuildJumpRTL(SMP_NOT_EQUAL); case NN_jng: // Jump if Not Greater (ZF=1 | SF!=OF) a.k.a. jle return this->BuildJumpRTL(SMP_LESS_EQUAL); case NN_jnge: // Jump if Not Greater or Equal (SF != OF) ** return this->BuildJumpRTL(SMP_LESS_THAN); case NN_jnl: // Jump if Not Less (SF=OF) a.k.a. jge return this->BuildJumpRTL(SMP_GREATER_EQUAL); case NN_jnle: // Jump if Not Less or Equal (ZF=0 & SF=OF) a.k.a. jg return this->BuildJumpRTL(SMP_GREATER_THAN); case NN_jno: // Jump if Not Overflow (OF=0) case NN_jnp: // Jump if Not Parity (PF=0) case NN_jns: // Jump if Not Sign (SF=0) return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_jnz: // Jump if Not Zero (ZF=0) a.k.a. jne return this->BuildJumpRTL(SMP_NOT_EQUAL); case NN_jo: // Jump if Overflow (OF=1) case NN_jp: // Jump if Parity (PF=1) case NN_jpe: // Jump if Parity Even (PF=1) case NN_jpo: // Jump if Parity Odd (PF=0) case NN_js: // Jump if Sign (SF=1) return this->BuildJumpRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_jz: // Jump if Zero (ZF=1) return this->BuildJumpRTL(SMP_EQUAL); case NN_jmp: // Jump case NN_jmpfi: // Indirect Far Jump case NN_jmpni: // Indirect Near Jump case NN_jmpshort: // Jump Short (not used) return this->BuildJumpRTL(SMP_NULL_OPERATOR); case NN_lahf: // Load Flags into AH Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); case NN_lar: // Load Access Right Byte return false; break; case NN_lea: // Load Effective Address return this->BuildLeaRTL(); case NN_leavew: // High Level Procedure Exit case NN_leave: // High Level Procedure Exit case NN_leaved: // High Level Procedure Exit case NN_leaveq: // High Level Procedure Exit return this->BuildLeaveRTL(); case NN_lgdt: // Load Global Descriptor Table Register case NN_lidt: // Load Interrupt Descriptor Table Register case NN_lgs: // Load Full Pointer to GS:xx case NN_lss: // Load Full Pointer to SS:xx case NN_lds: // Load Full Pointer to DS:xx case NN_les: // Load Full Pointer to ES:xx case NN_lfs: // Load Full Pointer to FS:xx case NN_lldt: // Load Local Descriptor Table Register case NN_lmsw: // Load Machine Status Word case NN_lock: // Assert LOCK# Signal Prefix case NN_lods: // Load String return false; break; case NN_loopw: // Loop while ECX != 0 case NN_loop: // Loop while CX != 0 case NN_loopd: // Loop while ECX != 0 case NN_loopq: // Loop while RCX != 0 case NN_loopwe: // Loop while CX != 0 and ZF=1 case NN_loope: // Loop while rCX != 0 and ZF=1 case NN_loopde: // Loop while ECX != 0 and ZF=1 case NN_loopqe: // Loop while RCX != 0 and ZF=1 case NN_loopwne: // Loop while CX != 0 and ZF=0 case NN_loopne: // Loop while rCX != 0 and ZF=0 case NN_loopdne: // Loop while ECX != 0 and ZF=0 case NN_loopqne: // Loop while RCX != 0 and ZF=0 return false; break; case NN_lsl: // Load Segment Limit case NN_ltr: // Load Task Register return false; break; case NN_mov: // Move Data case NN_movsp: // Move to/from Special Registers case NN_movs: // Move Byte(s) from String to String return this->BuildMoveRTL(SMP_NULL_OPERATOR); case NN_movsx: // Move with Sign-Extend return this->BuildUnary2OpndRTL(SMP_SIGN_EXTEND); case NN_movzx: // Move with Zero-Extend return this->BuildUnary2OpndRTL(SMP_ZERO_EXTEND); case NN_mul: // Unsigned Multiplication of AL or AX return this->BuildMultiplyDivideRTL(SMP_U_MULTIPLY); case NN_neg: // Two's Complement Negation return this->BuildUnaryRTL(SMP_NEGATE); case NN_nop: // No Operation NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_not: // One's Complement Negation return this->BuildUnaryRTL(SMP_BITWISE_NOT); case NN_or: // Logical Inclusive OR return this->BuildBinaryRTL(SMP_BITWISE_OR); case NN_out: // Output to Port return this->BuildBinaryRTL(SMP_OUTPUT); case NN_outs: // Output Byte(s) to Port return false; break; case NN_pop: // Pop a word from the Stack case NN_popaw: // Pop all General Registers case NN_popa: // Pop all General Registers case NN_popad: // Pop all General Registers (use32) case NN_popaq: // Pop all General Registers (use64) case NN_popfw: // Pop Stack into Flags Register case NN_popf: // Pop Stack into Flags Register case NN_popfd: // Pop Stack into Eflags Register case NN_popfq: // Pop Stack into Rflags Register return this->BuildPopRTL(); case NN_push: // Push Operand onto the Stack case NN_pushaw: // Push all General Registers case NN_pusha: // Push all General Registers case NN_pushad: // Push all General Registers (use32) case NN_pushaq: // Push all General Registers (use64) case NN_pushfw: // Push Flags Register onto the Stack case NN_pushf: // Push Flags Register onto the Stack case NN_pushfd: // Push Flags Register onto the Stack (use32) case NN_pushfq: // Push Flags Register onto the Stack (use64) return this->BuildPushRTL(); case NN_rcl: // Rotate Through Carry Left return this->BuildBinaryPlusFlagsRTL(SMP_ROTATE_LEFT_CARRY); case NN_rcr: // Rotate Through Carry Right return this->BuildBinaryPlusFlagsRTL(SMP_ROTATE_RIGHT_CARRY); case NN_rol: // Rotate Left return this->BuildBinaryRTL(SMP_ROTATE_LEFT); case NN_ror: // Rotate Right return this->BuildBinaryRTL(SMP_ROTATE_RIGHT); case NN_rep: // Repeat String Operation case NN_repe: // Repeat String Operation while ZF=1 case NN_repne: // Repeat String Operation while ZF=0 return false; break; case NN_retn: // Return Near from Procedure case NN_retf: // Return Far from Procedure return this->BuildReturnRTL(); case NN_sahf: // Store AH into Flags Register return this->BuildMoveRTL(SMP_NULL_OPERATOR); case NN_sal: // Shift Arithmetic Left return this->BuildBinaryRTL(SMP_S_LEFT_SHIFT); case NN_sar: // Shift Arithmetic Right return this->BuildBinaryRTL(SMP_S_RIGHT_SHIFT); case NN_shl: // Shift Logical Left return this->BuildBinaryRTL(SMP_U_LEFT_SHIFT); case NN_shr: // Shift Logical Right return this->BuildBinaryRTL(SMP_U_RIGHT_SHIFT); case NN_sbb: // Integer Subtraction with Borrow return this->BuildBinaryPlusFlagsRTL(SMP_SUBTRACT_BORROW); case NN_scas: // Compare String return this->BuildBinaryPlusFlagsRTL(SMP_U_COMPARE); case NN_seta: // Set Byte if Above (CF=0 & ZF=0) case NN_setae: // Set Byte if Above or Equal (CF=0) case NN_setb: // Set Byte if Below (CF=1) case NN_setbe: // Set Byte if Below or Equal (CF=1 | ZF=1) case NN_setc: // Set Byte if Carry (CF=1) case NN_sete: // Set Byte if Equal (ZF=1) case NN_setg: // Set Byte if Greater (ZF=0 & SF=OF) case NN_setge: // Set Byte if Greater or Equal (SF=OF) case NN_setl: // Set Byte if Less (SF!=OF) case NN_setle: // Set Byte if Less or Equal (ZF=1 | SF!=OF) case NN_setna: // Set Byte if Not Above (CF=1 | ZF=1) case NN_setnae: // Set Byte if Not Above or Equal (CF=1) case NN_setnb: // Set Byte if Not Below (CF=0) case NN_setnbe: // Set Byte if Not Below or Equal (CF=0 & ZF=0) case NN_setnc: // Set Byte if Not Carry (CF=0) case NN_setne: // Set Byte if Not Equal (ZF=0) case NN_setng: // Set Byte if Not Greater (ZF=1 | SF!=OF) case NN_setnge: // Set Byte if Not Greater or Equal (ZF=1) case NN_setnl: // Set Byte if Not Less (SF=OF) case NN_setnle: // Set Byte if Not Less or Equal (ZF=0 & SF=OF) case NN_setno: // Set Byte if Not Overflow (OF=0) case NN_setnp: // Set Byte if Not Parity (PF=0) case NN_setns: // Set Byte if Not Sign (SF=0) case NN_setnz: // Set Byte if Not Zero (ZF=0) case NN_seto: // Set Byte if Overflow (OF=1) case NN_setp: // Set Byte if Parity (PF=1) case NN_setpe: // Set Byte if Parity Even (PF=1) case NN_setpo: // Set Byte if Parity Odd (PF=0) case NN_sets: // Set Byte if Sign (SF=1) case NN_setz: // Set Byte if Zero (ZF=1) // Destination always get set to NUMERIC 0 or 1, depending on // the condition and the relevant flags bits. Best way to model // this in an RTL is to perform an unspecified unary NUMERIC // operation on the flags register and assign the result to the // destination operand, making it always NUMERIC. return this->BuildUnary2OpndRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_sgdt: // Store Global Descriptor Table Register case NN_sidt: // Store Interrupt Descriptor Table Register return false; break; case NN_shld: // Double Precision Shift Left return this->BuildDoubleShiftRTL(SMP_U_LEFT_SHIFT); case NN_shrd: // Double Precision Shift Right return this->BuildDoubleShiftRTL(SMP_U_RIGHT_SHIFT); case NN_sldt: // Store Local Descriptor Table Register case NN_smsw: // Store Machine Status Word return false; break; case NN_stc: // Set Carry Flag case NN_std: // Set Direction Flag return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_sti: // Set Interrupt Flag NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_stos: // Store String return this->BuildMoveRTL(SMP_NULL_OPERATOR); case NN_str: // Store Task Register return false; break; case NN_sub: // Integer Subtraction return this->BuildBinaryRTL(SMP_SUBTRACT); case NN_test: // Logical Compare return this->BuildFlagsDestBinaryRTL(SMP_U_COMPARE); case NN_verr: // Verify a Segment for Reading case NN_verw: // Verify a Segment for Writing case NN_wait: // Wait until BUSY# Pin is Inactive (HIGH) NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; if (NN_wait != this->SMPcmd.itype) this->RTL.ExtraKills.push_back(FlagsOp); return true; case NN_xchg: // Exchange Register/Memory with Register return this->BuildExchangeRTL(); case NN_xlat: // Table Lookup Translation return false; break; case NN_xor: // Logical Exclusive OR return this->BuildBinaryRTL(SMP_BITWISE_XOR); // // 486 instructions // case NN_cmpxchg: // Compare and Exchange return this->BuildCompareExchangeRTL(); case NN_bswap: // Swap bits in EAX return this->BuildUnaryRTL(SMP_UNARY_NUMERIC_OPERATION); case NN_xadd: // t<-dest; dest<-src+dest; src<-t return this->BuildExchangeAddRTL(); case NN_invd: // Invalidate Data Cache case NN_wbinvd: // Invalidate Data Cache (write changes) case NN_invlpg: // Invalidate TLB entry NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // // Pentium instructions // case NN_rdmsr: // Read Machine Status Register return this->BuildOptType8RTL(); case NN_wrmsr: // Write Machine Status Register return false; break; case NN_cpuid: // Get CPU ID return this->BuildOptType8RTL(); case NN_cmpxchg8b: // Compare and Exchange Eight Bytes return false; break; case NN_rdtsc: // Read Time Stamp Counter return this->BuildOptType8RTL(); case NN_rsm: // Resume from System Management Mode NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // // Pentium Pro instructions // case NN_cmova: // Move if Above (CF=0 & ZF=0) case NN_cmovb: // Move if Below (CF=1) case NN_cmovbe: // Move if Below or Equal (CF=1 | ZF=1) return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_cmovg: // Move if Greater (ZF=0 & SF=OF) return this->BuildMoveRTL(SMP_GREATER_THAN); case NN_cmovge: // Move if Greater or Equal (SF=OF) return this->BuildMoveRTL(SMP_GREATER_EQUAL); case NN_cmovl: // Move if Less (SF!=OF) return this->BuildMoveRTL(SMP_LESS_THAN); case NN_cmovle: // Move if Less or Equal (ZF=1 | SF!=OF) return this->BuildMoveRTL(SMP_LESS_EQUAL); case NN_cmovnb: // Move if Not Below (CF=0) case NN_cmovno: // Move if Not Overflow (OF=0) case NN_cmovnp: // Move if Not Parity (PF=0) case NN_cmovns: // Move if Not Sign (SF=0) return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_cmovnz: // Move if Not Zero (ZF=0) return this->BuildMoveRTL(SMP_NOT_EQUAL); case NN_cmovo: // Move if Overflow (OF=1) case NN_cmovp: // Move if Parity (PF=1) case NN_cmovs: // Move if Sign (SF=1) return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_cmovz: // Move if Zero (ZF=1) return this->BuildMoveRTL(SMP_EQUAL); case NN_fcmovb: // Floating Move if Below return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_fcmove: // Floating Move if Equal return this->BuildMoveRTL(SMP_EQUAL); case NN_fcmovbe: // Floating Move if Below or Equal return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_fcmovu: // Floating Move if Unordered return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_fcmovnb: // Floating Move if Not Below return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_fcmovne: // Floating Move if Not Equal return this->BuildMoveRTL(SMP_NOT_EQUAL); case NN_fcmovnbe: // Floating Move if Not Below or Equal return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_fcmovnu: // Floating Move if Not Unordered return this->BuildMoveRTL(SMP_BINARY_NUMERIC_OPERATION); case NN_fcomi: // FP Compare: result in EFLAGS case NN_fucomi: // FP Unordered Compare: result in EFLAGS case NN_fcomip: // FP Compare: result in EFLAGS: pop stack case NN_fucomip: // FP Unordered Compare: result in EFLAGS: pop stack return false; break; case NN_rdpmc: // Read Performance Monitor Counter return this->BuildOptType8RTL(); // // FPP instructions // case NN_fld: // Load Real case NN_fst: // Store Real case NN_fstp: // Store Real and Pop return this->BuildMoveRTL(SMP_NULL_OPERATOR); case NN_fxch: // Exchange Registers // FP registers remain NUMERIC anyway, so this is a no-op to our type system. NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_fild: // Load Integer case NN_fist: // Store Integer case NN_fistp: // Store Integer and Pop case NN_fbld: // Load BCD case NN_fbstp: // Store BCD and Pop return this->BuildMoveRTL(SMP_NULL_OPERATOR); case NN_fadd: // Add Real case NN_faddp: // Add Real and Pop case NN_fiadd: // Add Integer case NN_fsub: // Subtract Real case NN_fsubp: // Subtract Real and Pop case NN_fisub: // Subtract Integer case NN_fsubr: // Subtract Real Reversed case NN_fsubrp: // Subtract Real Reversed and Pop case NN_fisubr: // Subtract Integer Reversed case NN_fmul: // Multiply Real case NN_fmulp: // Multiply Real and Pop case NN_fimul: // Multiply Integer case NN_fdiv: // Divide Real case NN_fdivp: // Divide Real and Pop case NN_fidiv: // Divide Integer case NN_fdivr: // Divide Real Reversed case NN_fdivrp: // Divide Real Reversed and Pop case NN_fidivr: // Divide Integer Reversed return this->BuildBinaryRTL(SMP_BINARY_FLOATING_ARITHMETIC); case NN_fsqrt: // Square Root case NN_fscale: // Scale: st(0) <- st(0) * 2^st(1) case NN_fprem: // Partial Remainder case NN_frndint: // Round to Integer case NN_fxtract: // Extract exponent and significand case NN_fabs: // Absolute value case NN_fchs: // Change Sign return this->BuildUnaryRTL(SMP_UNARY_FLOATING_ARITHMETIC); case NN_fcom: // Compare Real case NN_fcomp: // Compare Real and Pop case NN_fcompp: // Compare Real and Pop Twice case NN_ficom: // Compare Integer case NN_ficomp: // Compare Integer and Pop case NN_ftst: // Test case 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->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_fptan: // Partial tangent case NN_fpatan: // Partial arctangent case NN_f2xm1: // 2^x - 1 case NN_fyl2x: // Y * lg2(X) case 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 NN_fldz: // Load +0.0 case NN_fld1: // Load +1.0 case NN_fldpi: // Load PI=3.14... case NN_fldl2t: // Load lg2(10) case NN_fldl2e: // Load lg2(e) case NN_fldlg2: // Load lg10(2) case NN_fldln2: // Load ln(2) case NN_finit: // Initialize Processor case NN_fninit: // Initialize Processor (no wait) case NN_fsetpm: // Set Protected Mode case NN_fldcw: // Load Control Word case NN_fstcw: // Store Control Word case NN_fnstcw: // Store Control Word (no wait) case NN_fstsw: // Store Status Word case NN_fnstsw: // Store Status Word (no wait) case NN_fclex: // Clear Exceptions case 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->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_fstenv: // Store Environment case NN_fnstenv: // Store Environment (no wait) case NN_fldenv: // Load Environment case NN_fsave: // Save State case NN_fnsave: // Save State (no wait) case NN_frstor: // Restore State case NN_fincstp: // Increment Stack Pointer case NN_fdecstp: // Decrement Stack Pointer case NN_ffree: // Free Register return false; break; case NN_fnop: // No Operation NopRT = new SMPRegTransfer; NopRT->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; case NN_feni: // (8087 only) case NN_fneni: // (no wait) (8087 only) case NN_fdisi: // (8087 only) case NN_fndisi: // (no wait) (8087 only) return false; break; // // 80387 instructions // case NN_fprem1: // Partial Remainder ( < half ) case NN_fsincos: // t<-cos(st); st<-sin(st); push t case NN_fsin: // Sine case NN_fcos: // Cosine case NN_fucom: // Compare Unordered Real case NN_fucomp: // Compare Unordered Real and Pop case 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->SetOperator(SMP_NULL_OPERATOR); this->RTL.push_back(NopRT); NopRT = NULL; return true; // // Instructions added 28.02.96 // case NN_setalc: // Set AL to Carry Flag case NN_svdc: // Save Register and Descriptor case NN_rsdc: // Restore Register and Descriptor case NN_svldt: // Save LDTR and Descriptor case NN_rsldt: // Restore LDTR and Descriptor case NN_svts: // Save TR and Descriptor case NN_rsts: // Restore TR and Descriptor case NN_icebp: // ICE Break Point case NN_loadall: // Load the entire CPU state from ES:EDI // // MMX instructions // case NN_emms: // Empty MMX state case NN_movd: // Move 32 bits case NN_movq: // Move 64 bits case NN_packsswb: // Pack with Signed Saturation (Word->Byte) case NN_packssdw: // Pack with Signed Saturation (Dword->Word) case NN_packuswb: // Pack with Unsigned Saturation (Word->Byte) case NN_paddb: // Packed Add Byte case NN_paddw: // Packed Add Word case NN_paddd: // Packed Add Dword case NN_paddsb: // Packed Add with Saturation (Byte) case NN_paddsw: // Packed Add with Saturation (Word) case NN_paddusb: // Packed Add Unsigned with Saturation (Byte) case NN_paddusw: // Packed Add Unsigned with Saturation (Word) case NN_pand: // Bitwise Logical And case NN_pandn: // Bitwise Logical And Not case NN_pcmpeqb: // Packed Compare for Equal (Byte) case NN_pcmpeqw: // Packed Compare for Equal (Word) case NN_pcmpeqd: // Packed Compare for Equal (Dword) case NN_pcmpgtb: // Packed Compare for Greater Than (Byte) case NN_pcmpgtw: // Packed Compare for Greater Than (Word) case NN_pcmpgtd: // Packed Compare for Greater Than (Dword) case NN_pmaddwd: // Packed Multiply and Add case NN_pmulhw: // Packed Multiply High case NN_pmullw: // Packed Multiply Low case NN_por: // Bitwise Logical Or case NN_psllw: // Packed Shift Left Logical (Word) case NN_pslld: // Packed Shift Left Logical (Dword) case NN_psllq: // Packed Shift Left Logical (Qword) case NN_psraw: // Packed Shift Right Arithmetic (Word) case NN_psrad: // Packed Shift Right Arithmetic (Dword) case NN_psrlw: // Packed Shift Right Logical (Word) case NN_psrld: // Packed Shift Right Logical (Dword) case NN_psrlq: // Packed Shift Right Logical (Qword) case NN_psubb: // Packed Subtract Byte case NN_psubw: // Packed Subtract Word case NN_psubd: // Packed Subtract Dword case NN_psubsb: // Packed Subtract with Saturation (Byte) case NN_psubsw: // Packed Subtract with Saturation (Word) case NN_psubusb: // Packed Subtract Unsigned with Saturation (Byte) case NN_psubusw: // Packed Subtract Unsigned with Saturation (Word) case NN_punpckhbw: // Unpack High Packed Data (Byte->Word) case NN_punpckhwd: // Unpack High Packed Data (Word->Dword) case NN_punpckhdq: // Unpack High Packed Data (Dword->Qword) case NN_punpcklbw: // Unpack Low Packed Data (Byte->Word) case NN_punpcklwd: // Unpack Low Packed Data (Word->Dword) case NN_punpckldq: // Unpack Low Packed Data (Dword->Qword) case NN_pxor: // Bitwise Logical Exclusive Or // // Undocumented Deschutes processor instructions // case NN_fxsave: // Fast save FP context case NN_fxrstor: // Fast restore FP context // Pentium II instructions case NN_sysenter: // Fast Transition to System Call Entry Point case NN_sysexit: // Fast Transition from System Call Entry Point // 3DNow! instructions case NN_pavgusb: // Packed 8-bit Unsigned Integer Averaging case NN_pfadd: // Packed Floating-Point Addition case NN_pfsub: // Packed Floating-Point Subtraction case NN_pfsubr: // Packed Floating-Point Reverse Subtraction case NN_pfacc: // Packed Floating-Point Accumulate case NN_pfcmpge: // Packed Floating-Point Comparison: Greater or Equal case NN_pfcmpgt: // Packed Floating-Point Comparison: Greater case NN_pfcmpeq: // Packed Floating-Point Comparison: Equal case NN_pfmin: // Packed Floating-Point Minimum case NN_pfmax: // Packed Floating-Point Maximum case NN_pi2fd: // Packed 32-bit Integer to Floating-Point case NN_pf2id: // Packed Floating-Point to 32-bit Integer case NN_pfrcp: // Packed Floating-Point Reciprocal Approximation case NN_pfrsqrt: // Packed Floating-Point Reciprocal Square Root Approximation case NN_pfmul: // Packed Floating-Point Multiplication case NN_pfrcpit1: // Packed Floating-Point Reciprocal First Iteration Step case NN_pfrsqit1: // Packed Floating-Point Reciprocal Square Root First Iteration Step case NN_pfrcpit2: // Packed Floating-Point Reciprocal Second Iteration Step case NN_pmulhrw: // Packed Floating-Point 16-bit Integer Multiply with rounding case NN_femms: // Faster entry/exit of the MMX or floating-point state case NN_prefetch: // Prefetch at least a 32-byte line into L1 data cache case NN_prefetchw: // Prefetch processor cache line into L1 data cache (mark as modified) // Pentium III instructions case NN_addps: // Packed Single-FP Add case NN_addss: // Scalar Single-FP Add case NN_andnps: // Bitwise Logical And Not for Single-FP case NN_andps: // Bitwise Logical And for Single-FP case NN_cmpps: // Packed Single-FP Compare case NN_cmpss: // Scalar Single-FP Compare case NN_comiss: // Scalar Ordered Single-FP Compare and Set EFLAGS case NN_cvtpi2ps: // Packed signed INT32 to Packed Single-FP conversion case NN_cvtps2pi: // Packed Single-FP to Packed INT32 conversion case NN_cvtsi2ss: // Scalar signed INT32 to Single-FP conversion case NN_cvtss2si: // Scalar Single-FP to signed INT32 conversion case NN_cvttps2pi: // Packed Single-FP to Packed INT32 conversion (truncate) case NN_cvttss2si: // Scalar Single-FP to signed INT32 conversion (truncate) case NN_divps: // Packed Single-FP Divide case NN_divss: // Scalar Single-FP Divide case NN_ldmxcsr: // Load Streaming SIMD Extensions Technology Control/Status Register case NN_maxps: // Packed Single-FP Maximum case NN_maxss: // Scalar Single-FP Maximum case NN_minps: // Packed Single-FP Minimum case NN_minss: // Scalar Single-FP Minimum case NN_movaps: // Move Aligned Four Packed Single-FP case NN_movhlps: // Move High to Low Packed Single-FP case NN_movhps: // Move High Packed Single-FP case NN_movlhps: // Move Low to High Packed Single-FP case NN_movlps: // Move Low Packed Single-FP case NN_movmskps: // Move Mask to Register case NN_movss: // Move Scalar Single-FP case NN_movups: // Move Unaligned Four Packed Single-FP case NN_mulps: // Packed Single-FP Multiply case NN_mulss: // Scalar Single-FP Multiply case NN_orps: // Bitwise Logical OR for Single-FP Data case NN_rcpps: // Packed Single-FP Reciprocal case NN_rcpss: // Scalar Single-FP Reciprocal case NN_rsqrtps: // Packed Single-FP Square Root Reciprocal case NN_rsqrtss: // Scalar Single-FP Square Root Reciprocal case NN_shufps: // Shuffle Single-FP case NN_sqrtps: // Packed Single-FP Square Root case NN_sqrtss: // Scalar Single-FP Square Root case NN_stmxcsr: // Store Streaming SIMD Extensions Technology Control/Status Register case NN_subps: // Packed Single-FP Subtract case NN_subss: // Scalar Single-FP Subtract case NN_ucomiss: // Scalar Unordered Single-FP Compare and Set EFLAGS case NN_unpckhps: // Unpack High Packed Single-FP Data case NN_unpcklps: // Unpack Low Packed Single-FP Data case NN_xorps: // Bitwise Logical XOR for Single-FP Data case NN_pavgb: // Packed Average (Byte) case NN_pavgw: // Packed Average (Word) case NN_pextrw: // Extract Word case NN_pinsrw: // Insert Word case NN_pmaxsw: // Packed Signed Integer Word Maximum case NN_pmaxub: // Packed Unsigned Integer Byte Maximum case NN_pminsw: // Packed Signed Integer Word Minimum case NN_pminub: // Packed Unsigned Integer Byte Minimum case NN_pmovmskb: // Move Byte Mask to Integer case NN_pmulhuw: // Packed Multiply High Unsigned case NN_psadbw: // Packed Sum of Absolute Differences case NN_pshufw: // Packed Shuffle Word case NN_maskmovq: // Byte Mask write case NN_movntps: // Move Aligned Four Packed Single-FP Non Temporal case NN_movntq: // Move 64 Bits Non Temporal case NN_prefetcht0: // Prefetch to all cache levels case NN_prefetcht1: // Prefetch to all cache levels case NN_prefetcht2: // Prefetch to L2 cache case NN_prefetchnta: // Prefetch to L1 cache case NN_sfence: // Store Fence // Pentium III Pseudo instructions case NN_cmpeqps: // Packed Single-FP Compare EQ case NN_cmpltps: // Packed Single-FP Compare LT case NN_cmpleps: // Packed Single-FP Compare LE case NN_cmpunordps: // Packed Single-FP Compare UNORD case NN_cmpneqps: // Packed Single-FP Compare NOT EQ case NN_cmpnltps: // Packed Single-FP Compare NOT LT case NN_cmpnleps: // Packed Single-FP Compare NOT LE case NN_cmpordps: // Packed Single-FP Compare ORDERED case NN_cmpeqss: // Scalar Single-FP Compare EQ case NN_cmpltss: // Scalar Single-FP Compare LT case NN_cmpless: // Scalar Single-FP Compare LE case NN_cmpunordss: // Scalar Single-FP Compare UNORD case NN_cmpneqss: // Scalar Single-FP Compare NOT EQ case NN_cmpnltss: // Scalar Single-FP Compare NOT LT case NN_cmpnless: // Scalar Single-FP Compare NOT LE case NN_cmpordss: // Scalar Single-FP Compare ORDERED // AMD K7 instructions case NN_pf2iw: // Packed Floating-Point to Integer with Sign Extend case NN_pfnacc: // Packed Floating-Point Negative Accumulate case NN_pfpnacc: // Packed Floating-Point Mixed Positive-Negative Accumulate case NN_pi2fw: // Packed 16-bit Integer to Floating-Point case NN_pswapd: // Packed Swap Double Word // Undocumented FP instructions (thanks to norbert.juffa@adm.com) case NN_fstp1: // Alias of Store Real and Pop case NN_fcom2: // Alias of Compare Real case NN_fcomp3: // Alias of Compare Real and Pop case NN_fxch4: // Alias of Exchange Registers case NN_fcomp5: // Alias of Compare Real and Pop case NN_ffreep: // Free Register and Pop case NN_fxch7: // Alias of Exchange Registers case NN_fstp8: // Alias of Store Real and Pop case NN_fstp9: // Alias of Store Real and Pop // Pentium 4 instructions case NN_addpd: // Add Packed Double-Precision Floating-Point Values case NN_addsd: // Add Scalar Double-Precision Floating-Point Values case NN_andnpd: // Bitwise Logical AND NOT of Packed Double-Precision Floating-Point Values case NN_andpd: // Bitwise Logical AND of Packed Double-Precision Floating-Point Values case NN_clflush: // Flush Cache Line case NN_cmppd: // Compare Packed Double-Precision Floating-Point Values case NN_cmpsd: // Compare Scalar Double-Precision Floating-Point Values case NN_comisd: // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS case NN_cvtdq2pd: // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values case NN_cvtdq2ps: // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values case NN_cvtpd2dq: // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case NN_cvtpd2pi: // Convert Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case NN_cvtpd2ps: // Convert Packed Double-Precision Floating-Point Values to Packed Single-Precision Floating-Point Values case NN_cvtpi2pd: // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values case NN_cvtps2dq: // Convert Packed Single-Precision Floating-Point Values to Packed Doubleword Integers case NN_cvtps2pd: // Convert Packed Single-Precision Floating-Point Values to Packed Double-Precision Floating-Point Values case NN_cvtsd2si: // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer case NN_cvtsd2ss: // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value case NN_cvtsi2sd: // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value case NN_cvtss2sd: // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value case NN_cvttpd2dq: // Convert With Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case NN_cvttpd2pi: // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers case NN_cvttps2dq: // Convert With Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers case NN_cvttsd2si: // Convert with Truncation Scalar Double-Precision Floating-Point Value to Doubleword Integer case NN_divpd: // Divide Packed Double-Precision Floating-Point Values case NN_divsd: // Divide Scalar Double-Precision Floating-Point Values case NN_lfence: // Load Fence case NN_maskmovdqu: // Store Selected Bytes of Double Quadword case NN_maxpd: // Return Maximum Packed Double-Precision Floating-Point Values case NN_maxsd: // Return Maximum Scalar Double-Precision Floating-Point Value case NN_mfence: // Memory Fence case NN_minpd: // Return Minimum Packed Double-Precision Floating-Point Values case NN_minsd: // Return Minimum Scalar Double-Precision Floating-Point Value case NN_movapd: // Move Aligned Packed Double-Precision Floating-Point Values case NN_movdq2q: // Move Quadword from XMM to MMX Register case NN_movdqa: // Move Aligned Double Quadword case NN_movdqu: // Move Unaligned Double Quadword case NN_movhpd: // Move High Packed Double-Precision Floating-Point Values case NN_movlpd: // Move Low Packed Double-Precision Floating-Point Values case NN_movmskpd: // Extract Packed Double-Precision Floating-Point Sign Mask case NN_movntdq: // Store Double Quadword Using Non-Temporal Hint case NN_movnti: // Store Doubleword Using Non-Temporal Hint case NN_movntpd: // Store Packed Double-Precision Floating-Point Values Using Non-Temporal Hint case NN_movq2dq: // Move Quadword from MMX to XMM Register case NN_movsd: // Move Scalar Double-Precision Floating-Point Values case NN_movupd: // Move Unaligned Packed Double-Precision Floating-Point Values case NN_mulpd: // Multiply Packed Double-Precision Floating-Point Values case NN_mulsd: // Multiply Scalar Double-Precision Floating-Point Values case NN_orpd: // Bitwise Logical OR of Double-Precision Floating-Point Values case NN_paddq: // Add Packed Quadword Integers case NN_pause: // Spin Loop Hint case NN_pmuludq: // Multiply Packed Unsigned Doubleword Integers case NN_pshufd: // Shuffle Packed Doublewords case NN_pshufhw: // Shuffle Packed High Words case NN_pshuflw: // Shuffle Packed Low Words case NN_pslldq: // Shift Double Quadword Left Logical case NN_psrldq: // Shift Double Quadword Right Logical case NN_psubq: // Subtract Packed Quadword Integers case NN_punpckhqdq: // Unpack High Data case NN_punpcklqdq: // Unpack Low Data case NN_shufpd: // Shuffle Packed Double-Precision Floating-Point Values case NN_sqrtpd: // Compute Square Roots of Packed Double-Precision Floating-Point Values case NN_sqrtsd: // Compute Square Rootof Scalar Double-Precision Floating-Point Value case NN_subpd: // Subtract Packed Double-Precision Floating-Point Values case NN_subsd: // Subtract Scalar Double-Precision Floating-Point Values case NN_ucomisd: // Unordered Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS case NN_unpckhpd: // Unpack and Interleave High Packed Double-Precision Floating-Point Values case NN_unpcklpd: // Unpack and Interleave Low Packed Double-Precision Floating-Point Values case NN_xorpd: // Bitwise Logical OR of Double-Precision Floating-Point Values // AMD syscall/sysret instructions case NN_syscall: // Low latency system call case NN_sysret: // Return from system call // AMD64 instructions case NN_swapgs: // Exchange GS base with KernelGSBase MSR // New Pentium instructions (SSE3) case NN_movddup: // Move One Double-FP and Duplicate case NN_movshdup: // Move Packed Single-FP High and Duplicate case NN_movsldup: // Move Packed Single-FP Low and Duplicate // Missing AMD64 instructions case NN_movsxd: // Move with Sign-Extend Doubleword case NN_cmpxchg16b: // Compare and Exchange 16 Bytes // SSE3 instructions case NN_addsubpd: // Add /Sub packed DP FP numbers case NN_addsubps: // Add /Sub packed SP FP numbers case NN_haddpd: // Add horizontally packed DP FP numbers case NN_haddps: // Add horizontally packed SP FP numbers case NN_hsubpd: // Sub horizontally packed DP FP numbers case NN_hsubps: // Sub horizontally packed SP FP numbers case NN_monitor: // Set up a linear address range to be monitored by hardware case NN_mwait: // Wait until write-back store performed within the range specified by the MONITOR instruction case NN_fisttp: // Store ST in intXX (chop) and pop case NN_lddqu: // Load unaligned integer 128-bit // SSSE3 instructions case NN_psignb: // Packed SIGN Byte case NN_psignw: // Packed SIGN Word case NN_psignd: // Packed SIGN Doubleword case NN_pshufb: // Packed Shuffle Bytes case NN_pmulhrsw: // Packed Multiply High with Round and Scale case NN_pmaddubsw: // Multiply and Add Packed Signed and Unsigned Bytes case NN_phsubsw: // Packed Horizontal Subtract and Saturate case NN_phaddsw: // Packed Horizontal Add and Saturate case NN_phaddw: // Packed Horizontal Add Word case NN_phaddd: // Packed Horizontal Add Doubleword case NN_phsubw: // Packed Horizontal Subtract Word case NN_phsubd: // Packed Horizontal Subtract Doubleword case NN_palignr: // Packed Align Right case NN_pabsb: // Packed Absolute Value Byte case NN_pabsw: // Packed Absolute Value Word case NN_pabsd: // Packed Absolute Value Doubleword // VMX instructions case NN_vmcall: // Call to VM Monitor case NN_vmclear: // Clear Virtual Machine Control Structure case NN_vmlaunch: // Launch Virtual Machine case NN_vmresume: // Resume Virtual Machine case NN_vmptrld: // Load Pointer to Virtual Machine Control Structure case NN_vmptrst: // Store Pointer to Virtual Machine Control Structure case NN_vmread: // Read Field from Virtual Machine Control Structure case NN_vmwrite: // Write Field from Virtual Machine Control Structure case NN_vmxoff: // Leave VMX Operation case NN_vmxon: // Enter VMX Operation return false; break; default: msg("ERROR: Unknown instruction opcode at %x : %s\n", this->GetAddr(), this->GetDisasm()); break; } // end switch on opcode return true; } // end SMPInstr::BuildRTL() // Iterate through all reg transfers and call SyncRTLDefUse for each. void SMPInstr::SyncAllRTs(void) { for (size_t index = 0; index < this->RTL.GetCount(); ++index) { this->SyncRTLDefUse(this->RTL.GetRT(index)); } 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) { // The Guard expression and ExtraKills are almost never represented in the DEF and USE // 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. op_t 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 (DebugFlag) { msg("SyncRTLDefUse entered. Dump of USE list:\n"); this->Uses.Dump(); } LeftOp = CurrRT->GetLeftOperand(); if (SMP_ASSIGN == CurrRT->GetOperator()) { assert(o_void != LeftOp.type); assert(o_imm != LeftOp.type); CurrDef = this->Defs.FindRef(LeftOp); if (CurrDef == this->GetLastDef() && !LeftOp.is_reg(R_ip)) { #if SMP_VERBOSE_DEBUG_BUILD_RTL msg("WARNING: DEF not found for SMP_ASSIGN in %s ; added op:", this->GetDisasm()); PrintOperand(LeftOp); msg("\n"); #endif this->Defs.SetRef(LeftOp, CurrRT->GetOperatorType()); } } else { // not SMP_ASSIGN; left operand should be a USE if (o_void != LeftOp.type) { CurrUse = this->Uses.FindRef(LeftOp); if (CurrUse == this->GetLastUse()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE msg("WARNING: USE not found for "); PrintOperand(LeftOp); msg(" in %s ; added\n", this->GetDisasm()); #endif this->Uses.SetRef(LeftOp); } } } if (!CurrRT->HasRightSubTree()) { RightOp = CurrRT->GetRightOperand(); // right operand should be a USE if (o_void != RightOp.type) { CurrUse = this->Uses.FindRef(RightOp); if (CurrUse == this->GetLastUse()) { #if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE msg("WARNING: USE not found for "); PrintOperand(RightOp); msg(" in %s ; added\n", this->GetDisasm()); #endif this->Uses.SetRef(RightOp); } } } else { // recurse into right subtree this->SyncRTLDefUse(CurrRT->GetRightTree()); } return; } // end of SMPInstr::SyncRTLDefUse()