Newer
Older
updated = true;
clc5q
committed
SMP_msg("ERROR: Unknown operator %d at %x in %s\n",
CurrOp, this->GetAddr(), DisAsmText.GetDisAsm(this->GetAddr()));
break;
} // end switch on operator
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
// Determine if type inference is finished for this register transfer.
if (updated && (!TypeInferenceFinished)) {
bool FinishedRight = false;
bool FinishedLeft = false;
bool FinishedOperator = (CurrRT->GetOperatorType() != UNINIT);
if (FinishedOperator) {
switch (CurrOp) {
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_SIGN_EXTEND:
case SMP_ZERO_EXTEND:
case SMP_ADDRESS_OF: // take effective address
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
case SMP_BITWISE_NOT: // unary operator
case SMP_NEGATE: // unary negation
case SMP_DECREMENT:
case SMP_INCREMENT:
case SMP_UNARY_NUMERIC_OPERATION: // miscellaneous; produces NUMERIC result
case SMP_UNARY_FLOATING_ARITHMETIC: // all the same to our type system; all NUMERIC
// Unary operators have no right operand.
FinishedRight = true;
break;
default: // All binary operators come here
if (CurrRT->HasRightSubTree()) {
FinishedRight = CurrRT->GetRightTree()->IsTypeInferenceComplete();
}
else {
UseOp = CurrRT->GetRightOperand();
if (UseOp.type != o_void) {
CurrUse = this->Uses.FindRef(UseOp);
assert(CurrUse != this->GetLastUse());
FinishedRight = (CurrUse->GetType() != UNINIT);
}
else { // if o_void, no further type inference on it is possible.
FinishedRight = true;
}
}
break;
} // end switch on CurrOp
clc5q
committed
if (FinishedRight) { // no point checking left op if right op is not finished
DefOp = CurrRT->GetLeftOperand();
if (DefOp.type != o_void) {
if (SMP_ASSIGN == CurrOp) {
CurrDef = this->Defs.FindRef(DefOp);
assert(CurrDef != this->GetLastDef());
FinishedLeft = (CurrDef->GetType() != UNINIT);
}
else { // not ASSIGN, so really a UseOp not DefOp
CurrUse = this->Uses.FindRef(DefOp);
assert(CurrUse != this->GetLastUse());
FinishedLeft = (CurrUse->GetType() != UNINIT);
}
}
else { // if o_void, no further type inference on it is possible.
FinishedLeft = true;
}
}
TypeInferenceFinished = (FinishedLeft && FinishedRight);
} // end if (FinishedOperator)
} // end if (updated && (!TypeInferenceFinished))
if (TypeInferenceFinished) {
CurrRT->SetTypeInferenceComplete();
}
return updated;
} // end of SMPInstr::InferOperatorType()
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
// Transfer function: Does operator propagate signedness of its operands to its result?
bool SMPInstr::DoesOperatorTransferSign(SMPoperator CurrOp) {
bool transfer = false;
switch (CurrOp) {
case SMP_NULL_OPERATOR:
case SMP_CALL: // CALL instruction
case SMP_INPUT: // input from port
case SMP_OUTPUT: // output to port
case SMP_SYSTEM_OPERATION: // for instructions such as CPUID, RDTSC, etc.; NUMERIC
// No concept of signedness for some operators
break;
case SMP_ADDRESS_OF: // take effective address
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)
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:
// Inherently unsigned and signed operators force the signedness
// of their results, rather than propagating the signedness of
// their operands.
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
transfer = true;
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;
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
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()
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
// 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
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
#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))) {
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
// 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()
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
// 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
}