Newer
Older
// Inequality operator for SMPInstr. Key field is address.
int SMPInstr::operator!=(const SMPInstr &rhs) const {
return (this->address != rhs.GetAddr());
}
// Less than operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<(const SMPInstr &rhs) const {
return (this->address < rhs.GetAddr());
}
// Less than or equal operator for sorting SMPInstr lists. Key field is address.
int SMPInstr::operator<=(const SMPInstr &rhs) const {
return (this->address <= rhs.GetAddr());
}
#define MD_FIRST_ENTER_INSTR NN_enterw
#define MD_LAST_ENTER_INSTR NN_enterq
// Is this instruction one that allocates space on the
// stack for the local variables?
bool SMPInstr::MDIsFrameAllocInstr(void) {
// The frame allocating instruction should look like:
// sub esp,48 or add esp,-64 etc.
op_t ESPOp = InitOp;
ESPOp.type = o_reg;
ESPOp.reg = R_sp;
if ((SMPcmd.itype == NN_sub) || (SMPcmd.itype == NN_add)) {
if (this->GetLastDef() != this->Defs.FindRef(ESPOp)) {
// We know that an addition or subtraction is being
// performed on the stack pointer. This should not be
// possible within the prologue except at the stack
// frame allocation instruction, so return true. We
// could be more robust in this analysis in the future. **!!**
// CAUTION: If a compiler allocates 64 bytes for locals
// and 16 bytes for outgoing arguments in a single
// instruction: sub esp,80
// you cannot insist on finding sub esp,LocSize
// To make this more robust, we are going to insist that
// an allocation of stack space is either performed by
// adding a negative immediate value, or by subtracting
// a positive immediate value. We will throw in, free of
// charge, a subtraction of a register, which is how alloca()
// usually allocates stack space.
// PHASE ORDERING: Should we use the Operands[] instead of the USE list? **!!**
set<DefOrUse, LessDefUse>::iterator CurrUse;
for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
if (o_imm == CurrUse->GetOp().type) {
signed long TempImm = (signed long) CurrUse->GetOp().value;
if (((0 > TempImm) && (this->SMPcmd.itype == NN_add))
|| ((0 < TempImm) && (this->SMPcmd.itype == NN_sub))) {
return true;
}
}
else if ((o_reg == CurrUse->GetOp().type)
&& (!CurrUse->GetOp().is_reg(R_sp)) // skip the ESP operand
&& (this->SMPcmd.itype == NN_sub)) { // sub esp,reg: alloca() ?
return true;
}
}
}
}
else if ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR)) {
return true;
}
return false;
} // end of SMPInstr::MDIsFrameAllocInstr()
#define MD_FIRST_LEAVE_INSTR NN_leavew
#define MD_LAST_LEAVE_INSTR NN_leaveq
// Is this instruction in the epilogue the one that deallocates the local
// vars region of the stack frame?
bool SMPInstr::MDIsFrameDeallocInstr(bool UseFP, asize_t LocalVarsSize) {
// The usual compiler idiom for the prologue on x86 is to
// deallocate the local var space with: mov esp,ebp
// It could be add esp,constant. We can be tricked by
// add esp,constant when the constant is just the stack
// adjustment after a call. We will have to insist that
// the immediate operand have at least the value of
// LocalVarsSize for this second form, and that UseFP be true
// for the first form.
set<DefOrUse, LessDefUse>::iterator FirstDef = this->GetFirstDef();
set<DefOrUse, LessDefUse>::iterator FirstUse = this->GetFirstUse();
if ((SMPcmd.itype >= MD_FIRST_LEAVE_INSTR) && (SMPcmd.itype <= MD_LAST_LEAVE_INSTR))
return true;
else if (this->HasDestMemoryOperand() || this->HasSourceMemoryOperand()) {
// Don't get fooled by USE or DEF entries of EBP or ESP that come
// from memory operands, e.g. mov eax,[ebp-20]
return false;
}
else if (UseFP && (this->SMPcmd.itype == NN_mov)
&& (FirstDef->GetOp().is_reg(R_sp))
&& (FirstUse->GetOp().is_reg(R_bp)))
return true;
else if ((this->SMPcmd.itype == NN_add)
&& (FirstDef->GetOp().is_reg(R_sp))) {
set<DefOrUse, LessDefUse>::iterator SecondUse = ++FirstUse;
if (SecondUse == this->Uses.GetLastRef())
return false; // no more USEs ... strange for ADD instruction
if (SecondUse->GetOp().is_imm((uval_t) LocalVarsSize))
return true;
else if (SecondUse->GetOp().type == o_imm) {
signed long TempImm = (signed long) this->SMPcmd.Operands[1].value;
if (0 > TempImm) // adding a negative to ESP; alloc, not dealloc
return false;
else {
clc5q
committed
SMP_msg("Used imprecise LocalVarsSize to find dealloc instr.\n");
return true;
}
}
else
return false;
}
else
return false;
} // end of SMPInstr::MDIsFrameDeallocInstr()
// Is instruction a no-op? There are 1-byte, 2-byte, etc., versions of no-ops.
bool SMPInstr::MDIsNop(void) const {
bool IsNop = false;
ushort opcode = this->SMPcmd.itype;
// NOTE: More examples have arisen, e.g. xchg reg with itself. !!!!!!
if (NN_nop == opcode)
IsNop = true;
else if (NN_mov == opcode) {
if ((o_reg == this->SMPcmd.Operands[0].type)
&& this->SMPcmd.Operands[1].is_reg(this->SMPcmd.Operands[0].reg)) {
// We have a register to register move with source == destination.
IsNop = true;
}
}
else if (NN_lea == opcode) {
if ((o_reg == this->SMPcmd.Operands[0].type)
&& (o_displ == this->SMPcmd.Operands[1].type)
&& (0 == this->SMPcmd.Operands[1].addr)) {
// We are looking for 6-byte no-ops like lea esi,[esi+0]
ushort destreg = this->SMPcmd.Operands[0].reg;
if ((this->SMPcmd.Operands[1].hasSIB)
&& (destreg == (ushort) sib_base(this->SMPcmd.Operands[1]))
&& (R_sp == sib_index(this->SMPcmd.Operands[1]))) {
// R_sp signifies no SIB index register. So, we have
// lea reg,[reg+0] with reg being the same in both place,
// once as Operands[0] and once as the base reg in Operands[1].
IsNop = true;
}
else if (destreg == this->SMPcmd.Operands[1].reg) {
IsNop = true;
}
}
}
return IsNop;
} // end of SMPInstr::MDIsNop()
// Opcode always produces an UNSIGNED DEF.
bool SMPInstr::MDAlwaysUnsignedDEF(void) const {
ushort opcode = this->SMPcmd.itype;
return ((opcode == NN_bsf) || (opcode == NN_bsr) || (opcode == NN_div)
|| (opcode == NN_lahf) || (opcode == NN_lar) || (opcode == NN_lgs)
|| (opcode == NN_lss) || (opcode == NN_lds) || (opcode == NN_les)
|| (opcode == NN_lfs) || (opcode == NN_lsl) || (opcode == NN_movzx)
|| (opcode == NN_rcl) || (opcode == NN_rcr) || (opcode == NN_rol)
|| (opcode == NN_ror) || (opcode == NN_shl) || (opcode == NN_shr)
|| ((opcode >= NN_seta) && (opcode <= NN_setz)) || (opcode == NN_cpuid)
|| (opcode == NN_rdtsc) || (opcode == NN_rdpmc) || (opcode == NN_fstsw)
|| (opcode == NN_setalc) || (opcode == NN_packuswb) || (opcode == NN_paddusb)
|| (opcode == NN_paddusw) || (opcode == NN_psllw) || (opcode == NN_pslld)
|| (opcode == NN_psllq) || (opcode == NN_psrlw) || (opcode == NN_psrld)
|| (opcode == NN_psrlq) || (opcode == NN_psubusb) || (opcode == NN_psubusw)
|| (opcode == NN_pxor) || (opcode == NN_pavgusb) || (opcode == NN_pavgb)
|| (opcode == NN_pavgw) || (opcode == NN_pextrw) || (opcode == NN_pmaxub)
|| ((opcode >= NN_pminub) && (opcode <= NN_psadbw))
|| (opcode == NN_movmskpd) || (opcode == NN_pmuludq) || (opcode == NN_pslldq)
|| (opcode == NN_psrldq) || ((opcode >= NN_pabsb) && (opcode <= NN_pabsd))
|| (opcode == NN_rdtscp) || (opcode == NN_mpsadbw) || (opcode == NN_packusdw)
|| ((opcode >= NN_pcmpeqq) && (opcode <= NN_phminposuw)) || (opcode == NN_pmaxud)
|| (opcode == NN_pmaxuw) || (opcode == NN_pminud) || (opcode == NN_pminuw)
|| ((opcode >= NN_pmovzxbw) && (opcode <= NN_pmovzxdq)) || ((opcode >= NN_crc32)
&& (opcode <= NN_pcmpistrm)) || (opcode == NN_popcnt) || (opcode == NN_lzcnt)
|| ((opcode >= NN_aesenc) && (opcode <= NN_aeskeygenassist)));
} // end of SMPInstr::MDAlwaysUnsignedDEF()
// Opcode always produces a SIGNED DEF.
bool SMPInstr::MDAlwaysSignedDEF(void) const {
ushort opcode = this->SMPcmd.itype;
return ((opcode == NN_cbw) || (opcode == NN_cwde) || (opcode == NN_cdqe)
|| (opcode == NN_cwd) || (opcode == NN_cdq) || (opcode == NN_cqo)
|| (opcode == NN_idiv) || (opcode == NN_movsx) || (opcode == NN_neg)
|| (opcode == NN_sal) || (opcode == NN_sar) || (opcode == NN_fist)
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
|| (opcode == NN_fistp) || (opcode == NN_fbstp) || (opcode == NN_packsswb)
|| (opcode == NN_packssdw) || (opcode == NN_paddsb) || (opcode == NN_paddsw)
|| (opcode == NN_pmaddwd) || (opcode == NN_pmulhw) || (opcode == NN_pmullw)
|| (opcode == NN_psraw) || (opcode == NN_psrad) || (opcode == NN_psubsb)
|| (opcode == NN_psubsw) || (opcode == NN_pfadd) || (opcode == NN_pfsub)
|| (opcode == NN_pfsubr) || (opcode == NN_pfacc) || (opcode == NN_pfmin)
|| (opcode == NN_pfmax) || (opcode == NN_pf2id) || (opcode == NN_pfrcp)
|| (opcode == NN_pfadd) || (opcode == NN_pfrsqrt) || (opcode == NN_pfmul)
|| (opcode == NN_pfrcpit1) || (opcode == NN_pfrsqit1) || (opcode == NN_pfrcpit2)
|| (opcode == NN_pmulhrw) || ((opcode >= NN_addps) && (opcode <= NN_andps))
|| ((opcode >= NN_cvtpi2ps) && (opcode <= NN_divss)) || ((opcode >= NN_maxps)
&& (opcode <= NN_movlps)) || ((opcode >= NN_movss) && (opcode <= NN_sqrtss))
|| (opcode == NN_subps) || (opcode == NN_subss) || (opcode == NN_unpckhps)
|| (opcode == NN_unpcklps) || (opcode == NN_pmaxsw) || (opcode == NN_pminsw)
|| (opcode == NN_movntps) || (opcode == NN_pf2iw) || (opcode == NN_pfnacc)
|| (opcode == NN_pfpnacc) || (opcode == NN_pi2fw) || ((opcode >= NN_addpd)
&& (opcode <= NN_andpd)) || ((opcode >= NN_cvtdq2pd) && (opcode <= NN_divsd))
|| (opcode == NN_maxpd) || (opcode == NN_maxsd) || ((opcode >= NN_minpd)
&& (opcode <= NN_movapd)) || (opcode == NN_movhpd) || (opcode == NN_movlpd)
|| (opcode == NN_movntpd) || ((opcode >= NN_movsd) && (opcode <= NN_orpd))
|| ((opcode >= NN_sqrtpd) && (opcode <= NN_subsd)) && ((opcode >= NN_unpckhpd)
&& (opcode <= NN_xorpd)) || ((opcode >= NN_movddup) && (opcode <= NN_movsxd))
|| ((opcode >= NN_addsubpd) && (opcode <= NN_hsubps)) || (opcode == NN_fisttp)
|| ((opcode >= NN_psignb) && (opcode <= NN_psignd)) || ((opcode >= NN_pmulhrsw)
&& (opcode <= NN_phsubd)) || (opcode == NN_pfrcpv) || (opcode == NN_pfrsqrtv)
|| ((opcode >= NN_blendpd) && (opcode <= NN_insertps)) || (opcode == NN_pmaxsb)
|| (opcode == NN_pmaxsd) || (opcode == NN_pminsb) || (opcode == NN_pminsd)
|| ((opcode >= NN_pmovsxbw) && (opcode <= NN_pmovsxdq)) || (opcode == NN_pmuldq)
|| (opcode == NN_pmulld) || ((opcode >= NN_roundpd) && (opcode <= NN_roundss))
|| (opcode == NN_movntsd) || (opcode == NN_movntss));
} // end of SMPInstr::MDAlwaysSignedDEF()
bool SMPInstr::MDIsAddition(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode));
}
// Is non-multiply arithmetic instruction that can possibly overflow?
bool SMPInstr::MDIsOverflowingOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode) || (NN_inc == opcode)
|| (NN_neg == opcode) || (NN_xadd == opcode));
}
// Is non-multiply arithmetic instruction that can possibly underflow?
bool SMPInstr::MDIsUnderflowingOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_dec == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}
clc5q
committed
// Is potentially benign overflow instruction?
bool SMPInstr::MDIsMaybeBenignOverflowOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_adc == opcode) || (NN_add == opcode));
}
// Is potentially benign underflow instruction?
bool SMPInstr::MDIsMaybeBenignUnderflowOpcode(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_neg == opcode) || (NN_sbb == opcode) || (NN_sub == opcode));
}
clc5q
committed
// Is definitely benign underflow instruction?
// NOTE: Overlaps with MDIsMaybeBenignUnderflowOpcode(), so call this one first.
bool SMPInstr::MDIsDefiniteBenignUnderflowOpcode(int &IdiomCode) {
clc5q
committed
unsigned short opcode = this->SMPcmd.itype;
// gcc use: sbb edx,edx as a tricky way to get all zeroes or all ones into edx.
clc5q
committed
// (Some sort of saturation? Often treated as 0 or -1, i.e. it becomes SIGNED
// even if it used to be UNSIGNED.)
clc5q
committed
// The "underflow" on the subtraction is irrelevant and benign.
bool benign = ((NN_sbb == opcode) && (this->SubtractsFromItself()));
if (benign) {
IdiomCode = 4;
}
return benign;
clc5q
committed
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
}
// Does a subtraction operator get applied to same left and right operands?
bool SMPInstr::SubtractsFromItself(void) {
bool SelfSubtract = false;
size_t RTLCount = this->RTL.GetCount();
for (size_t index = 0; index < RTLCount; ++index) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(index);
if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
if ((SMP_SUBTRACT_BORROW == CurrOp) || (SMP_SUBTRACT == CurrOp)) {
if (!(CurrRT->HasRightSubTree())) {
// NOTE: Must change this code when we build more precise SMP_SUBTRACT_BORROW RTL.
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
SelfSubtract = IsEqOp(RightOp, LeftOp);
}
break;
}
}
}
return SelfSubtract;
} // end of SMPInstr::SubtractsFromItself()
// Does instruction subtract an immediate value that is often used in ASCII computations,
// such as the ASCII code for '0', 'a', or 'A' ?
bool SMPInstr::SubtractsImmedASCII(void) {
return (this->MDIsMaybeBenignUnderflowOpcode() && (o_imm == this->AddSubSourceOp.type)
&& (('0' == this->AddSubSourceOp.value) || ('a' == this->AddSubSourceOp.value)
|| ('A' == this->AddSubSourceOp.value)));
}
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
// Does instruction compare a location to an immediate value that is often used in ASCII computations,
// such as the ASCII code for '0' or '9', 'a' or 'A', 'z' or 'Z', or carriage return?
#define SMP_ASCII_CARRIAGE_RETURN 13
bool SMPInstr::MDComparesImmedASCII(void) {
bool ComparesToASCII = false;
if (this->SMPcmd.itype == NN_cmp) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if ((CurrRT != NULL) && (CurrRT->HasRightSubTree())) {
CurrRT = CurrRT->GetRightTree();
if (!(CurrRT->HasRightSubTree())) {
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if ((o_imm == RightOp.type) && ((SMP_ASCII_CARRIAGE_RETURN == RightOp.value)
|| ('0' == RightOp.value) || ('9' == RightOp.value)
|| ('a' == RightOp.value) || ('z' == RightOp.value)
|| ('A' == RightOp.value) || ('Z' == RightOp.value))) {
ComparesToASCII = true;
}
}
}
}
return ComparesToASCII;
} // end of SMPInstr::MDComparesImmedASCII()
// Multiply by large constant; overflow is probably intentional.
#define STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD))
bool SMPInstr::IsMultiplyByLargeConstant(uval_t &ConstValue, unsigned short SignMask) {
bool LargeConstFound = false;
if (this->MDIsMultiply() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
set<DefOrUse, LessDefUse>::iterator UseIter;
for (UseIter = this->GetFirstUse(); UseIter != this->GetLastUse(); ++UseIter) {
if (this->FindConstantValue(UseIter, ConstValue)) {
if (FG_MASK_UNSIGNED == SignMask) {
if (((uval_t) STARS_LARGE_UNSIGNED_MUL_CONSTANT_THRESHOLD) <= ConstValue) {
LargeConstFound = true;
break;
}
}
else if (FG_MASK_SIGNED == SignMask) {
int SignedConstValue = (int) ConstValue;
if ( (((int) STARS_LARGE_SIGNED_MUL_CONSTANT_THRESHOLD) <= SignedConstValue)
|| (((int) STARS_SMALL_SIGNED_MUL_CONSTANT_THRESHOLD) >= SignedConstValue)) {
LargeConstFound = true;
break;
}
}
}
}
}
return LargeConstFound;
} // end of SMPInstr::IsMultiplyByLargeConstant()
// Subtraction of large constant; underflow is probably intentional.
#define STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD))
bool SMPInstr::IsSubtractionOfLargeConstant(uval_t &ConstValue, unsigned short SignMask) {
bool LargeConstFound = false;
if (this->MDIsUnderflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
op_t SubtrahendOp = this->AddSubSourceOp;
if (o_void != SubtrahendOp.type) {
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(SubtrahendOp);
if (this->FindConstantValue(UseIter, ConstValue)) {
if (FG_MASK_UNSIGNED == SignMask) {
if (((uval_t) STARS_LARGE_UNSIGNED_SUB_CONSTANT_THRESHOLD) <= ConstValue) {
LargeConstFound = true;
}
}
else if (FG_MASK_SIGNED == SignMask) {
int SignedConstValue = (int) ConstValue;
if ( (((int) STARS_LARGE_SIGNED_SUB_CONSTANT_THRESHOLD) <= SignedConstValue)
|| (((int) STARS_SMALL_SIGNED_SUB_CONSTANT_THRESHOLD) >= SignedConstValue)) {
LargeConstFound = true;
}
}
}
}
}
return LargeConstFound;
} // end of SMPInstr::IsSubtractionOfLargeConstant()
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
// Subtraction of large constant; underflow is probably intentional.
#define STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD 0x80000000
#define STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD 0x40000000
#define STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD ((int)(-STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD))
bool SMPInstr::IsAdditionOfLargeConstant(uval_t &ConstValue, unsigned short SignMask) {
bool LargeConstFound = false;
if (this->MDIsOverflowingOpcode() && (SignMask != FG_MASK_INCONSISTENT_SIGN) && (SignMask != 0)) {
op_t AddendOp = this->AddSubSourceOp;
if (o_void != AddendOp.type) {
set<DefOrUse, LessDefUse>::iterator UseIter = this->FindUse(AddendOp);
if (this->FindConstantValue(UseIter, ConstValue)) {
if (FG_MASK_UNSIGNED == SignMask) {
if (((uval_t) STARS_LARGE_UNSIGNED_ADD_CONSTANT_THRESHOLD) <= ConstValue) {
LargeConstFound = true;
}
}
else if (FG_MASK_SIGNED == SignMask) {
int SignedConstValue = (int) ConstValue;
if ( (((int) STARS_LARGE_SIGNED_ADD_CONSTANT_THRESHOLD) <= SignedConstValue)
|| (((int) STARS_SMALL_SIGNED_ADD_CONSTANT_THRESHOLD) >= SignedConstValue)) {
LargeConstFound = true;
}
}
}
}
}
return LargeConstFound;
} // end of SMPInstr::IsAdditionOfLargeConstant()
// MACHINE DEPENDENT: Is instruction a return instruction?
bool SMPInstr::MDIsReturnInstr(void) const {
return ((this->SMPcmd.itype == NN_retn) || (this->SMPcmd.itype == NN_retf));
}
// MACHINE DEPENDENT: Is instruction a POP instruction?
#define FIRST_POP_INST NN_pop
#define LAST_POP_INST NN_popfq
bool SMPInstr::MDIsPopInstr(void) const {
return ((this->SMPcmd.itype >= FIRST_POP_INST)
&& (this->SMPcmd.itype <= LAST_POP_INST));
}
// MACHINE DEPENDENT: Is instruction a PUSH instruction?
#define FIRST_PUSH_INST NN_push
#define LAST_PUSH_INST NN_pushfq
bool SMPInstr::MDIsPushInstr(void) const {
return ((this->SMPcmd.itype >= FIRST_PUSH_INST)
&& (this->SMPcmd.itype <= LAST_PUSH_INST));
}
// MACHINE DEPENDENT: Is instruction an ENTER instruction?
bool SMPInstr::MDIsEnterInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_ENTER_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_ENTER_INSTR));
}
// MACHINE DEPENDENT: Is instruction a LEAVE instruction?
bool SMPInstr::MDIsLeaveInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_LEAVE_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_LEAVE_INSTR));
// MACHINE DEPENDENT: Is instruction a HALT instruction?
bool SMPInstr::MDIsHaltInstr(void) const {
return (NN_hlt == this->SMPcmd.itype);
}
#define MD_FIRST_COND_MOVE_INSTR NN_cmova
#define MD_LAST_COND_MOVE_INSTR NN_fcmovnu
// MACHINE DEPENDENT: Is instruction a conditional move?
bool SMPInstr::MDIsConditionalMoveInstr(void) const {
return ((this->SMPcmd.itype >= MD_FIRST_COND_MOVE_INSTR)
&& (this->SMPcmd.itype <= MD_LAST_COND_MOVE_INSTR));
}
clc5q
committed
// MACHINE DEPENDENT: Is instruction any kind of move?
bool SMPInstr::MDIsMoveInstr(void) const {
return ((NN_mov == this->SMPcmd.itype) || (NN_movsx == this->SMPcmd.itype)
|| (NN_movzx == this->SMPcmd.itype) || this->MDIsConditionalMoveInstr());
}
// MACHINE DEPENDENT: Do opcode/operands definitely indicate signed arithmetic?
// Generally, this is only true for certain variants of multiplication and division.
bool SMPInstr::MDIsSignedArithmetic(void) const {
unsigned short opcode = this->SMPcmd.itype;
if (NN_idiv == opcode)
return true;
if (NN_imul == opcode) {
// If we discard the upper N bits of the multiplication result, then the
// lower N bits are the same for signed and unsigned multiplication, and
// gcc/g++ often use the IMUL opcode for both signed and unsigned multiplies
// when only N bits of result are retained. Therefore, the SIGNED nature of
// IMUL operands can only be inferred from the case in which 2N bits are kept.
return (!(this->AreMultiplicationBitsDiscarded()));
}
else { // idiv and imul are only possible signed cases
return false;
}
} // end of SMPInstr::MDIsSignedArithmetic()
// MACHINE DEPENDENT: Is instruction a conditional jump based on an unsigned condition?
bool SMPInstr::MDIsUnsignedBranch(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_ja == opcode) || (NN_jae == opcode) || (NN_jb == opcode) || (NN_jbe == opcode)
|| (NN_jna == opcode) || (NN_jnae == opcode) || (NN_jnb == opcode) || (NN_jnbe == opcode));
}
// MACHINE DEPENDENT: Is instruction a conditional jump based on a signed condition?
bool SMPInstr::MDIsSignedBranch(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_jg == opcode) || (NN_jge == opcode) || (NN_jl == opcode) || (NN_jle == opcode)
|| (NN_jng == opcode) || (NN_jnge == opcode) || (NN_jnl == opcode) || (NN_jnle == opcode)
|| (NN_js == opcode) || (NN_jns == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on an unsigned condition?
bool SMPInstr::MDIsUnsignedSetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_seta == opcode) || (NN_setae == opcode) || (NN_setb == opcode) || (NN_setbe == opcode)
|| (NN_setna == opcode) || (NN_setnae == opcode) || (NN_setnb == opcode) || (NN_setnbe == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on a signed condition?
bool SMPInstr::MDIsSignedSetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_setg == opcode) || (NN_setge == opcode) || (NN_setl == opcode) || (NN_setle == opcode)
|| (NN_setng == opcode) || (NN_setnge == opcode) || (NN_setnl == opcode) || (NN_setnle == opcode)
|| (NN_sets == opcode) || (NN_setns == opcode));
}
// MACHINE DEPENDENT: Is instruction a boolean set based on any condition?
bool SMPInstr::MDIsAnySetValue(void) const {
unsigned short opcode = this->SMPcmd.itype;
return ((NN_seta <= opcode) && (NN_setz >= opcode));
}
// Is kind of shift or rotate that is used in hash functions
#define STARS_HASH_SHIFT_THRESHOLD 4
bool SMPInstr::MDIsHashingArithmetic(void) const {
bool FoundHashShift = false;
unsigned short opcode = this->SMPcmd.itype;
// We are looking for shifts or rotates in the leftward direction.
if ((opcode == NN_rcl) || (opcode == NN_rol) || (opcode == NN_shl) || (opcode == NN_shld)) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
op_t ShiftCountOp = CurrRT->GetRightOperand();
if (o_imm == ShiftCountOp.type) {
uval_t CountValue = ShiftCountOp.value;
FoundHashShift = (CountValue >= STARS_HASH_SHIFT_THRESHOLD);
}
}
return FoundHashShift;
} // end of SMPInstr::MDIsHashingArithmetic()
clc5q
committed
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
// Detect comparison of non-immediate to immediate. Return the two operands if true.
bool SMPInstr::MDIsCompareToPositiveConstant(op_t &NonConstOperand, uval_t &ConstValue) const {
bool CompareToConst = false;
if (NN_cmp == this->SMPcmd.itype) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
assert(CurrRT->HasRightSubTree());
CurrRT = CurrRT->GetRightTree();
assert(!(CurrRT->HasRightSubTree()));
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
CompareToConst = true;
ConstValue = RightOp.value;
NonConstOperand = LeftOp;
}
else if (o_imm == LeftOp.type) { // rare to see immediate first
CompareToConst = true;
ConstValue = LeftOp.value;
NonConstOperand = RightOp;
}
}
return CompareToConst;
} // end of SMPInstr::MDIsCompareToPositiveConstant()
bool SMPInstr::MDIsSubtractionOfConstant(op_t &NonConstOperand, uval_t &ConstValue) const {
bool SubtractOfConst = false;
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if (CurrRT->HasRightSubTree()) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
if (SMP_SUBTRACT == CurrOp) {
assert(!(CurrRT->HasRightSubTree()));
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
SubtractOfConst = true;
ConstValue = RightOp.value;
NonConstOperand = LeftOp;
}
}
clc5q
committed
else if (this->MDIsLoadEffectiveAddressInstr() && (SMP_ADD == CurrOp)) {
// We could have an addition of a negative constant via an lea opcode,
// e.g. lea ecx,[eax-48] will look like ecx := eax+(-48) in the RTL.
if (!(CurrRT->HasRightSubTree())) {
op_t LeftOp = CurrRT->GetLeftOperand();
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
ConstValue = RightOp.value;
int SignedConstValue = (int) ConstValue;
if (0 > SignedConstValue) {
SubtractOfConst = true;
NonConstOperand = LeftOp;
ConstValue = (uval_t)(-SignedConstValue); // make +(-x) into -(+x)
}
}
}
}
clc5q
committed
}
return SubtractOfConst;
} // end of SMPInstr::MDIsSubtractionOfConstant()
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
// is AND operation that masks off lower BytesMasked bytes
bool SMPInstr::MDIsSubregMaskInst(size_t &BytesMasked) {
bool MaskingFound = false;
if (this->MDIsBitwiseAndOpcode()) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(0);
if (CurrRT->HasRightSubTree()) {
CurrRT = CurrRT->GetRightTree();
SMPoperator CurrOp = CurrRT->GetOperator();
assert(SMP_BITWISE_AND == CurrOp);
op_t RightOp = CurrRT->GetRightOperand();
if (o_imm == RightOp.type) {
uval_t MaskValue = RightOp.value;
if (0x01000000 > MaskValue) {
MaskingFound = true;
if (0x100 > MaskValue) {
BytesMasked = 1;
}
else if (0x10000 > MaskValue) {
BytesMasked = 2;
}
else {
BytesMasked = 3;
}
}
}
}
}
return MaskingFound;
}
// MACHINE DEPENDENT: Does instruction use a callee-saved register?
bool SMPInstr::MDUsesCalleeSavedReg(void) {
set<DefOrUse, LessDefUse>::iterator CurrUse;
for (CurrUse = this->GetFirstUse(); CurrUse != this->GetLastUse(); ++CurrUse) {
op_t CurrOp = CurrUse->GetOp();
if (CurrOp.is_reg(R_bp) || CurrOp.is_reg(R_si)
|| CurrOp.is_reg(R_di) || CurrOp.is_reg(R_bx)) {
return true;
}
}
return false;
} // end of SMPInstr::MDUsesCalleeSavedReg()
// Is the instruction a register to register copy of a stack pointer or frame pointer
// into a general purpose register (which mmStrata will now need to track as a stack
// relative pointer)?
bool SMPInstr::MDIsStackPointerCopy(bool UseFP) {
// OptType 3 indicates a move instruction
// The lea instruction can perform three operand arithmetic, e.g.
// lea ebx,[esp+12] is just ebx:=esp+12, so it is a stack pointer copy.
if (((this->OptType == 3) || (NN_lea == this->SMPcmd.itype))
&& (this->GetFirstDef()->GetOp().type == o_reg)
&& (!(this->GetFirstDef()->GetOp().is_reg(R_sp)))
&& (!(this->HasSourceMemoryOperand()))) { // reg to reg move
if (this->GetFirstUse()->GetOp().is_reg(R_bp))
// Move of base pointer EBP into a general register
return true;
else if ((this->GetFirstUse()->GetOp().is_reg(R_sp))
&& !(this->GetFirstDef()->GetOp().is_reg(R_bp)))
// Move of ESP into something besides a base pointer
return true;
}
else if (this->GetFirstUse()->GetOp().is_reg(R_sp)) {
// Move of ESP into a register; no base pointer used in this function
return true;
}
}
return false;
} // end of SMPInstr::MDIsStackPointerCopy()
// Does any RTL fit the alloca() pattern: stack_pointer -= non-immediate-operand
bool SMPInstr::HasAllocaRTL(void) {
bool FoundAlloca = false;
size_t RTLCount = this->RTL.GetCount();
size_t RTLIndex;
for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
if (CurrRT->IsAllocaRTL()) {
FoundAlloca = true;
break;
}
}
return FoundAlloca;
} // end of SMPInstr::HasAllocaRTL()
// Determine if the instruction saves or restores a pointer into the stack frame.
// If it saves a stack pointer, set Save to true, set the StackDelta saved, and set
// the operand that received the saved stack pointer into CopyOp. and return true.
// If it restores a stack pointer, set Save to false, set CopyOp to the operand that
// held the value being restored, set RestoreOp to the stack pointer or frame pointer
// register (whichever was restored), leave StackDelta alone for later computation
// based on reaching definitions, and return true.
// For most instructions, no save or restore of a stack pointer, so return false.
bool SMPInstr::MDIsStackPtrSaveOrRestore(bool UseFP, sval_t FPDelta, bool &Save, sval_t &StackDelta, op_t &CopyOp, bool &Error) {
bool StackPointerSaveOrRestore;
size_t RTLCount = this->RTL.GetCount();
size_t RTLIndex;
int BaseReg, IndexReg, CopyReg;
ushort Scale;
ea_t offset;
SMPoperator CurrOper;
bool LookUpStackDelta; // Get stack delta from reaching defs for TempOp
sval_t DeltaAdjust; // add to StackDelta after computing from reaching defs, e.g. lea esp,[ecx-4] get TempOp of ecx
// and DeltaAdjust of -4
Error = false;
for (RTLIndex = 0; RTLIndex < RTLCount; ++RTLIndex) {
bool FPRestore = false; // frame pointer is restored
bool SPRestore = false; // stack pointer is restored
StackPointerSaveOrRestore = false; // default unless we detect a save or restore of the stack or frame pointer
TempOp = InitOp;
LookUpStackDelta = false;
DeltaAdjust = 0;
Save = false; // default unless we detect a stack pointer save
// The stack alignment instructions (SP := SP bitwise_and immediate_value)
// look like something that needs to be processed here, but we always ignore
// these instructions. They have a variable effect on the stack pointer, from zero
// to -15 delta, but we assume that the delta is zero. This works for us because
// no stack accesses will occur into the padding region.
// Also, any instruction that definitely does not restore the stack pointer or
// frame pointer from an arbitrary register or memory location, e.g. a leave instruction
// in x86 CPUs, is already handled in normal stack delta computations and needs
// no lookups from reaching defs, etc.
if (this->IsStackAlignmentInst() || this->MDIsLeaveInstr() || this->MDIsFrameAllocInstr()) {
break; // exit and return false
}
SMPRegTransfer *CurrRT = this->RTL.GetRT(RTLIndex);
CurrOper = CurrRT->GetOperator();
if (SMP_ASSIGN != CurrOper) {
break; // not a regular RTL
}
op_t LeftOp = CurrRT->GetLeftOperand();
if (LeftOp.is_reg(MD_STACK_POINTER_REG)) {
SPRestore = true; // temporary; might just be a push or pop RTL, etc., in which case we will reset.
}
else if (UseFP && LeftOp.is_reg(MD_FRAME_POINTER_REG)) {
FPRestore = true; // likewise temporary
}
if (!(SPRestore || FPRestore)) {
#if 0
if (LeftOp.is_reg(MD_FLAGS_REG)) {
break; // No point in looking for a save into the flags register
}
#endif
clc5q
committed
Save = true; // Maybe; keep looking for save
// If we are assigning to the stack pointer reg or the frame pointer reg, we need to analyze the right
// hand side of the RTL to see if it is a stack/frame pointer value, and not a simple push, pop, etc.
if (!(CurrRT->HasRightSubTree())) {
// Simple assignment.
op_t RightOp = CurrRT->GetRightOperand();
if ((o_reg <= RightOp.type) && (o_displ >= RightOp.type)) { // register or memory
if (RightOp.is_reg(MD_STACK_POINTER_REG)) {
// Stack pointer reg is being saved.
StackDelta = this->GetStackPtrOffset(); // LeftOp := SP, so saved delta is just current delta
CopyOp = LeftOp;
StackPointerSaveOrRestore = true;
FPRestore = false; // treat FP := SP as a save of SP rather than a restoration of FP
else if (!SPRestore && UseFP && RightOp.is_reg(MD_FRAME_POINTER_REG)) {
// Frame pointer is being saved
StackDelta = FPDelta;
CopyOp = LeftOp;
StackPointerSaveOrRestore = true;
break;
}
else if (SPRestore || FPRestore) {
// stack or frame pointer is being restored; leave Save=false and set other outgoing arguments.
TempOp = RightOp;
CopyOp = RightOp;
StackPointerSaveOrRestore = true;
LookUpStackDelta = true;
}
else { // RightOp is register or non-stack-pointer memory expr; either might hold stack delta
TempOp = RightOp;
CopyOp = LeftOp;
LookUpStackDelta = true; // See if RightOp is holding a stack delta
clc5q
committed
StackPointerSaveOrRestore = true; // Maybe; flag tells us to keep looking
}
}
else {
if (SPRestore || FPRestore) {
SMP_msg("ERROR: Invalid operand type for assignment to stack or frame pointer at %x\n", this->GetAddr());
}
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
StackPointerSaveOrRestore = false;
break;
}
}
else { // we have a right subtree in the CurrRT
SMPRegTransfer *RightRT = CurrRT->GetRightTree();
// In order to have a right subtree, we must have something like:
// lea esp,[ecx-4] which produces the RTL: esp := ecx - 4
// We should consider any other RTL structure besides a basic addition or
// subtraction on the right subtree to be invalid.
CurrOper = RightRT->GetOperator();
if ((SMP_ADD == CurrOper) || (SMP_SUBTRACT == CurrOper)) {
op_t RightLeftOp = RightRT->GetLeftOperand();
if (o_reg == RightLeftOp.type) {
if (RightRT->HasRightSubTree()) {
// Complex RTL such as lea esp,[ebx+ecx*4] ; cannot analyze
StackPointerSaveOrRestore = false;
}
else {
op_t RightRightOp = RightRT->GetRightOperand();
if (o_imm != RightRightOp.type) {
// Complex RTL such as lea esp,[ebx+ecx] ; cannot analyze
StackPointerSaveOrRestore = false;
}
else {
TempOp = RightLeftOp;
DeltaAdjust = (sval_t) RightRightOp.value;
if (SMP_SUBTRACT == CurrOper) {
// Negate the stack delta adjustment, e.g. lea esp,[ecx-4] needs DeltaAdjust of -4, not 4.
DeltaAdjust = (0 - DeltaAdjust);
}
LookUpStackDelta = true;
StackPointerSaveOrRestore = true;
if (SPRestore || FPRestore) {
CopyOp = RightLeftOp;
}
else {
CopyOp = LeftOp;
}
}
}
}
else { // weird RTL; LeftOp := (MemoryOp OPER ???)
StackPointerSaveOrRestore = false;
}
}
else { // not ADD or SUBTRACT
StackPointerSaveOrRestore = false;
}
}
if (LookUpStackDelta) {
bool StackAccess = false;
clc5q
committed
bool NonStackMemAccess = false;
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
// We need to set StackDelta based on the reaching defs for TempOp
// A reg is probably a general register, but could have lea ebx,[esp+4] so it could be stack or frame pointer.
if (TempOp.is_reg(MD_STACK_POINTER_REG)) {
// Weed out RTs that increment or decrement the stack pointer, e.g. SP := SP -4.
// These are not the kind of "save" or "restore" RTs that we are tracking.
if (CopyOp.is_reg(MD_STACK_POINTER_REG)) {
StackPointerSaveOrRestore = false;
SPRestore = false;
FPRestore = false;
Save = false;
}
else {
StackDelta = this->GetStackPtrOffset();
StackDelta += DeltaAdjust;
LookUpStackDelta = false; // just got it; no need for reaching defs
StackPointerSaveOrRestore = true;
}
}
else if (UseFP && TempOp.is_reg(MD_FRAME_POINTER_REG)) {
StackDelta = FPDelta;
StackDelta += DeltaAdjust;
LookUpStackDelta = false; // just got it; no need for reaching defs
StackPointerSaveOrRestore = true;
else if (o_reg == TempOp.type) { // general reg, not frame or stack pointer reg
CopyReg = TempOp.reg;
MDExtractAddressFields(TempOp, BaseReg, IndexReg, Scale, offset);
CopyReg = BaseReg;
bool IndexedAccess = ((R_none != BaseReg) && (R_none != IndexReg));
if (IndexedAccess) {
StackPointerSaveOrRestore = false; // Cannot analyze indexed accesses into the stack
}
else if (MDIsStackPtrReg(BaseReg, UseFP)) {
StackAccess = true;
}
else {
// memory expr that is not stack or frame pointer
clc5q
committed
NonStackMemAccess = true; // something like [ecx] might actually turn out to be stack access
DeltaAdjust = (sval_t) TempOp.addr; // get normalized delta from addr field
}
if (StackPointerSaveOrRestore && LookUpStackDelta) {
op_t FindOp = InitOp;
if (StackAccess) {
FindOp = TempOp;
}
else {
FindOp.type = o_reg;
FindOp.reg = CopyReg;
}
if (this->GetBlock()->GetFunc()->IsInStackPtrCopySet(FindOp)) {
// Screened out time wasters that are not in copy set; now,
// look up reaching defs.
// We need to find out which are the reaching definitions for the FindOp at the current InstAddr.
this->GetBlock()->GetFunc()->ComputeTempReachingDefs(FindOp, this->GetAddr());
this->GetBlock()->GetFunc()->ComputeTempStackDeltaReachesList(FindOp);
// See if TempStackDeltaReachesList has a consistent delta value.
StackPointerSaveOrRestore = this->GetBlock()->GetFunc()->FindReachingStackDelta(StackDelta); // consistent SavedDelta value across entire list
StackDelta += DeltaAdjust;
clc5q
committed
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
if (StackPointerSaveOrRestore && NonStackMemAccess) {
// We have something like [ecx] or [ecx+DeltaAdjust]. It turns out that
// ECX has a copy of the stack pointer or frame pointer in it, but that
// does not mean that the memory location [ecx] has a copy of a stack or
// frame pointer. We need to look up the normalized stack address [esp+StackDelta]
// in the StackPtrCopySet just like we did for ECX before we conclude that a
// stack pointer save or restore is happening.
FindOp = InitOp;
FindOp.type = o_displ;
FindOp.reg = MD_STACK_POINTER_REG;
FindOp.addr = StackDelta;
if (this->GetBlock()->GetFunc()->IsInStackPtrCopySet(FindOp)) {
// Screened out time wasters that are not in copy set; now,
// look up reaching defs.
// We need to find out which are the reaching definitions for the FindOp at the current InstAddr.
this->GetBlock()->GetFunc()->ComputeTempReachingDefs(FindOp, this->GetAddr());
this->GetBlock()->GetFunc()->ComputeTempStackDeltaReachesList(FindOp);
// See if TempStackDeltaReachesList has a consistent delta value.
StackPointerSaveOrRestore = this->GetBlock()->GetFunc()->FindReachingStackDelta(StackDelta); // consistent SavedDelta value across entire list
// StackPointerSaveOrRestore will now be true only if [ecx] pointed to a saved stack or frame pointer with consistent delta.
}
else {
// E.g. [ecx] pointed to stack location that was not holding a saved stack or frame pointer.
StackPointerSaveOrRestore = false;
}
}
}
else {
StackPointerSaveOrRestore = false; // reset, not in stack pointer copy set
}
} // end if (LookupStackDelta)
if (!StackPointerSaveOrRestore && !Save && (SPRestore || FPRestore)) {
// Any restore that could not be analyzed is an error.
Error = true;
break; // error exit
}
else if (StackPointerSaveOrRestore) {
if (FPRestore) {
// If we succeeded in looking up a stack delta that goes into the frame pointer reg,
// then we want to consider this instruction to be a save of a stack delta into
// a register (which happens to be the frame pointer reg in this case).
FPRestore = false;
Save = true;
break; // assume only one save or restore in an instruction; exit with success
} // end for all RTs in the RTL
return StackPointerSaveOrRestore;
} // end of SMPInstr::MDIsStackPtrSaveOrRestore()
// If call instruction is to malloc(), set the DEF register EAX type to
// HEAPPTR and return true.
bool SMPInstr::MDFindMallocCall(op_t TargetOp) {
bool changed = false;
func_t *TargetFunc = get_func(TargetOp.addr);
if (TargetFunc) {
char FuncName[MAXSTR];
get_func_name(TargetFunc->startEA, FuncName, sizeof(FuncName) - 1);
if (0 == strcmp("malloc", FuncName)) {
// NOTE: Some compilers might call it __malloc ; make this more robust !!!
#if SMP_VERBOSE_FIND_POINTERS
clc5q
committed
SMP_msg("Found call to malloc at %x\n", this->addr);
#endif
op_t SearchOp = InitOp;
SearchOp.type = o_reg;
SearchOp.reg = R_ax;
set<DefOrUse, LessDefUse>::iterator EAXDEF;
EAXDEF = this->SetDefType(SearchOp, HEAPPTR);
int SSANum = EAXDEF->GetSSANum();
changed = true;