Newer
Older
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
case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
case SMP_COMPARE_EQ_AND_SET: // Compare for equality 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_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_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
transfer = true;
break;
default:
clc5q
committed
SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
break;
} // end switch on operator
return transfer;
} // end of SMPInstr::DoesOperatorTransferSign()
// Initial inferences (if any) about FG info of operand based solely on the RTL operator type above it in RTL.
bool SMPInstr::InitFGInfoFromOperator(SMPoperator CurrOp, struct FineGrainedInfo &InitFG) {
bool changed = false;
switch (CurrOp) {
case SMP_NULL_OPERATOR:
break;
case SMP_CALL: // CALL instruction
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED; // target address is unsigned 32-bit
InitFG.SizeInfo |= (MD_NORMAL_BITWIDTH_MASK | FG_MASK_CODEPOINTER);
changed = true;
break;
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_ADDRESS_OF: // take effective address
case SMP_U_COMPARE: // unsigned compare (AND-based)
case SMP_S_COMPARE: // signed compare (subtraction-based)
// NOTE: The AND-based and subtraction-based comparisons are used
// on lots of operands of all types, and the conditional jump that
// follows determines signedness, not the operator.
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:
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
changed = 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_LESS_THAN: // boolean test operators
case SMP_GREATER_THAN:
case SMP_LESS_EQUAL:
case SMP_GREATER_EQUAL:
// Special case: If signed multiply operator, it might sometimes
// be used for unsigned operands when upper bits of the result
// are discarded, because there is no difference in the result bits
// between unsigned and signed multiplcation when only the lower
// N bits are retained and the upper N bits are discarded.
if ((SMP_S_MULTIPLY == CurrOp) && (!(this->MDIsSignedArithmetic()))) {
break;
}
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
changed = true;
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
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
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
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= FG_MASK_FLOAT_MMX;
changed = true;
break;
case SMP_REVERSE_SHIFT_U: // Shift right operand by bit count in left operand
case SMP_SHUFFLE: // Shuffle bytes, words, etc. within destination operation per source mask
case SMP_COMPARE_EQ_AND_SET: // Compare for equality 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_PACK_S: // Pack operands into extended-precision register, signed saturation for loss of precision
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
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
InitFG.SignMiscInfo |= FG_MASK_UNSIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
case SMP_INTERLEAVE: // extended-precision interleaving of bytes or words or dwords etc.; NUMERIC
case SMP_CONCATENATE: // extended-precision concatenation; NUMERIC
InitFG.SignMiscInfo |= FG_MASK_SIGNED;
InitFG.SizeInfo |= (FG_MASK_FLOAT_MMX | FG_MASK_BITWIDTH_128);
changed = true;
break;
default:
clc5q
committed
SMP_msg("ERROR: Unknown operator in %s\n", DisAsmText.GetDisAsm(this->GetAddr()));
break;
} // end switch on operator
return changed;
} // end of SMPInstr::InitFGInfoFromOperator()
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
// Helper to take USE operand, find its SSANum, and return its UseHashValue.
int SMPInstr::GetUseOpHashAndSSA(op_t UseOp, int &SSANum) {
op_t SearchOp = UseOp;
SearchOp.reg = MDCanonicalizeSubReg(UseOp.reg);
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SearchOp);
assert(UseIter != this->GetLastUse());
SSANum = UseIter->GetSSANum();
int UseHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
return UseHashValue;
} // end of SMPInstr::GetUseOpHashAndSSA()
// Helper to take DEF operand, find its SSANum, and return its DefHashValue.
int SMPInstr::GetDefOpHashAndSSA(op_t DefOp, int &SSANum) {
op_t SearchOp = DefOp;
SearchOp.reg = MDCanonicalizeSubReg(DefOp.reg);
set<DefOrUse, LessDefUse>::iterator DefIter = this->FindDef(SearchOp);
assert(DefIter != this->GetLastDef());
SSANum = DefIter->GetSSANum();
int DefHashValue = HashGlobalNameAndSSA(SearchOp, SSANum);
return DefHashValue;
} // end of SMPInstr::GetDefOpHashAndSSA()
// helper for InferOperatorFGInfo() to update DEF maps, return true if changed maps
bool SMPInstr::UpdateDefOpFGInfo(op_t DefOp, struct FineGrainedInfo NewFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
set<DefOrUse, LessDefUse>::iterator DefIter;
int SSANum;
int DefHashValue;
op_t SearchOp;
bool LocalName;
struct FineGrainedInfo OldFG, UnionFG;
// If operator is inherently signed, then we will have
// a sign bit set in NewFG from InitFGInfoFromOperator().
DefHashValue = this->GetDefOpHashAndSSA(DefOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(DefOp);
if (LocalName) {
// Get old FG info from block level.
OldFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
}
else { // global name
// Get old FG info from function level.
OldFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
}
UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
// The signs they are a-changin'.
MapsChanged = true;
if (LocalName)
this->BasicBlock->UpdateDefFGInfo(DefHashValue, UnionFG);
this->BasicBlock->GetFunc()->UpdateDefFGInfo(DefHashValue, UnionFG);
}
return MapsChanged;
} // end of SMPInstr::UpdateDefOpFGInfo()
// helper for InferOperatorFGInfo() to update USE maps, return true if changed maps
bool SMPInstr::UpdateUseOpFGInfo(op_t UseOp, struct FineGrainedInfo NewFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
int SSANum;
int UseHashValue;
bool LocalName;
struct FineGrainedInfo OldFG, UnionFG;
// If operator is inherently signed, then we will have
// a sign bit set in NewFG from InitFGInfoFromOperator().
UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(UseOp);
if (LocalName) {
// Get old FG info from block level.
OldFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else { // global name
// Get old FG info from function level.
OldFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
UnionFG.SignMiscInfo = OldFG.SignMiscInfo | NewFG.SignMiscInfo;
UnionFG.SizeInfo = OldFG.SizeInfo | NewFG.SizeInfo;
if ((OldFG.SignMiscInfo != UnionFG.SignMiscInfo) || (OldFG.SizeInfo != UnionFG.SizeInfo)) {
// The signs they are a-changin'.
MapsChanged = true;
if (LocalName)
this->BasicBlock->UpdateUseFGInfo(UseHashValue, UnionFG);
this->BasicBlock->GetFunc()->UpdateUseFGInfo(UseHashValue, UnionFG);
}
return MapsChanged;
} // end of SMPInstr::UpdateUseOpFGInfo()
// Helper to fetch DEF signedness info for UseOp that has none.
unsigned short SMPInstr::GetDefSignInfoFromUseOp(op_t UseOp) {
int SSANum, UseHashValue;
bool LocalName;
UseHashValue = this->GetUseOpHashAndSSA(UseOp, SSANum);
LocalName = this->BasicBlock->IsLocalName(UseOp);
if (LocalName) {
// Get old sign info from block level.
return this->BasicBlock->GetDefSignMiscInfo(UseHashValue);
}
else { // global name
// Get old sign info from function level.
return this->BasicBlock->GetFunc()->GetDefSignMiscInfo(UseHashValue);
}
} // end of SMPInstr::GetDefSignInfoFromUseOp()
// infer FG info, + width on FirstIter; pass out FG info for op subtree, return true if change made to any FG info map.
bool SMPInstr::InferOperatorFGInfo(SMPRegTransfer *CurrRT, bool FirstIter, struct FineGrainedInfo &OpFG) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
bool NewChange = false; // Bit changes from InitFGInfoFromOperator() ?
SMPoperator CurrOp = CurrRT->GetOperator();
struct FineGrainedInfo LeftFG, OldLeftFG;
struct FineGrainedInfo RightFG, OldRightFG;
op_t LeftOp, RightOp;
unsigned short WidthMask, SignMask;
bool CurrOpTransfersSign = this->DoesOperatorTransferSign(CurrOp);
bool UseFP = this->BasicBlock->GetFunc()->UsesFramePointer();
bool success;
int DefHashValue, UseHashValue, SSANum;
// Recurse to the right first, so we can do a depth-first accumulation of FG info.
RightFG.SignMiscInfo = 0;
RightFG.SizeInfo = 0;
if (CurrRT->HasRightSubTree()) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
} // end if (FirstIter)
MapsChanged |= this->InferOperatorFGInfo(CurrRT->GetRightTree(), FirstIter, RightFG);
}
else {
RightOp = CurrRT->GetRightOperand();
if (RightOp.type == o_imm) {
// If immediate operand is a data address or code address, we can infer that it is unsigned.
uval_t ImmVal = RightOp.value;
if (IsImmedGlobalAddress((ea_t) ImmVal)) {
// Data address (type GLOBALPTR)
RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
}
else if (this->MDIsInterruptCall() || IsImmedCodeAddress((ea_t) ImmVal)) {
// Code address (type GLOBALPTR)
RightFG.SignMiscInfo |= FG_MASK_UNSIGNED;
}
}
else if ((RightOp.type == o_reg) && !RightOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, RightFG);
WidthMask = ComputeOperandBitWidthMask(RightOp, 0);
RightFG.SizeInfo |= WidthMask;
} // end if (FirstIter)
#define SMP_AGGRESSIVE_SIGN_TRANSFER 1
#if SMP_AGGRESSIVE_SIGN_TRANSFER
else {
// On all iterations other than 1st, see if USE has FG info.
UseHashValue = this->GetUseOpHashAndSSA(RightOp, SSANum);
if (this->BasicBlock->IsLocalName(RightOp)) {
// Get FG info from block.
RightFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else {
// Get FG info from function level.
RightFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
}
#endif
// Propagate signedness on all iterations.
// If operator is inherently signed, then we will have
// a sign bit set in RightFG from InitFGInfoFromOperator().
if ((RightFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
// We have a USE with no sign info. See if we
// can get sign info from the DEF of this USE so we can
// transfer it up the RTL tree.
RightFG.SignMiscInfo =
(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(RightOp)));
}
if ((RightFG.SignMiscInfo != 0) || (RightFG.SizeInfo != 0))
MapsChanged |= this->UpdateUseOpFGInfo(RightOp, RightFG);
} // end if (RightOP is o_reg)
else if (MDIsStackAccessOpnd(RightOp, UseFP)) {
// We used to assume that all FG info transfers from stack locations to
// the target registers of stack loads happened in SMPInstr::MDSetWidthSignInfo(),
// in an early pass that needed no iteration. The FG info was loaded from the
// StackFGInfo that was computed in SMPFunction::FindOutgoingArgsSize() based solely
// on whether the load was sign-extended or zero-extended. Of course, many stack
// locations have neither kind of signed/unsigned load. So, if we see a store to
// a stack location with no signedness, we transfer the signedness of the RightFG
// to the stack location FGInfo in the code below that processes the LeftOp.
// As a result, we now have a need to examine regular loads from the stack to
// see if there is signedness info for the stack location.
success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, RightOp, RightFG);
if (success) {
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
RightFG.SizeInfo = 0; // only want to transfer signedness
}
}
} // end if (right subtree) else right operand
LeftFG.SignMiscInfo = 0;
LeftFG.SizeInfo = 0;
LeftOp = CurrRT->GetLeftOperand();
bool OpIsDEF = (SMP_ASSIGN == CurrOp);
// Skip control-flow assignments to the instruction pointer register.
if ((LeftOp.type == o_reg) && !LeftOp.is_reg(MD_INSTRUCTION_POINTER_REG)) {
if (FirstIter) { // Get width as well as signedness
NewChange = this->InitFGInfoFromOperator(CurrOp, LeftFG);
// Special case: For sign-extended and zero-extended loads,
// we don't know whether the DEF will always be USEd as
// the smaller or larger size. For example, we could
// zero-extend a 16-bit stack location into a 32-bit register
// just because the compiler always loads unsigned shorts
// that way, but we might never use it as a 32-bit value.
// So there is no truncation if we store only 16 bits later.
// By setting the target of an extended load to zero width,
// we signal that we want the maximum USE width to determine
// whether the store is truncated (see EmitIntegerErrorAnnotations).
WidthMask = ComputeOperandBitWidthMask(LeftOp, 0);
if (OpIsDEF) {
if (this->MDIsSignedLoad(SignMask)) {
WidthMask = 0;
}
// DEF inherits sign from right hand side.
LeftFG.SignMiscInfo |= RightFG.SignMiscInfo;
else if ((LeftFG.SignMiscInfo == 0) && CurrOpTransfersSign) {
// We have a USE, not a DEF, with no sign info. See if we
// can get sign info from the DEF of this USE so we can
// transfer it up the RTL tree.
LeftFG.SignMiscInfo =
(FG_MASK_SIGNEDNESS_BITS & (this->GetDefSignInfoFromUseOp(LeftOp)));
LeftFG.SizeInfo |= WidthMask;
if ((LeftFG.SignMiscInfo != 0) || (LeftFG.SizeInfo != 0)) {
// Either NewChanged or CurrOpTransfersSign is true or we set WidthMask above.
// See if we would change the FG map entry.
if (OpIsDEF) { // Need DEF map info
MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
}
else { // need USE map info
MapsChanged |= this->UpdateUseOpFGInfo(LeftOp, LeftFG);
}
} // end if non-zero LeftFG info
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
#if SMP_AGGRESSIVE_SIGN_TRANSFER
else {
// On all iterations other than 1st, see if LeftOp has FG info.
if (!OpIsDEF) { // LeftOp is a USE
UseHashValue = this->GetUseOpHashAndSSA(LeftOp, SSANum);
if (this->BasicBlock->IsLocalName(LeftOp)) {
// Get FG info from block.
LeftFG = this->BasicBlock->GetUseFGInfo(UseHashValue);
}
else {
// Get FG info from function level.
LeftFG = this->BasicBlock->GetFunc()->GetUseFGInfo(UseHashValue);
}
}
else { // LeftOp is a DEF
DefHashValue = this->GetDefOpHashAndSSA(LeftOp, SSANum);
if (this->BasicBlock->IsLocalName(LeftOp)) {
// Get FG info from block.
LeftFG = this->BasicBlock->GetDefFGInfo(DefHashValue);
}
else {
// Get FG info from function level.
LeftFG = this->BasicBlock->GetFunc()->GetDefFGInfo(DefHashValue);
}
// See if RightFG has sign info to transfer to LeftFG.
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
if ((SignMask != 0) && (SignMask != (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS))) {
// SignMask from RightFG has bits that will change LeftFG.SignMiscInfo.
LeftFG.SignMiscInfo |= SignMask;
MapsChanged |= this->UpdateDefOpFGInfo(LeftOp, LeftFG);
}
}
}
#endif
} // end of register case for LeftOp
else if (OpIsDEF && MDIsStackAccessOpnd(LeftOp, UseFP)
&& (!this->BasicBlock->GetFunc()->IsInOutgoingArgsRegion(LeftOp))) {
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
// For stores into the stack, if the operand being stored has signedness
// and the stack location has no signedness, then we have a case where
// none of the loads from the stack location were signed, so it is
// safe to infer signedness of the stack location based on what is being
// stored into it, as no store signedness will conflict with load signedness.
success = this->BasicBlock->GetFunc()->MDGetFGStackLocInfo(this->address, LeftOp, LeftFG);
assert(success);
if (0 == (LeftFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS)) {
// No previous signedness info for the stack location.
// Get signedness info from RightFG.
SignMask = (RightFG.SignMiscInfo & FG_MASK_SIGNEDNESS_BITS);
if ((0 != SignMask) && (FG_MASK_INCONSISTENT_SIGN != SignMask)) {
// Operand being stored has signedness.
// Transfer the signedness to the stack location.
struct FineGrainedInfo TempFG;
TempFG.SignMiscInfo = SignMask;
TempFG.SizeInfo = 0; // just update signedness
success = this->BasicBlock->GetFunc()->MDUpdateFGStackLocInfo(this->address, LeftOp, TempFG);
MapsChanged |= success;
}
}
}
// Prepare to return FG info for operator. First, OR the left and right FG infos.
if (NewChange || MapsChanged || CurrOpTransfersSign) {
OpFG.SignMiscInfo |= LeftFG.SignMiscInfo;
OpFG.SizeInfo |= LeftFG.SizeInfo;
OpFG.SignMiscInfo |= RightFG.SignMiscInfo;
OpFG.SizeInfo |= RightFG.SizeInfo;
}
// An operator could override the width or signedness info of its operands.
if (CurrOp == SMP_ADDRESS_OF) {
// Result is 32-bit data pointer.
OpFG.SizeInfo &= (~FG_MASK_BITWIDTH_FIELDS); // clear all width bits
OpFG.SizeInfo |= (FG_MASK_BITWIDTH_32 | FG_MASK_DATAPOINTER);
OpFG.SignMiscInfo &= (~FG_MASK_SIGNED);
OpFG.SignMiscInfo |= FG_MASK_UNSIGNED;
}
return MapsChanged;
} // end of SMPInstr::InferOperatorFGInfo()
// infer width on first pass, signedness on all passes
bool SMPInstr::InferFGInfo(unsigned short IterCount) {
bool MapsChanged = false; // Changes to maps of name/SSA to FG info?
struct FineGrainedInfo OpFG;
SMPitype DFType = this->GetDataFlowType();
assert(0 < IterCount); // start IterCount at 1, not 0.
if (DFType != DEFAULT) {
// We have a control flow instruction, e.g. call, return, branch, jump
// No data operands unless these instructions are indirect through a register,
// and the indirect operand is a memory operand in that case, e.g. [eax].
return MapsChanged;
}
for (size_t index = 0; index < this->RTL.GetCount(); ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if (SMP_NULL_OPERATOR == CurrRT->GetOperator()) // nothing to infer
continue;
OpFG.SignMiscInfo = 0;
OpFG.SizeInfo = 0;
MapsChanged |= this->InferOperatorFGInfo(CurrRT, (1 == IterCount), OpFG);
if (SMP_CALL == CurrRT->GetOperator()) // no LeftOp DEF
continue;
} // end for all RTs in the RTL
return MapsChanged;
} // end of SMPInstr::InferFGInfo()
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
// Get the meet of the metadata types of all non-flags DEFs.
SMPMetadataType SMPInstr::GetDefMetadataType(void) {
SMPMetadataType MeetType = DEF_METADATA_UNANALYZED;
set<DefOrUse, LessDefUse>::iterator CurrDef;
for (CurrDef = this->GetFirstDef(); CurrDef != this->GetLastDef(); ++CurrDef) {
SMPMetadataType CurrType;
op_t DefOp = CurrDef->GetOp();
if (DefOp.is_reg(X86_FLAGS_REG))
continue; // flags are always unused metadata; irrelevant
CurrType = CurrDef->GetMetadataStatus();
if (MeetType == CurrType)
continue; // no meet operation to perform
// Any time we find USED metadata, that overrides all other types.
if (CurrType == DEF_METADATA_USED)
return CurrType;
if (MeetType == DEF_METADATA_UNANALYZED)
MeetType = CurrType;
else if (MeetType < DEF_METADATA_REDUNDANT) {
// Conflict between types of different DEFs. It could be that
// a multiply or divide instruction DEFs EAX and EDX, and one
// of them is used in a store and the other is unused. In that
// case, the final MeetType is USED and we can return. Or, if
// one type is UNUSED and the other is REDUNDANT, we can set
// the final type to the REDUNDANT type and return. The USED case
// is handled above, so we must have the UNUSED vs. REDUNDANT case.
assert(CurrType >= DEF_METADATA_REDUNDANT);
MeetType = CurrType;
}
else { // MeetType REDUNDANT, not equal to CurrType.
if (CurrType >= DEF_METADATA_REDUNDANT) {
// One type is profile derived, both are REDUNDANT.
MeetType = DEF_METADATA_PROF_REDUNDANT;
}
else {
assert(DEF_METADATA_UNUSED == CurrType);
// leave MeetType as REDUNDANT
}
}
} // end for all DEFs
return MeetType;
} // end of SMPInstr::GetDefMetadataType()
// 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;
char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
MDExtractAddressFields(Opnd, BaseReg, IndexReg, ScaleFactor, displacement);
if (BaseReg == R_sp) { // ESP cannot be IndexReg
// ESP-relative constant offset
clc5q
committed
SMP_fprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
else if (UseFP && ((IndexReg == R_bp) || (BaseReg == R_bp))) {
// EBP-relative constant offset
clc5q
committed
SMP_fprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, 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;
char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
#if 0
if (this->address == 0x80925f4) {
clc5q
committed
SMP_msg("PROBLEM INSTRUCTION: \n");
this->PrintOperands();
}
#endif
for (int i = 0; i < UA_MAXOP; ++i) {
Opnd = this->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
clc5q
committed
SMP_fprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
clc5q
committed
SMP_fprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->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
clc5q
committed
SMP_fprintf(AnnotFile,
"%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, offset, disasm);
}
else if (UseFP && (BaseReg == R_bp)) {
// EBP-relative constant offset
clc5q
committed
SMP_fprintf(AnnotFile,
"%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->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)) {
// Two possibilities: a move of the stack pointer, or an "lea"
// opcode, e.g. lea eax,[eap+8] ==> eax:=esp+8. In the move
// instruction (e.g. mov eax,esp), we have the implicit zero
// offset from the stack pointer register, but in the lea case,
// we might have zero or some other offset (lea eax,[esp] has
// the implicit zero).
int ESPoffset = 0;
if (NN_lea == this->SMPcmd.itype) {
ESPoffset = this->MDGetImmedUse();
}
// NOTE: Looks like this next line should be "else" because an lea instruction
// looks like it has a memory operand, hence it has already been handled above.
// We are getting duplicate annotations for lea instructions.
if (UseFP && this->GetFirstUse()->GetOp().is_reg(R_bp)) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d PTRIMMEDEBP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, ESPoffset, disasm);
}
else {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d PTRIMMEDESP STACK %d displ %s\n",
this->SMPcmd.ea, this->SMPcmd.size, ESPoffset, disasm);
}
}
return;
} // end of SMPInstr::AnnotateStackConstants()
// Emit all annotations for the instruction in the absence of RTL type inference.
void SMPInstr::EmitAnnotations(bool UseFP, bool AllocSeen, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) {
ea_t addr = this->address;
flags_t InstrFlags = getFlags(addr);
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(InstrFlags); // assumes 2nd source is Imm or not-numeric?!
clc5q
committed
bool NoWarnFlag = false; // NOWARN annotation emitted?
char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
clc5q
committed
bool OrphanCode = (NULL == this->BasicBlock);
ProfilerInformation *ProfInfo = NULL;
if (!OrphanCode)
ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
#endif
++OptCount[OptType]; // keep count for debugging info
clc5q
committed
#if SMP_ANNOTATE_ALL_MEMORY_OPERANDS
// Emit informational annotations for memory operands.
if (MemSrc) {
op_t MemSrcOp = this->MDGetMemUseOp();
size_t SrcBitWidth = 8 * GetOpDataSize(MemSrcOp);
clc5q
committed
SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR MEMSRC %d", addr, this->SMPcmd.size, SrcBitWidth);
AnnotPrintOperand(MemSrcOp, InfoAnnotFile);
clc5q
committed
SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
}
if (MemDest) {
op_t MemDestOp = this->MDGetMemDefOp();
size_t DestBitWidth = 8 * GetOpDataSize(MemDestOp);
clc5q
committed
SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR MEMDEF %d", addr, this->SMPcmd.size, DestBitWidth);
AnnotPrintOperand(MemDestOp, InfoAnnotFile);
clc5q
committed
SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
clc5q
committed
#endif
// If the instruction is a CALL (or INDIR_CALL that has been resolved to
// a single target address), then we need to see if the call is to a
// function that has been forbidden by a security policy. If so, we
// need to output a security alert.
// In the near future, we will output SPRI instrumentation to prevent
// the system/library call from executing.
if ((BADADDR != this->CallTarget) && (!this->IsCallUsedAsJump())) {
// We have a resolved call target address, either via direct or indirect call.
string FuncName = this->GetTrimmedCalledFunctionName();
ZST_SysCallType FuncCallType = GetCallTypeFromFuncName(FuncName);
ZST_Policy FuncCallPolicy = GetPolicyFromCallType(FuncCallType);
if (ZST_DISALLOW == FuncCallPolicy) {
if ((NULL != this->GetBlock()) && (NULL != this->GetBlock()->GetFunc())) {
clc5q
committed
SMP_fprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x in %s\n",
FuncName.c_str(), this->address, this->GetBlock()->GetFunc()->GetFuncName());
}
else {
clc5q
committed
SMP_fprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x\n", FuncName.c_str(), this->address);
clc5q
committed
SMP_fprintf(ZST_AlarmFile, "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR SECURITYCALL Disallow 1 1 %s \n", addr, this->SMPcmd.size, disasm);
}
}
#if SMP_DEBUG_MEM
if (MemDest || MemSrc) {
clc5q
committed
SMP_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
clc5q
committed
SMP_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 || !NeedsFrame) && this->MDIsPushInstr()) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL NoWarn %s \n",
clc5q
committed
NoWarnFlag = true;
}
else {
SDTInstrumentation = true;
}
break;
}
case 1: // nothing for SDT to do
clc5q
committed
{ SMP_fprintf(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
}
clc5q
committed
SMP_fprintf(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
}
if (SecondSrcOperandImmNum
&& !this->MDIsFrameAllocInstr()
#if SPECIAL_CASE_CARRY_BORROW
&& (this->SMPcmd.itype != NN_adc)
&& (this->SMPcmd.itype != NN_sbb)
#endif
) { // treat as category 1
clc5q
committed
SMP_fprintf(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
}
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL AlwaysPTR %s \n",
addr, -OptType, disasm);
++AnnotationCount[OptType];
break;
}
case 8: // Implicitly writes to EDX:EAX, always numeric.
clc5q
committed
{ SMP_fprintf(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.
clc5q
committed
SMP_msg("Floating point MemDest: %s \n", disasm);
#endif
SDTInstrumentation = true;
break; // treat as category 0
}
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL %s %s \n",
addr, -1, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
break;
}
case 10: // Implicitly writes to EDX:EAX and ECX, always numeric.
clc5q
committed
{ SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL n EDX EAX ECX ZZ %s %s \n",
addr, -2, OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
SDTInstrumentation = true;
break;
}
default: // 2,3,7: Optimization possibilities depend on operands
{
#if SMP_DEBUG2
if (OptType == 3) { // MOV instr class
if (MemDest) {
clc5q
committed
SMP_msg("MemDest on MOV: %s\n", disasm);
}
else if (!SecondSrcOperandNum) {
clc5q
committed
SMP_msg("MOV: not 2nd op numeric: %s\n", disasm);
this->PrintOperands();
}
}
#endif
SDTInstrumentation = true;
if (MemDest) {
#if SMP_DEBUG_XOR
if (OptType == 2)
clc5q
committed
SMP_msg("MemDest on OptType 2: %s\n", disasm);
#endif
break; // treat as category 0
}
if ((OptType == 2) || (OptType == 7) || SecondSrcOperandImmNum) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL n %s %s %s \n",
addr, -2, this->DestString(OptType),
OptExplanation[OptType], disasm);
++AnnotationCount[OptType];
}
break;
}
} // end switch (OptType)
// always emit stack constant annotations, in case strata is
// instrumenting all instructions, or trying to verify speculative annotations.
this->AnnotateStackConstants(UseFP, AnnotFile);
// 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.
// Likewise, we can tell mmStrata if a MemDest is an
// non-directly-accessed child object.
clc5q
committed
if (SDTInstrumentation || NoWarnFlag) {
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.
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR DEADREGS %s ZZ %s \n",
addr, this->SMPcmd.size, this->DeadRegsString, disasm);
}
#if SMP_CHILDACCESS_ALL_CODE
int ChildOffset, ChildSize;
if (MemDest && !OrphanCode
&& ProfInfo->GetMemoryAccessInfo()->ComputeNonDirectAccessRegion(addr,
ChildOffset, ChildSize)) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR CHILDACCESS %d %d ZZ %s \n",
addr, this->SMPcmd.size, ChildOffset, ChildSize, disasm);
}
#endif
}
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)
{
char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
clc5q
committed
SMP_fprintf(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, bool NeedsFrame, FILE *AnnotFile, FILE *InfoAnnotFile) {
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 ProfiledDEFs = this->AnyDefsProfiled(); // Some DEFs come from the profiler
bool UnusedMetadata = this->AllDefMetadataUnused();
bool MemDest = this->HasDestMemoryOperand();
bool MemSrc = this->HasSourceMemoryOperand();
bool SecondSrcOperandImmNum = this->IsSecondSrcOperandNumeric(InstrFlags); // assumes 2nd source is imm or not-numeric??
clc5q
committed
bool NoWarnFlag = false; // NOWARN annotation emitted?
bool CarryBorrow = ((this->SMPcmd.itype == NN_adc)
|| (this->SMPcmd.itype == NN_sbb));
// Do we have the special case in which a non-NUMERIC comes into
// an add with carry or subtract with borrow and the result
// has been inferred to be NUMERIC?
bool TypeChange = CarryBorrow && (!IsNumeric(this->AddSubUseType))
&& NumericDEFs;
SMPMetadataType DefMetadataType = this->GetDefMetadataType();
ProfilerInformation *ProfInfo;
ProfInfo = this->BasicBlock->GetFunc()->GetProg()->GetProfInfo();
char *disasm = DisAsmText.GetDisAsm(this->GetAddr());
++OptCount[this->OptType]; // keep count for debugging info
if (this->IsNop())
TypeGroup = 1; // no-op idioms need their category reset
// Emit appropriate optimization annotations.
bool SDTInstrumentation = false;
clc5q
committed
#if SMP_ANNOTATE_ALL_MEMORY_OPERANDS
// Emit informational annotations for memory operands.
if (MemSrc) {
op_t MemSrcOp = this->MDGetMemUseOp();
size_t SrcBitWidth = 8 * GetOpDataSize(MemSrcOp);
clc5q
committed
SMP_fprintf(InfoAnnotFile, "%10x %6zu INSTR MEMSRC %zu", addr, this->SMPcmd.size, SrcBitWidth);
AnnotPrintOperand(MemSrcOp, InfoAnnotFile);
clc5q
committed
SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
}
if (MemDest) {
op_t MemDestOp = this->MDGetMemDefOp();
size_t DestBitWidth = 8 * GetOpDataSize(MemDestOp);
clc5q
committed
SMP_fprintf(InfoAnnotFile, "%10x %6zu INSTR MEMDEF %zu", addr, this->SMPcmd.size, DestBitWidth);
AnnotPrintOperand(MemDestOp, InfoAnnotFile);
clc5q
committed
SMP_fprintf(InfoAnnotFile, " ZZ %s \n", disasm);
clc5q
committed
#endif
// If the instruction is a CALL (or INDIR_CALL that has been resolved to
// a single target address), then we need to see if the call is to a
// function that has been forbidden by a security policy. If so, we
// need to output a security alert.
// In the near future, we will output SPRI instrumentation to prevent
// the system/library call from executing.
if ((BADADDR != this->CallTarget) && (!this->IsCallUsedAsJump())) {
// We have a resolved call target address, either via direct or indirect call.
string FuncName = this->GetTrimmedCalledFunctionName();
ZST_SysCallType FuncCallType = GetCallTypeFromFuncName(FuncName);
ZST_Policy FuncCallPolicy = GetPolicyFromCallType(FuncCallType);
if (ZST_DISALLOW == FuncCallPolicy) {
clc5q
committed
SMP_fprintf(ZST_AlarmFile, "ALARM: Call to %s will be disallowed at %x in %s\n",
FuncName.c_str(), this->address, this->GetBlock()->GetFunc()->GetFuncName());
clc5q
committed
SMP_fprintf(ZST_AlarmFile, "ALARM REASON: Call policy is DISALLOW for all calls of type %s\n", CallTypeNames[FuncCallType]);
SMP_fprintf(InfoAnnotFile, "%10x %6d INSTR SECURITYCALL Disallow 1 1 %s \n", addr, this->SMPcmd.size, disasm);
}
}
// If the DEF metadata is all unused, mmStrata can skip the instruction.
// We omit this for groups 1 and 14, so that the metadata analysis
// does not get statistical credit for instructions that were already
// getting -1 annotations without analysis.
// We also cannot skip NN_adc and NN_sbb instructions that change the
// type of the incoming register.
if ((1 != TypeGroup) && (14 != TypeGroup) && (!this->MDIsInterruptCall())
&& !TypeChange) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataUnused %s \n",
++AnnotationCount[this->OptType];
return;
}
else if (DEF_METADATA_REDUNDANT == DefMetadataType) {
clc5q
committed
SMP_fprintf(AnnotFile, "%10x %6d INSTR LOCAL MetadataRedundant %s \n",