Newer
Older
/*
* SMPInstr.cpp - <see below>.
*
* Copyright (c) 2000, 2001, 2010 - University of Virginia
*
* This file is part of the Memory Error Detection System (MEDS) infrastructure.
* This file may be used and modified for non-commercial purposes as long as
* all copyright, permission, and nonwarranty notices are preserved.
* Redistribution is prohibited without prior written consent from the University
* of Virginia.
*
* Please contact the authors for restrictions applying to commercial use.
*
* THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: University of Virginia
* e-mail: jwd@virginia.com
* URL : http://www.cs.virginia.edu/
*
* Additional copyrights 2010, 2011 by Zephyr Software LLC
* e-mail: {clc,jwd}@zephyr-software.com
* URL : http://www.zephyr-software.com/
*
//
// SMPInstr.cpp
//
// This module performs the instruction level analyses needed for the
// SMP project (Software Memory Protection).
//
using namespace std;
#include <string>
#include <cstring>
#include <pro.h>
#include <assert.h>
#include <ua.hpp>
#include <ida.hpp>
#include <idp.hpp>
#include <auto.hpp>
#include <bytes.hpp>
#include <funcs.hpp>
#include <intel.hpp>
#include <loader.hpp>
#include <lines.hpp>
#include <name.hpp>
clc5q
committed
#include "SMPDBInterface.h"
#include "SMPStaticAnalyzer.h"
#include "SMPDataFlowAnalysis.h"
#include "SMPInstr.h"
#include "SMPProgram.h"
// Set to 1 for debugging output
#define SMP_DEBUG 1
#define SMP_DEBUG2 0 // verbose
#define SMP_DEBUG_XOR 0
#define SMP_DEBUG_BUILD_RTL 1 // should be left on, serious errors!
#define SMP_VERBOSE_DEBUG_BUILD_RTL 0
#define SMP_VERBOSE_DEBUG_BUILD_RTL_DEF_USE 0
#define SMP_VERBOSE_DEBUG_INFER_TYPES 0
#define STARS_DUMP_FG_INFO 1 // show signedness of DEFs and USEs in dump
#define SMP_CALL_TRASHES_REGS 1 // Add DEFs of caller-saved regs to CALL instructions
#define SMP_BASEREG_POINTER_TYPE 1 // Initialize Base Register USEs to type POINTER?
#define SMP_OPTIMIZE_ADD_TO_NUMERIC 0 // optimizing annotation type -5
#define SMP_IDENTIFY_POINTER_ADDRESS_REG 0 // optimizing annotation POINTER
#define SMP_CHILDACCESS_ALL_CODE 0 // CHILDACCESS annotations for all funcs, or just analyzed funcs?
#define SPECIAL_CASE_CARRY_BORROW 0 // Treat sbb/adc different from sub/add annotations?
#define SMP_BUILD_SPECIAL_ADC_SBB_RTL 0 // Explicit RTL subtree for carry flag?
clc5q
committed
#define SMP_AGGRESSIVE_TYPE_INFERENCE 1 // Shorten iterations by quick propagation in InferOperatorType()
clc5q
committed
#define SMP_ANNOTATE_ALL_MEMORY_OPERANDS 0 // Info annotation for all memory read and write operands?
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1 // More transfer of signedness across instructions
#define STARS_NO_SHIFT_SIGNEDNESS_IN_SCALEFACTOR 1 // unsigned left shift for scale factors is really unknownsign multiply
// Make the CF_CHG1 .. CF_CHG6 and CF_USE1..CF_USE6 macros more usable
// by allowing us to pick them up with an array index.
static ulong DefMacros[UA_MAXOP] = {CF_CHG1, CF_CHG2, CF_CHG3, CF_CHG4, CF_CHG5, CF_CHG6};
static ulong UseMacros[UA_MAXOP] = {CF_USE1, CF_USE2, CF_USE3, CF_USE4, CF_USE5, CF_USE6};
// Text to be printed in each optimizing annotation explaining why
// the annotation was emitted.
static const char *OptExplanation[LAST_TYPE_CATEGORY + 1] =
{ "NoOpt", "NoMetaUpdate", "AlwaysNUM", "NUMVia2ndSrcIMMEDNUM",
"Always1stSrc", "1stSrcVia2ndSrcIMMEDNUM", "AlwaysPtr",
"AlwaysNUM", "AlwaysNUM", "NUMViaFPRegDest", "NumericSources",
"StackMemoryTracking", "NumericSources", "NumericMemDest",
"NeverMemDest", "SafeIfNoIndexing"
static const char *OperatorText[LAST_SMP_OPERATOR + 1] =
{ "SMP_NULL_OPERATOR", "SMP_CALL", "SMP_INPUT", "SMP_OUTPUT", "SMP_ADDRESS_OF",
"SMP_U_LEFT_SHIFT", "SMP_S_LEFT_SHIFT", "SMP_U_RIGHT_SHIFT", "SMP_S_RIGHT_SHIFT",
"SMP_ROTATE_LEFT", "SMP_ROTATE_LEFT_CARRY", "SMP_ROTATE_RIGHT", "SMP_ROTATE_RIGHT_CARRY",
"SMP_DECREMENT", "SMP_INCREMENT",
"SMP_ADD", "SMP_ADD_CARRY", "SMP_SUBTRACT", "SMP_SUBTRACT_BORROW", "SMP_U_MULTIPLY",
"SMP_S_MULTIPLY", "SMP_U_DIVIDE", "SMP_S_DIVIDE", "SMP_U_REMAINDER",
"SMP_SIGN_EXTEND", "SMP_ZERO_EXTEND", "SMP_ASSIGN", "SMP_BITWISE_AND",
"SMP_BITWISE_OR", "SMP_BITWISE_NOT", "SMP_BITWISE_XOR", "SMP_BITWISE_AND_NOT", "SMP_NEGATE",
"SMP_S_COMPARE", "SMP_U_COMPARE", "SMP_GENERAL_COMPARE", "SMP_LESS_THAN", "SMP_GREATER_THAN",
"SMP_LESS_EQUAL", "SMP_GREATER_EQUAL", "SMP_EQUAL", "SMP_NOT_EQUAL",
"SMP_LOGICAL_AND", "SMP_LOGICAL_OR", "SMP_UNARY_NUMERIC_OPERATION",
"SMP_BINARY_NUMERIC_OPERATION", "SMP_SYSTEM_OPERATION",
"SMP_UNARY_FLOATING_ARITHMETIC", "SMP_BINARY_FLOATING_ARITHMETIC",
"SMP_REVERSE_SHIFT_U", "SMP_SHUFFLE", "SMP_COMPARE_EQ_AND_SET",
"SMP_COMPARE_NE_AND_SET", "SMP_COMPARE_GT_AND_SET",
"SMP_COMPARE_GE_AND_SET", "SMP_COMPARE_LT_AND_SET", "SMP_COMPARE_LE_AND_SET",
"SMP_PACK_SIGNED", "SMP_PACK_UNSIGNED",
"SMP_AVERAGE_UNSIGNED", "SMP_MULTIPLY_AND_ADD", "SMP_SUM_OF_DIFFS",
"SMP_MAX_S", "SMP_MAX_U", "SMP_MIN_S", "SMP_MIN_U", "SMP_ABS_VALUE",
"SMP_CONVERT_INT_TO_FP", "SMP_CONVERT_FP_TO_INT", "SMP_CREATE_MASK",
"SMP_INTERLEAVE", "SMP_CONCATENATE", "SMP_EXTRACT_ZERO_EXTEND",
"SMP_ENCRYPTION_OPERATION", "SMP_SIGNAL"
#if 0
// Does the CurrOperator definitely indicate a signed or unsigned operation?
bool OperatorHasSignedness(SMPoperator CurrOperator) {
bool DetectedSignedness;
switch (CurrOperator) {
case SMP_NULL_OPERATOR:
DetectedSignedness = false;
break;
case SMP_CALL: // CALL instruction
DetectedSignedness = true;
break;
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_ADDRESS_OF: // take effective address
case SMP_GENERAL_COMPARE:
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
DetectedSignedness = false;
break;
case SMP_U_LEFT_SHIFT: // unsigned left shift
case SMP_U_RIGHT_SHIFT: // unsigned right shift
case SMP_ROTATE_LEFT:
case SMP_ROTATE_LEFT_CARRY: // rotate left through carry
case SMP_ROTATE_RIGHT:
case SMP_ROTATE_RIGHT_CARRY: // rotate right through carry
case SMP_U_MULTIPLY:
case SMP_U_DIVIDE:
case SMP_U_REMAINDER:
case SMP_ZERO_EXTEND:
case SMP_BITWISE_NOT: // unary operator
case SMP_BITWISE_XOR:
case SMP_BITWISE_AND_NOT:
case SMP_U_COMPARE: // unsigned compare (AND-based)
DetectedSignedness = true;
break;
case SMP_S_LEFT_SHIFT: // signed left shift
case SMP_S_RIGHT_SHIFT: // signed right shift
case SMP_S_MULTIPLY:
case SMP_S_DIVIDE:
case SMP_SIGN_EXTEND:
case SMP_NEGATE: // unary negation
case SMP_S_COMPARE: // signed compare (subtraction-based)
case SMP_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
DetectedSignedness = true;
break;
case SMP_DECREMENT:
case SMP_INCREMENT:
case SMP_ADD:
case SMP_ADD_CARRY: // add with carry
case SMP_SUBTRACT:
case SMP_SUBTRACT_BORROW: // subtract with borrow
case SMP_ASSIGN:
case SMP_BITWISE_AND:
case SMP_BITWISE_OR:
case SMP_EQUAL:
case SMP_NOT_EQUAL:
case SMP_LOGICAL_AND:
case SMP_LOGICAL_OR:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_BINARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
clc5q
committed
case SMP_SIGNAL: // signal or raise exception
DetectedSignedness = false;
break;
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
case SMP_BINARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
DetectedSignedness = true;
break;
case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
case SMP_COMPARE_EQ_AND_SET: // Compare for equality and set fields to all 1's or all 0's
case SMP_COMPARE_NE_AND_SET: // Compare for inequality and set fields to all 1's or all 0's
case SMP_COMPARE_GT_AND_SET: // Compare for greater-than and set fields to all 1's or all 0's
case SMP_COMPARE_GE_AND_SET: // Compare for greater-than-or-equal and set fields to all 1's or all 0's
case SMP_COMPARE_LT_AND_SET: // Compare for less-than and set fields to all 1's or all 0's
case SMP_COMPARE_LE_AND_SET: // Compare for less-than-or-equal and set fields to all 1's or all 0's
case SMP_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision
case SMP_PACK_U: // Pack operands into extended-precision register, unsigned saturation for loss of precision
case SMP_AVERAGE_U: // Average of unsigned operands
case SMP_MULTIPLY_AND_ADD: // multiply and add (or multiply and accumulate)
case SMP_SUM_OF_DIFFS: // sum over two vectors of absolute values of differences of their elements
case SMP_MAX_S: // dest := signed_max(dest, src)
case SMP_MAX_U: // dest := unsigned_max(dest, src)
case SMP_MIN_S: // dest := signed_min(dest, src)
case SMP_MIN_U: // dest := unsigned_min(dest, src)
case SMP_ABSOLUTE_VALUE: // take absolute value
case SMP_CONVERT_INT_TO_FP: // convert integer to floating point
case SMP_CONVERT_FP_TO_INT: // convert floating point to integer
case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
DetectedSignedness = true;
break;
default:
DetectedSignedness = false;
clc5q
committed
SMP_msg("ERROR: Unknown operator in OperatorHasSignedness: %d\n", CurrOperator);
break;
} // end switch on operator
return DetectedSignedness;
} // end of OperatorHasSignedness()
#endif
// *****************************************************************
// Class SMPGuard
// *****************************************************************
// Constructor
SMPGuard::SMPGuard(void) {
this->LeftOperand.type = o_void;
this->RightOperand.type = o_void;
this->GuardOp = SMP_NULL_OPERATOR;
clc5q
committed
void SMPGuard::Dump(void) const {
clc5q
committed
SMP_msg("GUARD: ");
clc5q
committed
SMP_msg(" %s ", OperatorText[this->GuardOp]);
clc5q
committed
SMP_msg(":");
return;
} // end of SMPGuard::Dump()
// *****************************************************************
// Class SMPRegTransfer
// *****************************************************************
SMPRegTransfer::SMPRegTransfer(void) {
this->Guard = NULL;
this->LeftOperand.type = o_void;
this->RightOperand.type = o_void;
this->RTop.oper = SMP_NULL_OPERATOR;
this->RTop.NonSpeculativeType = UNINIT;
this->ParentInst = NULL;
return;
}
// Destructor
SMPRegTransfer::~SMPRegTransfer() {
#if 0
clc5q
committed
SMP_msg("Destroying SMPRegTransfer.\n");
#endif
if (NULL != this->RightRT)
delete this->RightRT;
if (NULL != this->Guard)
delete this->Guard;
return;
}
// Get the left operand, and normalize it if it is a stack operand.
op_t SMPRegTransfer::GetLeftOperand(void) const {
op_t TempOp = this->LeftOperand;
// AreDefsNormalized and AreUsesNormalized should always agree, but we
// use Defs for left operands and Uses for right operands, which is not
// strictly true, but there is no difference in results.
if (this->ParentInst->AreDefsNormalized()) {
ea_t InstAddr = this->ParentInst->GetAddr();
TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
}
return TempOp;
} // end of SMPRegTransfer::GetLeftOperand()
// Get the right operand, and normalize it if it is a stack operand.
op_t SMPRegTransfer::GetRightOperand(void) const {
op_t TempOp = this->RightOperand;
if (this->ParentInst->AreDefsNormalized()) {
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
ea_t InstAddr = this->ParentInst->GetAddr();
TempOp = this->ParentInst->GetBlock()->GetFunc()->GetNormalizedOperand(InstAddr, TempOp);
}
return TempOp;
} // end of SMPRegTransfer::GetRightOperand()
// Does RTL subtract a non-immediate value from the stack pointer?
bool SMPRegTransfer::IsAllocaRTL(void) {
bool AllocaFound = false;
// Search for the pattern: stack_pointer := stack_pointer minus non-immediate
if ((SMP_ASSIGN == this->GetOperator()) && (this->HasRightSubTree())) {
op_t DefOp = this->GetLeftOperand();
if (DefOp.is_reg(MD_STACK_POINTER_REG)) {
// We have the code pattern stack_pointer := ...
SMPRegTransfer *RightRT = this->GetRightTree();
SMPoperator RightOperator = RightRT->GetOperator();
op_t RightDefOp = RightRT->GetLeftOperand();
if ((RightDefOp.is_reg(MD_STACK_POINTER_REG)) && (SMP_SUBTRACT == RightOperator)) {
// We have the code pattern stack_pointer := stack_pointer minus ...
if (RightRT->HasRightSubTree()) {
AllocaFound = true; // not an immediate rightop, whatever it is
}
else {
op_t RightUseOp = RightRT->GetRightOperand();
if (o_imm != RightUseOp.type) {
AllocaFound = true;
}
}
}
}
}
return AllocaFound;
} // end of SMPRegTransfer::IsAllocaRTL()
// Compute operand-dependent change in stack pointer value.
clc5q
committed
sval_t SMPRegTransfer::ComputeStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
sval_t delta = 0;
// Search for the pattern: stack_pointer := ...
if (SMP_ASSIGN == this->GetOperator()) {
op_t DefOp = this->GetLeftOperand();
if (DefOp.is_reg(MD_STACK_POINTER_REG)) {
// We have the code pattern stack_pointer := ...
// We expect to find an overall RT structure of:
// stack_pointer := stack_pointer binaryoperator constant
// If the binaryoperator is addition or subtraction, then
// we use the constant to determine our return value.
// If the binaryoperator is a bitwise AND, then we return
// a special code. Delta is unknown but can probably be treated
// as zero, assuming that no stack-pointer-relative accesses to
// the stack region above the current stack pointer occur later.
// If we have a non-constant operand, we return an error code
// to indicate that we cannot compute the delta.
// If we don't have a binary operator, we return an error code,
// unless we find a stack frame deallocation: esp := ebp
if (!this->HasRightSubTree()) {
op_t UseOp = this->GetRightOperand();
clc5q
committed
if (UseOp.is_reg(MD_FRAME_POINTER_REG)) { // !!!!****!!!! Should validate that frame pointer reg is used as frame pointer
// Found esp := ebp (deallocation of stack frame)
clc5q
committed
delta = FramePtrDelta - IncomingDelta;
assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
clc5q
committed
// !!!!****!!!!**** Need to look up deltas for registers that
// were used to hold a copy of the stack pointer.
// For now, just consider it an error.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
else {
SMPRegTransfer *RightRT = this->GetRightTree();
SMPoperator RightOperator = RightRT->GetOperator();
op_t RightDefOp = RightRT->GetLeftOperand();
if (IsLeaveInstr) {
// Found the RT esp := ebp + wordsize that adjusts the stack pointer
// for an x86 LEAVE instruction. esp := ebp is equivalent
clc5q
committed
// to esp := <esp when frame ptr was set up>, so delta becomes
// <esp delta when frame ptr was set up> - IncomingDelta + wordsize.
assert(SMP_ADD == RightOperator);
assert(!RightRT->HasRightSubTree());
assert(RightDefOp.is_reg(X86_FRAME_POINTER_REG));
delta = STARS_ISA_Bytewidth + FramePtrDelta - IncomingDelta;
clc5q
committed
else if (RightRT->HasRightSubTree()) {
// Not the right code pattern; unknown effect on stack pointer.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
clc5q
committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
else if (!RightDefOp.is_reg(MD_STACK_POINTER_REG)) {
// We have stack_pointer := something1 operator something2
// where something1 is not the stack_pointer. It might be
// the frame pointer, e.g. SP := FP-12. We can compute this
// stack delta because we know the delta when the FP was set up.
op_t RightUseOp = RightRT->GetRightOperand();
if (RightDefOp.is_reg(MD_FRAME_POINTER_REG) && (o_imm == RightUseOp.type)) {
// We have SP := FP operator immediate
delta = FramePtrDelta - IncomingDelta; // partial computation: SP := BP
assert(delta >= 0); // e.g. -4 - -12 => +8 for an 8-byte frame
if (SMP_ADD == RightOperator) {
delta += RightUseOp.value;
}
else if (SMP_SUBTRACT == RightOperator) {
delta -= RightUseOp.value;
}
else {
// Not the right code pattern; unknown effect on stack pointer.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
else {
// !!!!****!!!!**** Need to look up deltas for registers that
// were used to hold a copy of the stack pointer.
// For now, just consider it an error.
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
else {
// We have stack_pointer := stack_pointer operator ...
op_t RightUseOp = RightRT->GetRightOperand();
// Check the operator
if (SMP_BITWISE_AND == RightOperator) {
delta = (sval_t) SMP_STACK_POINTER_BITWISE_AND_CODE;
}
else {
if (o_imm != RightUseOp.type) {
// Don't know how to deal with adding non-constant to stack pointer
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
else if (SMP_ADD == RightOperator) {
delta = (sval_t) RightUseOp.value;
}
else if (SMP_SUBTRACT == RightOperator) {
delta = (0 - ((sval_t) RightUseOp.value));
}
else {
delta = (sval_t) SMP_STACK_DELTA_ERROR_CODE;
}
}
}
}
}
}
return delta;
} // end of SMPRegTransfer::ComputeStackPointerAlteration()
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
// Evaluate constant expressions for SCCP algorithm
struct STARS_SCCP_Const_Struct SMPRegTransfer::SCCPEvaluateRTLConsts(list<pair<int, int> > &SSAWorkList) {
struct STARS_SCCP_Const_Struct ReturnConstStruct;
ReturnConstStruct.ConstType = STARS_CONST_TOP; // default value
SMPoperator CurrOper = this->GetOperator();
switch (CurrOper) {
case SMP_ASSIGN:
{
op_t LeftOp = this->GetLeftOperand();
if (o_reg != LeftOp.type) {
break; // Only looking to update registers now
}
bool NewValueAvailable;
if (this->HasRightSubTree()) {
ReturnConstStruct = this->GetRightTree()->SCCPEvaluateRTLConsts(SSAWorkList); // recurse into right subtree
}
else {
op_t RightOp = this->GetRightOperand();
this->ParentInst->SCCPFetchConstUseValue(RightOp, ReturnConstStruct);
}
NewValueAvailable = (STARS_CONST_TOP != ReturnConstStruct.ConstType);
// Update const map entry for DEF
if (NewValueAvailable) {
CanonicalizeOpnd(LeftOp);
struct STARS_SCCP_Const_Struct OldConstStruct;
OldConstStruct.ConstType = STARS_CONST_TOP;
set<DefOrUse, LessDefUse>::iterator DefIter = this->ParentInst->FindDef(LeftOp);
if (DefIter != this->ParentInst->GetLastDef()) {
int DefSSANum = DefIter->GetSSANum();
int DefHashValue = HashGlobalNameAndSSA(LeftOp, DefSSANum);
bool LocalName = this->ParentInst->GetBlock()->IsLocalName(LeftOp);
this->ParentInst->SCCPFetchConstDefValue(LeftOp, OldConstStruct);
bool HasOldValue = (STARS_CONST_TOP != OldConstStruct.ConstType);
if (HasOldValue) { // must perform type lattice meet operation to update ReturnConstStruct
STARSConstantTypeMeet(OldConstStruct, ReturnConstStruct);
}
if (ReturnConstStruct.ConstType != OldConstStruct.ConstType) { // type change
map<int, struct STARS_SCCP_Const_Struct>::iterator NewConstIter;
if (LocalName) {
NewConstIter = this->ParentInst->GetBlock()->InsertLocalConstValue(DefHashValue, ReturnConstStruct);
}
else {
NewConstIter = this->ParentInst->GetBlock()->GetFunc()->InsertGlobalConstValue(DefHashValue, ReturnConstStruct);
}
// Propagate along SSA edges.
int BlockNum = this->ParentInst->GetBlock()->GetNumber();
pair<int, int> SSAEdge(BlockNum, DefHashValue);
SSAWorkList.push_back(SSAEdge);
}
}
}
break; // end case for SMP_ASSIGN
}
case SMP_ADD:
case SMP_SUBTRACT:
case SMP_U_MULTIPLY:
case SMP_S_MULTIPLY:
case SMP_BITWISE_AND:
case SMP_BITWISE_OR:
case SMP_BITWISE_XOR:
case SMP_BITWISE_AND_NOT:
case SMP_S_COMPARE:
case SMP_U_COMPARE:
// binary arithmetic operators
// We will initially deal with the simple case: The comparison is of a LeftOp register to a RightOp register or immediate.
// If the result is definitely zero, we return zero as the const value (presumably to be put into the zero flag).
if (!(this->HasRightSubTree())) { // simple compare of two operands should always be the case
op_t LeftOp = this->GetLeftOperand();
op_t RightOp = this->GetRightOperand();
if ((LeftOp.type == o_reg) && ((RightOp.type == o_reg) || (RightOp.type == o_imm))) {
CanonicalizeOpnd(LeftOp);
CanonicalizeOpnd(RightOp);
struct STARS_SCCP_Const_Struct LeftValue, RightValue;
this->ParentInst->SCCPFetchConstUseValue(LeftOp, LeftValue);
bool LeftValueAvailable = (STARS_CONST_TOP != LeftValue.ConstType);
if (STARS_CONST_BOTTOM == LeftValue.ConstType) {
ReturnConstStruct = LeftValue;
break; // right operand is irrelevant if left is BOTTOM
}
bool RightValueAvailable = false;
if (o_imm == RightOp.type) {
RightValueAvailable = true;
RightValue.ConstType = STARS_CONST_HAS_VALUE;
RightValue.ConstValue = RightOp.value;
}
else {
this->ParentInst->SCCPFetchConstUseValue(RightOp, RightValue);
RightValueAvailable = (STARS_CONST_TOP != RightValue.ConstType);
if (STARS_CONST_BOTTOM == RightValue.ConstType) {
ReturnConstStruct = RightValue;
break; // left operand is irrelevant if right is BOTTOM
}
}
if (LeftValueAvailable && RightValueAvailable) {
// Apply the operator to the values.
ReturnConstStruct.ConstType = STARS_CONST_HAS_VALUE;
uval_t TestValue;
bool CompareFlag = ((CurrOper == SMP_S_COMPARE) || (CurrOper == SMP_U_COMPARE));
if (CurrOper == SMP_ADD) {
TestValue = (LeftValue.ConstValue + RightValue.ConstValue);
}
else if ((CurrOper == SMP_U_MULTIPLY) || (CurrOper == SMP_S_MULTIPLY)) {
TestValue = (LeftValue.ConstValue * RightValue.ConstValue);
}
else if ((CurrOper == SMP_SUBTRACT) || (CurrOper == SMP_S_COMPARE)) {
// Signed compare is a subtraction operation
TestValue = (LeftValue.ConstValue - RightValue.ConstValue);
}
else if ((CurrOper == SMP_U_COMPARE) || (CurrOper == SMP_BITWISE_AND)) {
// Unsigned compare is a bitwise AND operation
TestValue = (LeftValue.ConstValue & RightValue.ConstValue);
}
else if (CurrOper == SMP_BITWISE_OR) {
TestValue = (LeftValue.ConstValue | RightValue.ConstValue);
}
else if (CurrOper == SMP_BITWISE_XOR) {
TestValue = (LeftValue.ConstValue ^ RightValue.ConstValue);
}
else if (CurrOper == SMP_BITWISE_AND_NOT) {
TestValue = (LeftValue.ConstValue & (~(RightValue.ConstValue)));
}
else {
break; // should be unreachable
}
if ((0 != TestValue) && CompareFlag) {
TestValue = 1; // i.e. zero flag will be set to false
}
ReturnConstStruct.ConstValue = TestValue;
}
} // end if two regs, or one reg and one immediate
} // end if no right subtree
break; // end of signed and unsigned compare operators case
default:
break; // ignore
} // end switch(CurrOper)
return ReturnConstStruct;
} // end of SMPRegTransfer::SCCPEvaluateRTLConsts()
clc5q
committed
void SMPRegTransfer::Dump(void) const {
if (NULL != this->Guard)
this->Guard->Dump();
// Left operand
if (o_void != this->LeftOperand.type)
PrintOperand(this->LeftOperand);
// Then the operator
clc5q
committed
SMP_msg(" %s ", OperatorText[this->GetOperator()]);
// then the right operand or subtree
if (this->HasRightSubTree())
this->GetRightTree()->Dump();
else if (o_void != this->RightOperand.type)
PrintOperand(this->RightOperand);
return;
}
// *****************************************************************
// Class SMPRTL
// *****************************************************************
// Constructor
SMPRTL::SMPRTL() {
this->ExtraKills.clear();
this->RTCount = 0;
return;
}
// Destructor
SMPRTL::~SMPRTL() {
for (size_t index = 0; index < this->RTCount; ++index) {
delete (this->RTvector[index]);
}
this->ExtraKills.clear();
return;
}
// Get methods
clc5q
committed
SMPRegTransfer *SMPRTL::GetRT(size_t index) const {
if (index > this->RTCount)
return NULL;
else
return this->RTvector[index];
}
// Set methods
void SMPRTL::push_back(SMPRegTransfer *NewEffect) {
assert(SMP_RT_LIMIT > this->RTCount);
this->RTvector[this->RTCount] = NewEffect;
++(this->RTCount);
return;
}
clc5q
committed
void SMPRTL::Dump(void) const {
size_t index;
if (0 < this->RTCount) {
clc5q
committed
SMP_msg("RTL: ");
for (index = 0; index < this->RTCount; ++index) {
this->RTvector[index]->Dump();
}
for (index = 0; index < this->ExtraKills.size(); ++index) {
clc5q
committed
SMP_msg(" KILL: ");
PrintOperand(this->ExtraKills.at(index));
}
clc5q
committed
SMP_msg("\n");
}
return;
} // end of SMPRTL::Dump()
// Accumulate stack pointer alteration total across all RTs.
clc5q
committed
sval_t SMPRTL::TotalStackPointerAlteration(bool IsLeaveInstr, sval_t IncomingDelta, sval_t FramePtrDelta) {
sval_t TotalDelta = 0;
sval_t IncrementalDelta;
for (size_t index = 0; index < this->RTCount; ++index) {
clc5q
committed
IncrementalDelta = this->RTvector[index]->ComputeStackPointerAlteration(IsLeaveInstr, IncomingDelta, FramePtrDelta);
if ((SMP_STACK_DELTA_ERROR_CODE == IncrementalDelta)
|| (SMP_STACK_POINTER_BITWISE_AND_CODE == IncrementalDelta)) {
TotalDelta = IncrementalDelta; // pass code back
break; // exit loop and return coded value
}
else {
TotalDelta += IncrementalDelta;
}
}
return TotalDelta;
} // end of SMPRTL::TotalStackPointerAlteration()
// *****************************************************************
// Class SMPInstr
// *****************************************************************
// Constructor for instruction.
SMPInstr::SMPInstr(ea_t addr) {
this->ResetGoodRTL();
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
this->ResetJumpTarget();
this->ResetBlockTerm();
this->ResetTailCall();
this->ResetCondTailCall();
this->ResetCallUsedAsJump();
this->ResetDirectRecursiveCall();
this->ResetInterrupt();
#else
this->booleans1 = 0;
#endif
#if 0
this->ResetNop();
this->ResetRegClearIdiom();
this->ResetDefsFlags();
this->ResetUsesFlags();
this->ResetFarBranchComputed();
this->ResetBranchesToFarChunk();
this->ResetIndirectMemWrite();
this->ResetIndirectMemRead();
#else
this->booleans2 = 0;
#endif
#if 0
this->ResetLoadFromStack();
this->ResetMultiplicationBitsDiscarded();
this->ResetTypeInferenceComplete();
this->ResetCategoryInferenceComplete();
this->ResetDEFsTyped();
this->ResetUSEsTyped();
#else
this->booleans3 = 0;
#endif
this->booleans4 = 0;
this->CallTarget = BADADDR;
this->AddSubSourceType = UNINIT;
this->AddSubUseType = UNINIT;
clc5q
committed
this->AddSubSourceOp = InitOp;
this->AddSubUseOp = InitOp;
this->DEFMemOp = InitOp;
this->USEMemOp = InitOp;
this->MoveSource = InitOp;
this->BasicBlock = NULL;
clc5q
committed
this->features = 0;
this->StackPtrOffset = 0;
clc5q
committed
this->type = DEFAULT;
this->OptType = 0;
this->Defs.clear();
this->Uses.clear();
clc5q
committed
// Destructor.
clc5q
committed
SMPInstr::~SMPInstr() {
this->Defs.clear();
this->Uses.clear();
clc5q
committed
return;
clc5q
committed
}
char *SMPInstr::GetDisasm(void) const {
return DisAsmText.GetDisAsm(this->GetAddr());
}
// Is the instruction the type that terminates a basic block?
bool SMPInstr::IsBasicBlockTerminator() const {
return ((type == JUMP) || (type == COND_BRANCH)
|| (type == INDIR_JUMP) || (type == RETURN));
}
// Get non-flags DEF, usually for arithmetic opcode.
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetFirstNonFlagsDef(void) {
set<DefOrUse, LessDefUse>::iterator DefIter;
op_t DefOp;
for (DefIter = this->GetFirstDef(); DefIter != this->GetLastDef(); ++DefIter) {
DefOp = DefIter->GetOp();
if (!((o_reg == DefOp.type) && DefOp.is_reg(MD_FLAGS_REG)))
break; // found a non-flags-reg DEF.
}
return DefIter;
}
// Is the destination operand a memory reference?
bool SMPInstr::HasDestMemoryOperand(void) {
} // end of SMPInstr::HasDestMemoryOperand()
// Is a source operand a memory reference?
bool SMPInstr::HasSourceMemoryOperand(void) {
} // end of SMPInstr::HasSourceMemoryOperand()
// Get the first memory operand in the DEF list.
clc5q
committed
op_t SMPInstr::MDGetMemDefOp(void) const {
} // end of SMPInstr::MDGetMemDefOp()
// Get the first memory operand in the USE list.
clc5q
committed
op_t SMPInstr::MDGetMemUseOp(void) const {
} // end of SMPInstr::MDGetMemUseOp()
// return original Lea instruction [pseudo-]memory operand.
op_t SMPInstr::GetLeaMemUseOp(void) {
if (this->BasicBlock == NULL) {
return InitOp;
}
else {
map<ea_t, op_t>::iterator MapIter = this->GetBlock()->GetFunc()->FindLeaOperand(this->GetAddr());
return MapIter->second;
}
}
// return BADADDR if not jump, target addr otherwise.
clc5q
committed
ea_t SMPInstr::GetJumpTarget(void) const {
ea_t TargetAddr = BADADDR;
if (this->HasGoodRTL()) {
// We want to find an RTL of the form: inst_ptr_reg := code_addr
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
op_t DefOp = CurrRT->GetLeftOperand();
if (DefOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if ((SMP_ASSIGN == CurrRT->GetOperator()) && (!CurrRT->HasRightSubTree())) {
op_t UseOp = CurrRT->GetRightOperand();
if ((o_near == UseOp.type) || (o_far == UseOp.type)) { // address
TargetAddr = UseOp.addr;
}
}
}
}
return TargetAddr;
} // end SMPInstr::GetJumpTarget()
clc5q
committed
// Does any USE have type NEGATEDPTR?
bool SMPInstr::HasNegatedPtrUSE(void) {
bool UseFound = false;
set<DefOrUse, LessDefUse>::iterator UseIter;
SMPOperandType UseType;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
UseType = UseIter->GetType();
if (IsEqType(UseType, NEGATEDPTR)) {
UseFound = true;
break;
}
}
return UseFound;
} // end of SMPInstr::HasNegatedPtrUSE()
// Detect indirect memory DEFs or USEs
void SMPInstr::AnalyzeIndirectRefs(bool UseFP) {
op_t DefMemOp = this->MDGetMemDefOp();
op_t UseMemOp = this->MDGetMemUseOp();
if (o_void != DefMemOp.type) {
// Found a memory DEF. Is it indirect?
if (MDIsIndirectMemoryOpnd(DefMemOp, UseFP)) {
this->SetIndirectMemWrite();
}
}
if (o_void != UseMemOp.type) {
// Found a memory USE. Is it indirect?
if (MDIsIndirectMemoryOpnd(UseMemOp, UseFP)) {
this->SetIndirectMemRead();
}
}
return;
} // end of SMPInstr::AnalyzeIndirectRefs()
set<DefOrUse, LessDefUse>::iterator SMPInstr::GetPointerAddressReg(op_t MemOp) {
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t displacement;
set<DefOrUse, LessDefUse>::iterator PtrIter;
if ((NULL == this->BasicBlock) || (NULL == this->BasicBlock->GetFunc())) {
SMP_msg("ERROR: NULL member pointers in SMPInstr::GetPointerAddressReg() at %lx \n",
(unsigned long) this->address);
return this->GetLastUse();
}
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
MDExtractAddressFields(MemOp, BaseReg, IndexReg, ScaleFactor,
displacement);
if ((R_none != BaseReg) && (!MDIsStackPtrReg(BaseReg, UseFP))) {
op_t BaseOp = InitOp;
BaseOp.type = o_reg;
BaseOp.reg = (ushort) BaseReg;
PtrIter = this->FindUse(BaseOp);
assert(PtrIter != this->GetLastUse());
if (IsDataPtr(PtrIter->GetType())) {
return PtrIter;
}
}
if ((R_none != IndexReg) && (!MDIsStackPtrReg(IndexReg, UseFP))) {
op_t IndexOp = InitOp;
IndexOp.type = o_reg;
IndexOp.reg = (ushort) IndexReg;
PtrIter = this->FindUse(IndexOp);
assert(PtrIter != this->GetLastUse());
if (IsDataPtr(PtrIter->GetType())) {
return PtrIter;
}
}
PtrIter = this->GetLastUse();
return PtrIter;
} // end of SMPInstr::GetPointerAddressReg()
// Does the instruction whose flags are in F have a numeric type
// as the second source operand?
// NOTE: We can only analyze immediate values now. When data flow analyses are implemented,
// we will be able to analyze many non-immediate operands.
#define IMMEDNUM_LOWER -8191
#define IMMEDNUM_UPPER 8191
bool SMPInstr::IsSecondSrcOperandNumeric(flags_t F) const {
bool SecondOpImm = (this->SMPcmd.Operands[1].type == o_imm);
uval_t TempImm;
TempImm = this->SMPcmd.Operands[1].value;
return (SecondOpImm && IsImmedNumeric(TempImm));
} // end of SMPInstr::IsSecondSrcOperandNumeric()
// Determine the type of the USE-only operand for add and subtract
// instructions. If it is NUMERIC or PROF_NUMERIC, an optimizing
// annotation will result.
// As a byproduct, find the type of the USE/DEF operand as well.
void SMPInstr::SetAddSubSourceType(void) {
// Walk the RTL and find the operands we care about.
// The RTL should look like: opnd1 := (opnd1 op opnd2), where op is
// and add or subtract operator. Within the parentheses, the type
// of opnd1 is our AddSubUseType and opnd1 is our AddSubUseOp, while
// the type of opnd2 is our AddSubSourceType.
if (this->RTL.GetCount() < 1)
return; // no RTL, no leave types as UNINIT.
assert(this->RTL.GetRT(0)->HasRightSubTree());
SMPRegTransfer *RightTree = this->RTL.GetRT(0)->GetRightTree();
op_t LeftOp, RightOp;
LeftOp = RightTree->GetLeftOperand(); // Use (also DEF) operand
#if SMP_BUILD_SPECIAL_ADC_SBB_RTL
if ((NN_adc != this->SMPcmd.itype) && (NN_sbb != this->SMPcmd.itype)) {
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
}
else {
// Add with carry and subtract with borrow have an extra level
// to the tree RTL, e.g. for add with carry:
// opnd1 := (opnd1 + (opnd2 + carryflag))
assert(RightTree->HasRightSubTree());
RightTree = RightTree->GetRightTree();
RightOp = RightTree->GetLeftOperand();
}
#else
assert(!(RightTree->HasRightSubTree()));
RightOp = RightTree->GetRightOperand(); // Src (non-DEF) operand
#endif
set<DefOrUse, LessDefUse>::iterator UseIter, SrcIter;
SrcIter = this->FindUse(RightOp);
assert(SrcIter != this->GetLastUse());
this->AddSubSourceType = SrcIter->GetType();
this->AddSubSourceOp = RightOp;
UseIter = this->FindUse(LeftOp);
assert(UseIter != this->GetLastUse());
this->AddSubUseType = UseIter->GetType();
this->AddSubUseOp = LeftOp;
return;
} // end of SMPInstr::SetAddSubSourceType()
// Are all DEFs in the DEF set NUMERIC type?
bool AllNumeric = (this->Defs.GetSize() > 0); // false if no DEFs, true otherwise
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
// We ignore the stack pointer for pop instructions and consider only
// the register DEF of the pop.
if (this->MDIsPopInstr() && CurrDef->GetOp().is_reg(R_sp))
continue;
clc5q
committed
AllNumeric = (AllNumeric && IsNumeric(CurrDef->GetType()));
}
return AllNumeric;
} // end of SMPInstr::AllDefsNumeric()
// Were the types of any DEFs derived from profiler info?
bool SMPInstr::AnyDefsProfiled(void)
{
bool profd = false;
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {