Skip to content
Snippets Groups Projects
SMPInstr.cpp 197 KiB
Newer Older
	}
	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
			}
		}
	} // 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 (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");
3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847
			}
			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;