Skip to content
Snippets Groups Projects
SMPInstr.cpp 173 KiB
Newer Older
						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
			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))
#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 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))
#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);
				}
			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
2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000
			}
		}
	} // 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);
		}
		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 (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");
			}
			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;