Newer
Older
}
// We keep it simple by only trying to propagate one step at a time, from
// the right operand or tree up to the SMP_ASSIGN operator, then from
// the operator to the left (DEF) operand, or from left up to operator
// and down the right, depending on where the existing types are.
if (DebugFlag) {
msg("%x LeftType: %d OperatorType: %d RightType: %d\n", this->address, LeftType,
OperType, RightType);
}
if ((UNINIT == RightType) && (UNINIT == LeftType)) {
// We will only try to solve the right hand side on this iteration.
if (CurrRT->HasRightSubTree()) {
updated |= this->InferOperatorType(CurrRT->GetRightTree());
else if (UNINIT == OperType) {
// UNINIT SMP_ASSIGN operator, but either LeftType or RightType is not UNINIT.
if (UNINIT != RightType) {
// We have to special case conditional moves. Only if both operands
// (the source and the prior value of the potential destination,
// which was added to the USE set by BuildMoveRTL()) agree in type
// can we propagate their common type to the operator and ultimately
// to the DEF.
if ((!this->MDIsConditionalMoveInstr()) || this->Uses.TypesAgreeNoFlags()) {
CurrRT->SetOperatorType(RightType);
updated = true;
}
}
else {
updated = true;
}
break;
}
else if (UNINIT == LeftType) {
// SMP_ASSIGN operator has type, so propagate it.
LeftType = OperType;
CurrDef = this->SetDefType(DefOp, OperType);
// Propagate the new DEF type unless it is an indirect memory access.
// Future: Propagate until re-DEF of addressing register terminates
// the propagation. **!!**
if (!MDIsIndirectMemoryOpnd(DefOp, this->BasicBlock->GetFunc()->UsesFramePointer())) {
clc5q
committed
// Be conservative and only propagate register DEFs and SAFE stack locs.
// We can improve this in the future. **!!**
if ((o_reg == DefOp.type)
|| (FUNC_SAFE == this->BasicBlock->GetFunc()->GetReturnAddressStatus())) {
clc5q
committed
int SSANum = CurrDef->GetSSANum();
if (this->BasicBlock->IsLocalName(DefOp)) {
(void) this->BasicBlock->PropagateLocalDefType(DefOp, LeftType,
clc5q
committed
this->GetAddr(), SSANum);
}
else { // global name
this->BasicBlock->GetFunc()->ResetProcessedBlocks(); // set Processed to false
(void) this->BasicBlock->PropagateGlobalDefType(DefOp, LeftType,
SSANum);
}
}
}
break;
}
else if (UNINIT == RightType) {
// SMP_ASSIGN operator has type, so propagate it.
if (CurrRT->HasRightSubTree()) {
CurrRT->GetRightTree()->SetOperatorType(OperType);
updated = true;
updated |= this->InferOperatorType(CurrRT->GetRightTree());
}
else {
// For conditional moves, propagate to the pseudo-USE of the
// destination register as well as the source operand.
if (this->MDIsConditionalMoveInstr()) {
CurrUse = this->FindUse(DefOp);
assert(CurrUse != this->GetLastUse());
if (UNINIT == CurrUse->GetType())
CurrUse = this->SetUseType(DefOp, OperType);
else if (OperType != CurrUse->GetType()) {
msg("WARNING: Avoiding lattice oscillation from type %d to %d at %x for: ",
CurrUse->GetType(), OperType, this->address);
PrintOperand(CurrUse->GetOp());
msg("\n");
}
}
CurrUse = this->SetUseType(UseOp, OperType);
updated = true;
break;
default:
msg("Unknown operator in %s\n", this->GetDisasm());
break;
} // end switch on operator
return updated;
} // end of SMPInstr::InferOperatorType()
// Handle x86 opcode SIB byte annotations.
void SMPInstr::MDAnnotateSIBStackConstants(FILE *AnnotFile, op_t Opnd, ea_t offset, bool UseFP) {
int BaseReg;
int IndexReg;
ea_t displacement;
ushort ScaleFactor;
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement);
if (BaseReg == R_sp) { // ESP cannot be IndexReg
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
}
else if (UseFP && ((IndexReg == R_bp) || (BaseReg == R_bp))) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, this->disasm);
}
return;
} // end of MDAnnotateSIBStackConstants
// Emit annotations for constants used as ptr offsets from EBP or
// ESP into the stack frame. Only pay attention to EBP-relative
// offsets if EBP is being used as a frame pointer (UseFP == true).
void SMPInstr::AnnotateStackConstants(bool UseFP, FILE *AnnotFile) {
op_t Opnd;
ea_t offset;
int BaseReg;
int IndexReg;
ushort ScaleFactor;
#if 0
if (this->address == 0x80925f4) {
msg("PROBLEM INSTRUCTION: \n");
this->PrintOperands();
}
#endif
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = SMPcmd.Operands[i];
if ((Opnd.type == o_displ) || (Opnd.type == o_phrase))
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, offset);
if (Opnd.type == o_displ) {
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // no SIB
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end if (Opnd.type == o_displ)
else if (Opnd.type == o_phrase) {
offset = 0; // mmStrata thinks [esp] is [esp+0]
if (Opnd.hasSIB) {
MDAnnotateSIBStackConstants(AnnotFile, Opnd, offset, UseFP);
}
else { // Something like [ecx]; is it [esp] or [ebp] ?
if (BaseReg == R_sp) {
// ESP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
qfprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
SMPcmd.ea, SMPcmd.size, offset, disasm);
}
} // end if (Opnd.hasSIB) ... else ...
} // end else if (Opnd.type == o_phrase)
} // end for all operands
// If we move a stack pointer or frame pointer into another register, we
// need to annotate the implicit zero offset, e.g. mov edi,esp == mov edi,esp+0
// and edi is becoming a stack pointer that mmStrata needs to track.
if (this->MDIsStackPointerCopy(UseFP)) {
if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK 0 displ %s\n",
SMPcmd.ea, SMPcmd.size, disasm);
}
else {
qfprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK 0 displ %s\n",
SMPcmd.ea, SMPcmd.size, disasm);
}
}
return;
} // end of SMPInstr::AnnotateStackConstants()
// Emit all annotations for the instruction in the absence of RTL type inference.
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);
++OptCount[OptType]; // keep count for debugging info
#if SMP_DEBUG_MEM
if (MemDest || MemSrc) {
msg("OptType: %d %s", OptType, disasm);
this->PrintOperands();
}
#endif
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
switch (OptType) {
case 0: // SDT will have to handle these
{
#if SMP_DEBUG_TYPE0
msg("OptType 0: %x %s\n", addr, disasm);
#endif
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if (!AllocSeen && this->MDIsPushInstr()) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
addr, -3, disasm);
}
else {
SDTInstrumentation = true;
}
break;
}
case 1: // nothing for SDT to do
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
}
case 4: // INC, DEC, etc.: no SDT work unless MemDest
{ if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
}
case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
{ if (MemDest || MemSrc) {
SDTInstrumentation = true;
break; // treat as category 0
}
clc5q
committed
if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
clc5q
committed
else {
SDTInstrumentation = true;
}
break;
}
case 6: // Only OS code should include these; problem for SDT
{ if (MemDest) {
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
addr, -OptType, disasm);
++AnnotationCount[OptType];
break;
}
case 8: // Implicitly writes to EDX:EAX, always numeric.
{ qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
addr, -2, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
SDTInstrumentation = true;
break;
}
case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0)
{ if (MemDest) {
clc5q
committed
#if SMP_DEBUG2
// MemDest seems to happen too much.
msg("Floating point MemDest: %s \n", disasm);
#endif
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
}
default: // 2,3,7: Optimization possibilities depend on operands
{
#if SMP_DEBUG2
if (OptType == 3) { // MOV instr class
if (MemDest) {
msg("MemDest on MOV: %s\n", disasm);
}
else if (!SecondSrcOperandNum) {
msg("MOV: not 2nd op numeric: %s\n", disasm);
this->PrintOperands();
}
}
#endif
SDTInstrumentation = true;
if (MemDest) {
#if SMP_DEBUG_XOR
if (OptType == 2)
msg("MemDest on OptType 2: %s\n", disasm);
#endif
break; // treat as category 0
}
if ((OptType == 2) || (OptType == 7) || SecondSrcOperandNum) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
addr, -2, this->DestString(OptType),
OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
break;
}
} // end switch (OptType)
// If mmStrata is going to have to deal with the
// instruction, then we can annotate EBP and ESP
// relative constant offsets. If we have emitted
// an annotation of type -1, there is no point
// in telling mmStrata about these constants.
if (SDTInstrumentation) {
this->AnnotateStackConstants(UseFP, AnnotFile);
if (strlen(this->DeadRegsString) > 0) {
// Optimize by informing mmStrata of dead registers. It can avoid saving
// and restoring dead state. This is particularly important for EFLAGS,
// as restoring the flags is a pipeline serializing instruction.
qfprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
addr, this->SMPcmd.size, this->DeadRegsString, disasm);
}
}
return;
} // end of SMPInstr::EmitAnnotations()
/**
* Emits Safe Returns
* Mark the type of the annotation as "-4". Currently the SDT is ignoring this
* annotation.
*/
void SMPInstr::EmitSafeReturn(FILE *AnnotFile)
{
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL SafeReturn %s\n", this->address, -4, disasm);
// Emit all annotations for the instruction using RTL type inference.
void SMPInstr::EmitTypeAnnotations(bool UseFP, bool AllocSeen, FILE *AnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
int TypeGroup = SMPTypeCategory[this->SMPcmd.itype];
bool NumericDEFs = this->AllDefsNumeric(); // all DEFs are NUMERIC or CODEPTR
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandNum = this->IsSecondSrcOperandNumeric(InstrFlags);
++OptCount[this->OptType]; // keep count for debugging info
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
case 0: // SDT will have to handle these
case 11: // PUSH/POP **!!** What if we push/pop NUMERIC type? Optimize?
// mmStrata wants to suppress warnings on the PUSH
// instructions that precede the LocalVarsAllocInstr
// (i.e. the PUSHes of callee-saved regs).
if (!AllocSeen && this->MDIsPushInstr()) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
addr, -3, disasm);
}
else {
SDTInstrumentation = true;
}
break;
case 1: // nothing for SDT to do
case 14:
if (MemDest) {
msg("ERROR: MemDest in Type Category 1 or 14: %x %s\n", addr, disasm);
SDTInstrumentation = true;
break;
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
case 4: // INC, DEC, etc.: no SDT work unless MemDest
if (MemDest || MemSrc) { // pretty conservative here?
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL Always1stSrc %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
break;
case 5: // ADD, etc.: If numeric 2nd src operand, no SDT work.
if (MemDest) {
SDTInstrumentation = true;
break; // treat as category 0
}
#endif
this->SetAddSubSourceType();
if (SecondSrcOperandNum && !this->MDIsFrameAllocInstr()) { // treat as category 1
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
else if (IsEqType(NUMERIC, this->AddSubSourceType)
&& !this->MDIsFrameAllocInstr()
&& (this->SMPcmd.itype != NN_adc)
&& (this->SMPcmd.itype != NN_sbb)) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL 2ndSrcNumeric %s \n",
addr, -1, disasm);
++AnnotationCount[OptType];
}
else if (NumericDEFs) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, -2, this->DestString(OptType), disasm);
++AnnotationCount[OptType];
}
else {
SDTInstrumentation = true;
}
break;
case 6: // Only OS code should include these; problem for SDT
SDTInstrumentation = true;
break; // treat as category 0
}
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
addr, -OptType, disasm);
++AnnotationCount[OptType];
break;
case 8: // Implicitly writes to EDX:EAX, always numeric.
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ZZ %s %s \n",
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
addr, -2, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
SDTInstrumentation = true;
break;
case 9: // Either writes to FP reg (cat. 1) or memory (cat. 0)
if (MemDest) {
SDTInstrumentation = true;
#if 0
if (NumericDEFs) {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, -2, this->DestString(OptType), disasm);
++AnnotationCount[OptType];
}
#endif
}
else {
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
break;
clc5q
committed
case 10: // AND, OR, etc.: If all DEFs have been inferred to be
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
// NUMERIC, then output optimizing annotation.
SDTInstrumentation = true;
if (MemDest) { // **!!** optimize with numeric annotation in future
break; // treat as category 0
}
else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s NumericDEFs %s \n",
addr, -2, this->DestString(OptType), disasm);
++AnnotationCount[OptType];
}
break;
case 12: // Exchange, exchange and add, conditional exchange: All NUMERIC
// sources ==> NUMERIC DEFs, so nothing for mmStrata to do.
if (MemDest) { // **!!** optimize with numeric annotation in future
SDTInstrumentation = true;
break; // treat as category 0
}
else if (NumericDEFs) { // NUMERIC result because of NUMERIC sources
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr,
-1, OptExplanation[TypeGroup], disasm);
++AnnotationCount[OptType];
}
else
SDTInstrumentation = true;
break;
case 15: // Floating point, NUMERIC, possible memory destination.
// If not memory destination, fpreg dest, so nothing for mmStrata to do.
if (MemDest) { // **!!** optimize with numeric annotation in future
SDTInstrumentation = true;
break; // treat as category 0
}
else { // NUMERIC floating register result; these regs are always NUMERIC
qfprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n", addr,
-1, OptExplanation[TypeGroup], disasm);
++AnnotationCount[OptType];
}
break;
default: // 2,3,7: Optimization possibilities depend on operands
SDTInstrumentation = true;
if (MemDest) {
break; // treat as category 0
}
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
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()
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
// 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();
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
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
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
if (!DestFound && MDKnownOperandType(TempOp)) {
// See comments just below for floating point sources. FP stores
// are analogous to FP loads.
if (!MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) {
DestFound = true;
TempRT = new SMPRegTransfer;
TempRT->SetLeftOperand(TempOp);
TempRT->SetOperator(SMP_ASSIGN);
RightRT->SetLeftOperand(TempOp);
RightRT->SetOperator(BinaryOp);
TempRT->SetRightTree(RightRT);
}
else {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
msg("WARNING: Skipping DEF operand: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
}
else if (DestFound && (SMP_BINARY_FLOATING_ARITHMETIC != BinaryOp)) {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
msg("ERROR: Found two DEF operands: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
}
else { // USE
if (!SourceFound && MDKnownOperandType(TempOp)) {
// If this is a floating point instruction with the fpregs listed as
// a USE and a memory operand also listed as a USE, then we want to
// ignore the irrelevant USE of the fpreg stack.
// Note that MemDest AND MemSrc means something like add mem,reg is being
// processed, where the memory operand is both DEF and USE.
if (!MemSrc || MemDest || ((TempOp.type >= o_mem) && (TempOp.type <= o_displ))) {
SourceFound = true;
RightRT->SetRightOperand(TempOp);
}
if (!(this->features & UseMacros[OpNum])) {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
msg("WARNING: Operand neither DEF nor USE: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
} // end if DEF ... else ...
} // end for (OpNum = 0; ...)
if (!DestFound || !SourceFound) {
assert(NULL != RightRT);
if (DestFound && (NULL != TempRT))
else
delete RightRT;
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()
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
// Build the RTL for a load-effective-address instruction.
bool SMPInstr::BuildLeaRTL(void) {
size_t OpNum;
bool DestFound = false;
bool SourceFound = false;
bool MemSrc = this->HasSourceMemoryOperand();
op_t DefOp;
SMPRegTransfer *AssignRT = NULL;
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t offset;
bool ScaledIndexReg;
for (OpNum = 0; !(DestFound && SourceFound) && (OpNum < UA_MAXOP); ++OpNum) {
op_t TempOp = this->SMPcmd.Operands[OpNum];
if (this->features & DefMacros[OpNum]) { // DEF
DefOp = TempOp;
DestFound = true;
assert(o_reg == DefOp.type);
}
else { // USE
if (!SourceFound && MDKnownOperandType(TempOp)) {
if ((TempOp.type >= o_mem) && (TempOp.type <= o_displ)) {
SourceFound = true;
MDExtractAddressFields(TempOp, BaseReg, IndexReg, ScaleFactor, offset);
}
else {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL
msg("WARNING: Skipping USE operand: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
}
if (!(this->features & UseMacros[OpNum])) {
;
#if SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE
msg("WARNING: Operand neither DEF nor USE: ");
PrintOperand(TempOp);
msg(" at %x in %s\n", this->GetAddr(), this->GetDisasm());
#endif
}
} // end if DEF ... else ...
} // end for (OpNum = 0; ...)
if (!DestFound || !SourceFound) {
#if SMP_DEBUG_BUILD_RTL
if (!DestFound) {
msg("ERROR: Could not find lea DEF operand at %x for %s\n", this->GetAddr(),
this->GetDisasm());
}
else {
msg("ERROR: Could not find lea USE operand at %x for %s\n", this->GetAddr(),
this->GetDisasm());
this->PrintOperands();
}
#endif
}
else { // Ready to build the RTL
// We build the RTL down to the right, in reverse order, with any multiplication
// of the index register by a scale factor at the bottom of the RTL tree.
// Note that almost any combination of BaseReg, IndexReg, and offset can be present
// or absent.
AssignRT = new SMPRegTransfer;
AssignRT->SetLeftOperand(DefOp);
AssignRT->SetOperator(SMP_ASSIGN);
ScaledIndexReg = ((ScaleFactor > 0) && (IndexReg != R_none));
op_t BaseOp, IndexOp, OffsetOp, ScaleOp;
BaseOp.type = o_reg;
BaseOp.reg = (ushort) BaseReg;
IndexOp.type = o_reg;
IndexOp.reg = (ushort) IndexReg;
OffsetOp.type = o_imm;
OffsetOp.value = (uval_t) offset;
ScaleOp.type = o_imm;
ScaleOp.value = (uval_t) ScaleFactor;
if (ScaledIndexReg) {
// First, build the subtree to scale the IndexReg.
SMPRegTransfer *MultRT = new SMPRegTransfer;
MultRT->SetLeftOperand(IndexOp);
MultRT->SetOperator(SMP_U_LEFT_SHIFT);
MultRT->SetRightOperand(ScaleOp);
// Now, case on the possibilities for existence of the other address fields.
if (0 != offset) {
// Add the offset to the scaled index subtree.
SMPRegTransfer *AddOffRT = new SMPRegTransfer;
AddOffRT->SetLeftOperand(OffsetOp);
AddOffRT->SetOperator(SMP_ADD);
AddOffRT->SetRightTree(MultRT);
// Add a BaseReg, if any.
if (R_none != BaseReg) {
SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
AddBaseRT->SetLeftOperand(BaseOp);
AddBaseRT->SetOperator(SMP_ADD);
AddBaseRT->SetRightTree(AddOffRT);
// Link into assignment root tree.
AssignRT->SetRightTree(AddBaseRT);
}
else { // no BaseReg
AssignRT->SetRightTree(AddOffRT);
}
} // end if nonzero offset
else { // no offset to add
// Add a BaseReg, if any.
if (R_none != BaseReg) {
SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
AddBaseRT->SetLeftOperand(BaseOp);
AddBaseRT->SetOperator(SMP_ADD);
AddBaseRT->SetRightTree(MultRT);
// Link into assignment root tree.
AssignRT->SetRightTree(AddBaseRT);
}
else { // no BaseReg
AssignRT->SetRightTree(MultRT);
}
}
} // end if ScaleIndexReg
else { // no scaled index register
if (0 != offset) {
if (R_none != IndexReg) {
SMPRegTransfer *AddOffRT = new SMPRegTransfer;
AddOffRT->SetLeftOperand(OffsetOp);
AddOffRT->SetOperator(SMP_ADD);
AddOffRT->SetRightOperand(IndexOp);
// Add BaseReg, if any.
if (R_none != BaseReg) {
SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
AddBaseRT->SetLeftOperand(BaseOp);
AddBaseRT->SetOperator(SMP_ADD);
AddBaseRT->SetRightTree(AddOffRT);
// Link into assignment root tree.
AssignRT->SetRightTree(AddBaseRT);
}
else { // no BaseReg
AssignRT->SetRightTree(AddOffRT);
}
} // end if valid IndexReg
else { // no IndexReg
// Add BaseReg, if any.
if (R_none != BaseReg) {
SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
AddBaseRT->SetLeftOperand(BaseOp);
AddBaseRT->SetOperator(SMP_ADD);
AddBaseRT->SetRightOperand(OffsetOp);
// Link into assignment root tree.
AssignRT->SetRightTree(AddBaseRT);
}
else { // no BaseReg, no IndexReg, just offset?
msg("ERROR: No BaseReg, no IndexReg at %x for %s\n", this->address,
this->GetDisasm());
AssignRT->SetRightOperand(OffsetOp);
}
}
} // end if nonzero offset
else { // no offset
if ((R_none == BaseReg) || (R_none == IndexReg)) {
msg("WARNING: lea used as move at %x for %s\n", this->address,
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
this->GetDisasm());
if (R_none != BaseReg)
AssignRT->SetRightOperand(BaseOp);
else {
assert(R_none != IndexReg);
AssignRT->SetRightOperand(IndexOp);
}
}
else { // we have a BaseReg and an IndexReg, unscaled, no offset
SMPRegTransfer *AddBaseRT = new SMPRegTransfer;
AddBaseRT->SetLeftOperand(BaseOp);
AddBaseRT->SetOperator(SMP_ADD);
AddBaseRT->SetRightOperand(IndexOp);
// Link into assignment root tree.
AssignRT->SetRightTree(AddBaseRT);
}
} // end if nonzero offset ... else ...
} // end if (ScaledIndexReg) ... else ...
this->RTL.push_back(AssignRT);
}
return (DestFound && SourceFound);
} // end of SMPInstr::BuildLeaRTL()
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
// 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);