Skip to content
Snippets Groups Projects
SMPInstr.cpp 173 KiB
Newer Older
	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
					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;
3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 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

	// 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;

	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->BuildUnary2OpndRTL(SMP_ADDRESS_OF);

		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