Newer
Older
// This module contains common types an helper classes needed for the
#include <vector>
#include <algorithm>
#include <cstring>
#include <ida.hpp>
#include <idp.hpp>
#include <allins.hpp>
#include <auto.hpp>
#include <bytes.hpp>
#include <funcs.hpp>
#include <intel.hpp>
#include <loader.hpp>
#include <lines.hpp>
#include <name.hpp>
#include "SMPDataFlowAnalysis.h"
#include "SMPStaticAnalyzer.h"
// Set to 1 for debugging output
#define SMP_DEBUG 1
#define SMP_DEBUG2 0 // verbose
#define SMP_DEBUG3 0 // verbose
#define SMP_DEBUG_CONTROLFLOW 0 // tells what processing stage is entered
#define SMP_DEBUG_XOR 0
#define SMP_DEBUG_CHUNKS 1 // tracking down tail chunks for functions
#define SMP_DEBUG_FRAMEFIXUP 0
#define SMP_DEBUG_OPERAND_TYPES 1
// Compute LVA/SSA or not? Turn it off for NICECAP demo on 31-JAN-2008
#define SMP_COMPUTE_LVA_SSA 0
char *RegNames[R_of + 1] =
{ "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI",
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH",
"SPL", "BPL", "SIL", "DIL", "EIP", "ES", "CS", "SS",
"DS", "FS", "GS", "CF", "ZF", "SF", "OF"
};
SMPitype DFACategory[NN_last+1];
// Define instruction categories for data type analysis.
int SMPTypeCategory[NN_last+1];
// Define which instructions define and use the CPU flags.
bool SMPDefsFlags[NN_last + 1];
bool SMPUsesFlags[NN_last + 1];
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Get the size in bytes of the data type of an operand.
size_t GetOpDataSize(op_t DataOp) {
size_t DataSize;
switch (DataOp.dtyp) {
case dt_byte:
DataSize = 1;
break;
case dt_word:
DataSize = 2;
break;
case dt_dword:
case dt_float:
case dt_code:
case dt_unicode:
case dt_string:
DataSize = 4;
break;
case dt_double:
case dt_qword:
DataSize = 8;
break;
case dt_packreal:
DataSize = 12;
break;
case dt_byte16:
DataSize = 16;
break;
case dt_fword:
DataSize = 6;
break;
case dt_3byte:
DataSize = 3;
break;
default:
msg("WARNING: unexpected data type %d in GetOpDataSize() :", DataOp.dtyp);
PrintOperand(DataOp);
msg("\n");
DataSize = 4;
break;
}
return DataSize;
} // end of GetOpDataSize()
// We need to make subword registers equal to their containing registers when we
// do comparisons, so that we will realize that register EAX is killed by a prior DEF
// of register AL, for example, and vice versa. To keep sets ordered strictly,
// we also have to make AL and AH be equal to each other as well as equal to EAX.
#define FIRST_x86_SUBWORD_REG R_al
#define LAST_x86_SUBWORD_REG R_bh
bool MDLessReg(const ushort Reg1, const ushort Reg2) {
bool FirstSubword = ((Reg1 >= FIRST_x86_SUBWORD_REG) && (Reg1 <= LAST_x86_SUBWORD_REG));
bool SecondSubword = ((Reg2 >= FIRST_x86_SUBWORD_REG) && (Reg2 <= LAST_x86_SUBWORD_REG));
ushort SReg1 = Reg1;
ushort SReg2 = Reg2;
if (FirstSubword) {
// See enumeration RegNo in intel.hpp.
if (SReg1 < 20) // AL, CL, DL or BL
SReg1 -= 16;
else // AH, CH, DH or BH
SReg1 -= 20;
}
if (SecondSubword) {
if (SReg2 < 20)
SReg2 -= 16;
else
SReg2 -= 20;
return (SReg1 < SReg2);
} // end of MDLessReg()
// In SSA computations, we are storing the GlobalNames index into the op_t fields
// n, offb, and offo. This function extracts an unsigned int from these three 8-bit
// fields.
unsigned int ExtractGlobalIndex(op_t GlobalOp) {
unsigned int index = 0;
index |= (((unsigned int) GlobalOp.offo) & 0x000000ff);
index <<= 8;
index |= (((unsigned int) GlobalOp.offb) & 0x000000ff);
index <<= 8;
index |= (((unsigned int) GlobalOp.n) & 0x000000ff);
void SetGlobalIndex(op_t *TempOp, size_t index) {
TempOp->n = (char) (index & 0x000000ff);
TempOp->offb = (char) ((index & 0x0000ff00) >> 8);
TempOp->offo = (char) ((index & 0x00ff0000) >> 16);
return;
}
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// DEBUG Print DEF and/or USE for an operand.
void PrintDefUse(ulong feature, int OpNum) {
// CF_ macros number the operands from 1 to 6, while OpNum
// is a 0 to 5 index into the insn_t.Operands[] array.
// OpNum == -1 is a signal that this is a DEF or USE or VarKillSet etc.
// operand and not an instruction operand.
if (-1 == OpNum)
return;
switch (OpNum) {
case 0:
if (feature & CF_CHG1)
msg(" DEF");
if (feature & CF_USE1)
msg(" USE");
break;
case 1:
if (feature & CF_CHG2)
msg(" DEF");
if (feature & CF_USE2)
msg(" USE");
break;
case 2:
if (feature & CF_CHG3)
msg(" DEF");
if (feature & CF_USE3)
msg(" USE");
break;
case 3:
if (feature & CF_CHG4)
msg(" DEF");
if (feature & CF_USE4)
msg(" USE");
break;
case 4:
if (feature & CF_CHG5)
msg(" DEF");
if (feature & CF_USE5)
msg(" USE");
break;
case 5:
if (feature & CF_CHG6)
msg(" DEF");
if (feature & CF_USE6)
msg(" USE");
break;
}
return;
} // end PrintDefUse()
// DEBUG print SIB info for an operand.
void PrintSIB(op_t Opnd) {
int BaseReg = sib_base(Opnd);
short IndexReg = sib_index(Opnd);
int ScaleFactor = sib_scale(Opnd);
#define NAME_LEN 5
char BaseName[NAME_LEN] = {'N', 'o', 'n', 'e', '\0'};
char IndexName[NAME_LEN] = {'N', 'o', 'n', 'e', '\0'};
#if 1
if (!((BaseReg == R_bp) && (Opnd.type == o_mem))) // EBP can be SIB code for NO BASE REG
#endif
qstrncpy(BaseName, RegNames[BaseReg], NAME_LEN - 1);
if (IndexReg != R_sp) { // SIB code for NO INDEX REG
qstrncpy(IndexName, RegNames[IndexReg], NAME_LEN -1);
}
msg(" Base %s Index %s Scale %d", BaseName, IndexName, ScaleFactor);
} // end PrintSIB()
// Debug: print one operand from an instruction or DEF or USE list.
void PrintOneOperand(op_t Opnd, ulong features, int OpNum) {
if (Opnd.type != o_void) {
PrintOperand(Opnd);
PrintDefUse(features, OpNum);
}
return;
} // end of PrintOneOperand()
// Debug: print one operand.
void PrintOperand(op_t Opnd) {
if (Opnd.type == o_void)
return;
else if (Opnd.type == o_mem) {
msg(" Operand: memory : addr: %x", Opnd.addr);
PrintSIB(Opnd);
}
}
else if (Opnd.type == o_phrase) {
if (Opnd.hasSIB) { // has SIB info
PrintSIB(Opnd);
}
else { // no SIB info
ushort BaseReg = Opnd.phrase;
msg(" reg %s", RegNames[BaseReg]);
}
if (Opnd.addr != 0) {
msg(" \n WARNING: addr for o_phrase type: %d\n", Opnd.addr);
}
}
else if (Opnd.type == o_displ) {
ea_t offset = Opnd.addr;
if (Opnd.hasSIB) {
PrintSIB(Opnd);
msg(" displ %d", offset);
}
else {
ushort BaseReg = Opnd.reg;
msg(" reg %s displ %d", RegNames[BaseReg], offset);
}
}
else if (Opnd.type == o_reg) {
msg(" Operand: register %s", RegNames[Opnd.reg]);
}
else if (Opnd.type == o_imm) {
msg(" Operand: immed %d", Opnd.value);
}
else if (Opnd.type == o_far) {
msg(" Operand: FarPtrImmed addr: %x", Opnd.addr);
}
else if (Opnd.type == o_near) {
msg(" Operand: NearPtrImmed addr: %x", Opnd.addr);
else if (Opnd.type == o_trreg) {
msg(" Operand: TaskReg reg: %d", Opnd.reg);
else if (Opnd.type == o_dbreg) {
msg(" Operand: DebugReg reg: %d", Opnd.reg);
else if (Opnd.type == o_crreg) {
msg(" Operand: ControlReg reg: %d", Opnd.reg);
else if (Opnd.type == o_fpreg) {
msg(" Operand: FloatReg reg: %d", Opnd.reg);
else if (Opnd.type == o_mmxreg) {
msg(" Operand: MMXReg reg: %d", Opnd.reg);
else if (Opnd.type == o_xmmreg) {
msg(" Operand: XMMReg reg: %d", Opnd.reg);
}
if (!(Opnd.showed()))
msg(" HIDDEN ");
return;
} // end of PrintOperand()
// Print an operand that has no features flags or operand position number, such
// as the op_t types found in lists and sets throughout the blocks, phi functions, etc.
void PrintListOperand(op_t Opnd, int SSANum) {
if (Opnd.type != o_void) {
PrintOperand(Opnd);
msg(" SSANum: %d ", SSANum);
}
return;
} // end of PrintListOperand()
// MACHINE DEPENDENT: Is operand type a known type that we want to analyze?
bool MDKnownOperandType(op_t TempOp) {
bool GoodOpType = ((TempOp.type >= o_reg) && (TempOp.type <= o_xmmreg));
#if SMP_DEBUG_OPERAND_TYPES
if (!GoodOpType && (o_void != TempOp.type)) {
msg("WARNING: Operand type %d \n", TempOp.type);
}
#endif
return GoodOpType;
// *****************************************************************
// Class DefOrUse
// *****************************************************************
// Default constructor to make the compilers happy.
DefOrUse::DefOrUse(void) {
this->OpType = UNINIT;
this->SSANumber = -2;
return;
}
// Constructor.
DefOrUse::DefOrUse(op_t Ref, SMPOperandType Type, int SSASub) {
this->Operand = Ref;
this->OpType = Type;
this->SSANumber = SSASub;
return;
}
// Copy constructor.
DefOrUse::DefOrUse(const DefOrUse &CopyIn) {
*this = CopyIn;
return;
}
// Assignment operator for copy constructor use.
DefOrUse &DefOrUse::operator=(const DefOrUse &rhs) {
this->Operand = rhs.Operand;
this->OpType = rhs.OpType;
this->SSANumber = rhs.SSANumber;
return *this;
}
// Debug printing.
void DefOrUse::Dump(void) const {
PrintListOperand(this->Operand, this->SSANumber);
if (this->OpType == NUMERIC)
msg("N ");
else if (this->OpType == CODEPTR)
msg("C ");
else if (this->OpType == POINTER)
msg("P ");
else if (this->OpType == STACKPTR)
msg("S ");
else if (this->OpType == GLOBALPTR)
msg("G ");
else if (this->OpType == HEAPPTR)
msg("H ");
else if (this->OpType == PTROFFSET)
msg("O ");
else if (this->OpType == UNKNOWN)
msg("U ");
// Don't write anything for UNINIT OpType
return;
} // end of DefOrUse::Dump()
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
// *****************************************************************
// Class DefOrUseSet
// *****************************************************************
// Default constructor.
DefOrUseSet::DefOrUseSet(void) {
return;
}
// Find the reference for a given operand type.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::FindRef(op_t SearchOp) {
set<DefOrUse, LessDefUse>::iterator CurrRef;
DefOrUse DummyRef(SearchOp);
CurrRef = this->Refs.find(DummyRef);
return CurrRef;
}
// Set a Def or Use into the list, along with its type.
void DefOrUseSet::SetRef(op_t Ref, SMPOperandType Type, int SSASub) {
DefOrUse CurrRef(Ref, Type, SSASub);
this->Refs.insert(CurrRef);
return;
}
// Change the SSA subscript for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetSSANum(op_t CurrOp, int NewSSASub) {
// To change a field within a set, we must grab a copy, change the copy,
// delete the old set member, and insert the updated copy as a new member.
set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
assert(CurrRef != this->Refs.end());
set<DefOrUse, LessDefUse>::iterator NextRef = CurrRef;
++NextRef;
DefOrUse NewCopy = (*CurrRef);
NewCopy.SetSSANum(NewSSASub);
this->Refs.erase(CurrRef);
CurrRef = this->Refs.insert(NextRef, NewCopy);
return CurrRef;
}
// Change the operand type for a reference.
set<DefOrUse, LessDefUse>::iterator DefOrUseSet::SetType(op_t CurrOp, SMPOperandType Type) {
// To change a field within a set, we must grab a copy, change the copy,
// delete the old set member, and insert the updated copy as a new member.
set<DefOrUse, LessDefUse>::iterator CurrRef = this->FindRef(CurrOp);
assert(CurrRef != this->Refs.end());
#if 1
if (o_imm == CurrOp.type) {
if (UNINIT != CurrRef->GetType()) {
msg("ERROR: Changing type of immediate to %d : ", Type);
CurrRef->Dump();
msg("\n");
}
}
#endif
DefOrUse NewCopy = (*CurrRef);
NewCopy.SetType(Type);
this->Refs.erase(CurrRef);
pair<set<DefOrUse, LessDefUse>::iterator, bool> InsertResult;
InsertResult = this->Refs.insert(NewCopy);
assert(InsertResult.second);
CurrRef = InsertResult.first;
return CurrRef;
}
// Debug printing.
void DefOrUseSet::Dump(void) {
set<DefOrUse, LessDefUse>::iterator CurrRef;
for (CurrRef = this->Refs.begin(); CurrRef != this->Refs.end(); ++CurrRef) {
CurrRef->Dump();
}
msg("\n");
return;
}
// *****************************************************************
// Class DefOrUseList
// *****************************************************************
// Default constructor.
DefOrUseList::DefOrUseList(void) {
return;
}
// Set a Def or Use into the list, along with its type.
void DefOrUseList::SetRef(op_t Ref, SMPOperandType Type, int SSASub) {
DefOrUse CurrRef(Ref, Type, SSASub);
this->Refs.push_back(CurrRef);
DefOrUse DefOrUseList::GetRef(size_t index) const {
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
// Change the SSA subscript for a reference.
void DefOrUseList::SetSSANum(size_t index, int NewSSASub) {
this->Refs[index].SetSSANum(NewSSASub);
return;
}
// Change the operand type for a reference.
void DefOrUseList::SetType(size_t index, SMPOperandType Type) {
this->Refs[index].SetType(Type);
return;
}
// Debug printing.
void DefOrUseList::Dump(void) const {
for (size_t index = 0; index < this->Refs.size(); ++index) {
Refs[index].Dump();
}
msg("\n");
return;
}
// Erase duplicate entries, in case SMPInstr::MDFixupDefUseLists() adds one.
void DefOrUseList::EraseDuplicates(void) {
set<op_t, LessOp> TempRefs; // Use STL set to find duplicates
set<op_t, LessOp>::iterator TempIter;
vector<DefOrUse>::iterator RefIter;
RefIter = this->Refs.begin();
while (RefIter != this->Refs.end()) {
TempIter = TempRefs.find(RefIter->GetOp());
if (TempIter == TempRefs.end()) { // not already in set
TempRefs.insert(RefIter->GetOp());
++RefIter;
}
else { // found it in set already
RefIter = this->Refs.erase(RefIter);
}
}
return;
} // end of DefOrUseList::EraseDuplicates()
// *****************************************************************
// Class SMPPhiFunction
// *****************************************************************
// Constructor
SMPPhiFunction::SMPPhiFunction(int GlobIndex, const DefOrUse &Def) {
this->DefName = Def;
// Add a phi item to the list
void SMPPhiFunction::PushBack(DefOrUse Ref) {
this->SubscriptedOps.SetRef(Ref.GetOp(), Ref.GetType(), Ref.GetSSANum());
return;
}
// Set the SSA number of the defined variable.
void SMPPhiFunction::SetSSADef(int NewSSASub) {
this->DefName.SetSSANum(NewSSASub);
return;
}
// Set the SSA number of the input variable.
void SMPPhiFunction::SetSSARef(size_t index, int NewSSASub) {
this->SubscriptedOps.SetSSANum(index, NewSSASub);
return;
}
// Set the type of the defined variable.
void SMPPhiFunction::SetDefType(SMPOperandType Type) {
this->DefName.SetType(Type);
return;
}
// Set the type of the input variable.
void SMPPhiFunction::SetRefType(size_t index, SMPOperandType Type) {
this->SubscriptedOps.SetType(index, Type);
return;
}
// Debug printing.
void SMPPhiFunction::Dump(void) const {
msg(" DEF: ");
this->DefName.Dump();
msg(" USEs: ");
this->SubscriptedOps.Dump();
return;
}
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
// *****************************************************************
// Class SMPDefUseChain
// *****************************************************************
// Constructors
SMPDefUseChain::SMPDefUseChain(void) {
this->SSAName.type = o_void;
this->RefInstrs.push_back(BADADDR);
return;
}
SMPDefUseChain::SMPDefUseChain(op_t Name, ea_t Def) {
this->SSAName = Name;
this->RefInstrs.push_back(Def);
return;
}
// Set the variable name.
void SMPDefUseChain::SetName(op_t Name) {
this->SSAName = Name;
return;
}
// Set the DEF instruction.
void SMPDefUseChain::SetDef(ea_t Def) {
this->RefInstrs[0] = Def;
return;
}
// Push a USE onto the list
void SMPDefUseChain::PushUse(ea_t Use) {
this->RefInstrs.push_back(Use);
return;
}
// DEBUG dump.
void SMPDefUseChain::Dump(int SSANum) {
msg("DEF-USE chain for: ");
PrintListOperand(this->SSAName, SSANum);
if (this->RefInstrs.size() < 1) {
msg(" no references.\n");
return;
}
msg("\n DEF: %x USEs: ", this->RefInstrs.at(0));
size_t index;
for (index = 1; index < this->RefInstrs.size(); ++index)
msg("%x ", this->RefInstrs.at(index));
msg("\n");
return;
} // end of SMPDefUseChain::Dump()
// *****************************************************************
// Class SMPDUChainArray
// *****************************************************************
SMPDUChainArray::SMPDUChainArray(void) {
this->SSAName.type = o_void;
return;
}
SMPDUChainArray::SMPDUChainArray(op_t Name) {
this->SSAName = Name;
return;
}
void SMPDUChainArray::SetName(op_t Name) {
this->SSAName = Name;
return;
}
// DEBUG dump.
void SMPDUChainArray::Dump(void) {
size_t index;
for (index = 0; index < this->DUChains.size(); ++index) {
this->DUChains.at(index).Dump((int) index);
}
return;
}
// *****************************************************************
// Class SMPCompleteDUChains
// *****************************************************************
// DEBUG dump.
void SMPCompleteDUChains::Dump(void) {
size_t index;
for (index = 0; index < this->ChainsByName.size(); ++index) {
this->ChainsByName.at(index).Dump();
}
return;
} // end of SMPCompleteDUChains::Dump()
// Initialize the DFACategory[] array to define instruction classes
// for the purposes of data flow analysis.
void InitDFACategory(void) {
// Default category is 0, not the start or end of a basic block.
(void) memset(DFACategory, 0, sizeof(DFACategory));
DFACategory[NN_call] = CALL; // Call Procedure
DFACategory[NN_callfi] = INDIR_CALL; // Indirect Call Far Procedure
DFACategory[NN_callni] = INDIR_CALL; // Indirect Call Near Procedure
DFACategory[NN_hlt] = HALT; // Halt
DFACategory[NN_int] = INDIR_CALL; // Call to Interrupt Procedure
DFACategory[NN_into] = INDIR_CALL; // Call to Interrupt Procedure if Overflow Flag = 1
DFACategory[NN_int3] = INDIR_CALL; // Trap to Debugger
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
DFACategory[NN_iretw] = RETURN; // Interrupt Return
DFACategory[NN_iret] = RETURN; // Interrupt Return
DFACategory[NN_iretd] = RETURN; // Interrupt Return (use32)
DFACategory[NN_iretq] = RETURN; // Interrupt Return (use64)
DFACategory[NN_ja] = COND_BRANCH; // Jump if Above (CF=0 & ZF=0)
DFACategory[NN_jae] = COND_BRANCH; // Jump if Above or Equal (CF=0)
DFACategory[NN_jb] = COND_BRANCH; // Jump if Below (CF=1)
DFACategory[NN_jbe] = COND_BRANCH; // Jump if Below or Equal (CF=1 | ZF=1)
DFACategory[NN_jc] = COND_BRANCH; // Jump if Carry (CF=1)
DFACategory[NN_jcxz] = COND_BRANCH; // Jump if CX is 0
DFACategory[NN_jecxz] = COND_BRANCH; // Jump if ECX is 0
DFACategory[NN_jrcxz] = COND_BRANCH; // Jump if RCX is 0
DFACategory[NN_je] = COND_BRANCH; // Jump if Equal (ZF=1)
DFACategory[NN_jg] = COND_BRANCH; // Jump if Greater (ZF=0 & SF=OF)
DFACategory[NN_jge] = COND_BRANCH; // Jump if Greater or Equal (SF=OF)
DFACategory[NN_jl] = COND_BRANCH; // Jump if Less (SF!=OF)
DFACategory[NN_jle] = COND_BRANCH; // Jump if Less or Equal (ZF=1 | SF!=OF)
DFACategory[NN_jna] = COND_BRANCH; // Jump if Not Above (CF=1 | ZF=1)
DFACategory[NN_jnae] = COND_BRANCH; // Jump if Not Above or Equal (CF=1)
DFACategory[NN_jnb] = COND_BRANCH; // Jump if Not Below (CF=0)
DFACategory[NN_jnbe] = COND_BRANCH; // Jump if Not Below or Equal (CF=0 & ZF=0)
DFACategory[NN_jnc] = COND_BRANCH; // Jump if Not Carry (CF=0)
DFACategory[NN_jne] = COND_BRANCH; // Jump if Not Equal (ZF=0)
DFACategory[NN_jng] = COND_BRANCH; // Jump if Not Greater (ZF=1 | SF!=OF)
DFACategory[NN_jnge] = COND_BRANCH; // Jump if Not Greater or Equal (ZF=1)
DFACategory[NN_jnl] = COND_BRANCH; // Jump if Not Less (SF=OF)
DFACategory[NN_jnle] = COND_BRANCH; // Jump if Not Less or Equal (ZF=0 & SF=OF)
DFACategory[NN_jno] = COND_BRANCH; // Jump if Not Overflow (OF=0)
DFACategory[NN_jnp] = COND_BRANCH; // Jump if Not Parity (PF=0)
DFACategory[NN_jns] = COND_BRANCH; // Jump if Not Sign (SF=0)
DFACategory[NN_jnz] = COND_BRANCH; // Jump if Not Zero (ZF=0)
DFACategory[NN_jo] = COND_BRANCH; // Jump if Overflow (OF=1)
DFACategory[NN_jp] = COND_BRANCH; // Jump if Parity (PF=1)
DFACategory[NN_jpe] = COND_BRANCH; // Jump if Parity Even (PF=1)
DFACategory[NN_jpo] = COND_BRANCH; // Jump if Parity Odd (PF=0)
DFACategory[NN_js] = COND_BRANCH; // Jump if Sign (SF=1)
DFACategory[NN_jz] = COND_BRANCH; // Jump if Zero (ZF=1)
DFACategory[NN_jmp] = JUMP; // Jump
DFACategory[NN_jmpfi] = INDIR_JUMP; // Indirect Far Jump
DFACategory[NN_jmpni] = INDIR_JUMP; // Indirect Near Jump
DFACategory[NN_jmpshort] = JUMP; // Jump Short (only in 64-bit mode)
DFACategory[NN_loopw] = COND_BRANCH; // Loop while ECX != 0
DFACategory[NN_loop] = COND_BRANCH; // Loop while CX != 0
DFACategory[NN_loopd] = COND_BRANCH; // Loop while ECX != 0
DFACategory[NN_loopq] = COND_BRANCH; // Loop while RCX != 0
DFACategory[NN_loopwe] = COND_BRANCH; // Loop while CX != 0 and ZF=1
DFACategory[NN_loope] = COND_BRANCH; // Loop while rCX != 0 and ZF=1
DFACategory[NN_loopde] = COND_BRANCH; // Loop while ECX != 0 and ZF=1
DFACategory[NN_loopqe] = COND_BRANCH; // Loop while RCX != 0 and ZF=1
DFACategory[NN_loopwne] = COND_BRANCH; // Loop while CX != 0 and ZF=0
DFACategory[NN_loopne] = COND_BRANCH; // Loop while rCX != 0 and ZF=0
DFACategory[NN_loopdne] = COND_BRANCH; // Loop while ECX != 0 and ZF=0
DFACategory[NN_loopqne] = COND_BRANCH; // Loop while RCX != 0 and ZF=0
DFACategory[NN_retn] = RETURN; // Return Near from Procedure
DFACategory[NN_retf] = RETURN; // Return Far from Procedure
//
// Pentium instructions
//
DFACategory[NN_rsm] = HALT; // Resume from System Management Mode
// Pentium II instructions
DFACategory[NN_sysenter] = CALL; // Fast Transition to System Call Entry Point
DFACategory[NN_sysexit] = CALL; // Fast Transition from System Call Entry Point
// AMD syscall/sysret instructions NOTE: not AMD, found in Intel manual
DFACategory[NN_syscall] = CALL; // Low latency system call
DFACategory[NN_sysret] = CALL; // Return from system call
// VMX instructions
DFACategory[NN_vmcall] = INDIR_CALL; // Call to VM Monitor
return;
} // end InitDFACategory()
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Initialize the SMPDefsFlags[] array to define how we emit
// optimizing annotations.
void InitSMPDefsFlags(void) {
// Default value is true. Many instructions set the flags.
(void) memset(SMPDefsFlags, true, sizeof(SMPDefsFlags));
SMPDefsFlags[NN_null] = false; // Unknown Operation
SMPDefsFlags[NN_bound] = false; // Check Array Index Against Bounds
SMPDefsFlags[NN_call] = false; // Call Procedure
SMPDefsFlags[NN_callfi] = false; // Indirect Call Far Procedure
SMPDefsFlags[NN_callni] = false; // Indirect Call Near Procedure
SMPDefsFlags[NN_cbw] = false; // AL -> AX (with sign)
SMPDefsFlags[NN_cwde] = false; // AX -> EAX (with sign)
SMPDefsFlags[NN_cdqe] = false; // EAX -> RAX (with sign)
SMPDefsFlags[NN_clts] = false; // Clear Task-Switched Flag in CR0
SMPDefsFlags[NN_cwd] = false; // AX -> DX:AX (with sign)
SMPDefsFlags[NN_cdq] = false; // EAX -> EDX:EAX (with sign)
SMPDefsFlags[NN_cqo] = false; // RAX -> RDX:RAX (with sign)
SMPDefsFlags[NN_enterw] = false; // Make Stack Frame for Procedure Parameters
SMPDefsFlags[NN_enter] = false; // Make Stack Frame for Procedure Parameters
SMPDefsFlags[NN_enterd] = false; // Make Stack Frame for Procedure Parameters
SMPDefsFlags[NN_enterq] = false; // Make Stack Frame for Procedure Parameters
SMPDefsFlags[NN_hlt] = false; // Halt
SMPDefsFlags[NN_in] = false; // Input from Port
SMPDefsFlags[NN_ins] = false; // Input Byte(s) from Port to String
SMPDefsFlags[NN_iretw] = false; // Interrupt Return
SMPDefsFlags[NN_iret] = false; // Interrupt Return
SMPDefsFlags[NN_iretd] = false; // Interrupt Return (use32)
SMPDefsFlags[NN_iretq] = false; // Interrupt Return (use64)
SMPDefsFlags[NN_ja] = false; // Jump if Above (CF=0 & ZF=0)
SMPDefsFlags[NN_jae] = false; // Jump if Above or Equal (CF=0)
SMPDefsFlags[NN_jb] = false; // Jump if Below (CF=1)
SMPDefsFlags[NN_jbe] = false; // Jump if Below or Equal (CF=1 | ZF=1)
SMPDefsFlags[NN_jc] = false; // Jump if Carry (CF=1)
SMPDefsFlags[NN_jcxz] = false; // Jump if CX is 0
SMPDefsFlags[NN_jecxz] = false; // Jump if ECX is 0
SMPDefsFlags[NN_jrcxz] = false; // Jump if RCX is 0
SMPDefsFlags[NN_je] = false; // Jump if Equal (ZF=1)
SMPDefsFlags[NN_jg] = false; // Jump if Greater (ZF=0 & SF=OF)
SMPDefsFlags[NN_jge] = false; // Jump if Greater or Equal (SF=OF)
SMPDefsFlags[NN_jl] = false; // Jump if Less (SF!=OF)
SMPDefsFlags[NN_jle] = false; // Jump if Less or Equal (ZF=1 | SF!=OF)
SMPDefsFlags[NN_jna] = false; // Jump if Not Above (CF=1 | ZF=1)
SMPDefsFlags[NN_jnae] = false; // Jump if Not Above or Equal (CF=1)
SMPDefsFlags[NN_jnb] = false; // Jump if Not Below (CF=0)
SMPDefsFlags[NN_jnbe] = false; // Jump if Not Below or Equal (CF=0 & ZF=0)
SMPDefsFlags[NN_jnc] = false; // Jump if Not Carry (CF=0)
SMPDefsFlags[NN_jne] = false; // Jump if Not Equal (ZF=0)
SMPDefsFlags[NN_jng] = false; // Jump if Not Greater (ZF=1 | SF!=OF)
SMPDefsFlags[NN_jnge] = false; // Jump if Not Greater or Equal (ZF=1)
SMPDefsFlags[NN_jnl] = false; // Jump if Not Less (SF=OF)
SMPDefsFlags[NN_jnle] = false; // Jump if Not Less or Equal (ZF=0 & SF=OF)
SMPDefsFlags[NN_jno] = false; // Jump if Not Overflow (OF=0)
SMPDefsFlags[NN_jnp] = false; // Jump if Not Parity (PF=0)
SMPDefsFlags[NN_jns] = false; // Jump if Not Sign (SF=0)
SMPDefsFlags[NN_jnz] = false; // Jump if Not Zero (ZF=0)
SMPDefsFlags[NN_jo] = false; // Jump if Overflow (OF=1)
SMPDefsFlags[NN_jp] = false; // Jump if Parity (PF=1)
SMPDefsFlags[NN_jpe] = false; // Jump if Parity Even (PF=1)
SMPDefsFlags[NN_jpo] = false; // Jump if Parity Odd (PF=0)
SMPDefsFlags[NN_js] = false; // Jump if Sign (SF=1)
SMPDefsFlags[NN_jz] = false; // Jump if Zero (ZF=1)
SMPDefsFlags[NN_jmp] = false; // Jump
SMPDefsFlags[NN_jmpfi] = false; // Indirect Far Jump
SMPDefsFlags[NN_jmpni] = false; // Indirect Near Jump
SMPDefsFlags[NN_jmpshort] = false; // Jump Short (not used)
SMPDefsFlags[NN_lahf] = false; // Load Flags into AH Register
SMPDefsFlags[NN_lea] = false; // Load Effective Address
SMPDefsFlags[NN_leavew] = false; // High Level Procedure Exit
SMPDefsFlags[NN_leave] = false; // High Level Procedure Exit
SMPDefsFlags[NN_leaved] = false; // High Level Procedure Exit
SMPDefsFlags[NN_leaveq] = false; // High Level Procedure Exit
SMPDefsFlags[NN_lgdt] = false; // Load Global Descriptor Table Register
SMPDefsFlags[NN_lidt] = false; // Load Interrupt Descriptor Table Register
SMPDefsFlags[NN_lgs] = false; // Load Full Pointer to GS:xx
SMPDefsFlags[NN_lss] = false; // Load Full Pointer to SS:xx
SMPDefsFlags[NN_lds] = false; // Load Full Pointer to DS:xx
SMPDefsFlags[NN_les] = false; // Load Full Pointer to ES:xx
SMPDefsFlags[NN_lfs] = false; // Load Full Pointer to FS:xx
SMPDefsFlags[NN_loopwe] = false; // Loop while CX != 0 and ZF=1
SMPDefsFlags[NN_loope] = false; // Loop while rCX != 0 and ZF=1
SMPDefsFlags[NN_loopde] = false; // Loop while ECX != 0 and ZF=1
SMPDefsFlags[NN_loopqe] = false; // Loop while RCX != 0 and ZF=1
SMPDefsFlags[NN_loopwne] = false; // Loop while CX != 0 and ZF=0
SMPDefsFlags[NN_loopne] = false; // Loop while rCX != 0 and ZF=0
SMPDefsFlags[NN_loopdne] = false; // Loop while ECX != 0 and ZF=0
SMPDefsFlags[NN_loopqne] = false; // Loop while RCX != 0 and ZF=0
SMPDefsFlags[NN_ltr] = false; // Load Task Register
SMPDefsFlags[NN_mov] = false; // Move Data
SMPDefsFlags[NN_movsp] = false; // Move to/from Special Registers
SMPDefsFlags[NN_movs] = false; // Move Byte(s) from String to String
SMPDefsFlags[NN_movsx] = false; // Move with Sign-Extend
SMPDefsFlags[NN_movzx] = false; // Move with Zero-Extend
SMPDefsFlags[NN_nop] = false; // No Operation
SMPDefsFlags[NN_out] = false; // Output to Port
SMPDefsFlags[NN_outs] = false; // Output Byte(s) to Port
SMPDefsFlags[NN_pop] = false; // Pop a word from the Stack
SMPDefsFlags[NN_popaw] = false; // Pop all General Registers
SMPDefsFlags[NN_popa] = false; // Pop all General Registers
SMPDefsFlags[NN_popad] = false; // Pop all General Registers (use32)
SMPDefsFlags[NN_popaq] = false; // Pop all General Registers (use64)
SMPDefsFlags[NN_push] = false; // Push Operand onto the Stack
SMPDefsFlags[NN_pushaw] = false; // Push all General Registers
SMPDefsFlags[NN_pusha] = false; // Push all General Registers
SMPDefsFlags[NN_pushad] = false; // Push all General Registers (use32)
SMPDefsFlags[NN_pushaq] = false; // Push all General Registers (use64)
SMPDefsFlags[NN_pushfw] = false; // Push Flags Register onto the Stack
SMPDefsFlags[NN_pushf] = false; // Push Flags Register onto the Stack
SMPDefsFlags[NN_pushfd] = false; // Push Flags Register onto the Stack (use32)
SMPDefsFlags[NN_pushfq] = false; // Push Flags Register onto the Stack (use64)
SMPDefsFlags[NN_rep] = false; // Repeat String Operation
SMPDefsFlags[NN_repe] = false; // Repeat String Operation while ZF=1
SMPDefsFlags[NN_repne] = false; // Repeat String Operation while ZF=0
SMPDefsFlags[NN_retn] = false; // Return Near from Procedure
SMPDefsFlags[NN_retf] = false; // Return Far from Procedure
SMPDefsFlags[NN_shl] = false; // Shift Logical Left
SMPDefsFlags[NN_shr] = false; // Shift Logical Right
SMPDefsFlags[NN_seta] = false; // Set Byte if Above (CF=0 & ZF=0)
SMPDefsFlags[NN_setae] = false; // Set Byte if Above or Equal (CF=0)
SMPDefsFlags[NN_setb] = false; // Set Byte if Below (CF=1)
SMPDefsFlags[NN_setbe] = false; // Set Byte if Below or Equal (CF=1 | ZF=1)
SMPDefsFlags[NN_setc] = false; // Set Byte if Carry (CF=1)
SMPDefsFlags[NN_sete] = false; // Set Byte if Equal (ZF=1)
SMPDefsFlags[NN_setg] = false; // Set Byte if Greater (ZF=0 & SF=OF)
SMPDefsFlags[NN_setge] = false; // Set Byte if Greater or Equal (SF=OF)
SMPDefsFlags[NN_setl] = false; // Set Byte if Less (SF!=OF)
SMPDefsFlags[NN_setle] = false; // Set Byte if Less or Equal (ZF=1 | SF!=OF)
SMPDefsFlags[NN_setna] = false; // Set Byte if Not Above (CF=1 | ZF=1)
SMPDefsFlags[NN_setnae] = false; // Set Byte if Not Above or Equal (CF=1)
SMPDefsFlags[NN_setnb] = false; // Set Byte if Not Below (CF=0)
SMPDefsFlags[NN_setnbe] = false; // Set Byte if Not Below or Equal (CF=0 & ZF=0)
SMPDefsFlags[NN_setnc] = false; // Set Byte if Not Carry (CF=0)
SMPDefsFlags[NN_setne] = false; // Set Byte if Not Equal (ZF=0)
SMPDefsFlags[NN_setng] = false; // Set Byte if Not Greater (ZF=1 | SF!=OF)
SMPDefsFlags[NN_setnge] = false; // Set Byte if Not Greater or Equal (ZF=1)
SMPDefsFlags[NN_setnl] = false; // Set Byte if Not Less (SF=OF)
SMPDefsFlags[NN_setnle] = false; // Set Byte if Not Less or Equal (ZF=0 & SF=OF)
SMPDefsFlags[NN_setno] = false; // Set Byte if Not Overflow (OF=0)
SMPDefsFlags[NN_setnp] = false; // Set Byte if Not Parity (PF=0)
SMPDefsFlags[NN_setns] = false; // Set Byte if Not Sign (SF=0)
SMPDefsFlags[NN_setnz] = false; // Set Byte if Not Zero (ZF=0)
SMPDefsFlags[NN_seto] = false; // Set Byte if Overflow (OF=1)
SMPDefsFlags[NN_setp] = false; // Set Byte if Parity (PF=1)
SMPDefsFlags[NN_setpe] = false; // Set Byte if Parity Even (PF=1)
SMPDefsFlags[NN_setpo] = false; // Set Byte if Parity Odd (PF=0)
SMPDefsFlags[NN_sets] = false; // Set Byte if Sign (SF=1)
SMPDefsFlags[NN_setz] = false; // Set Byte if Zero (ZF=1)
SMPDefsFlags[NN_sgdt] = false; // Store Global Descriptor Table Register
SMPDefsFlags[NN_sidt] = false; // Store Interrupt Descriptor Table Register
SMPDefsFlags[NN_sldt] = false; // Store Local Descriptor Table Register
SMPDefsFlags[NN_str] = false; // Store Task Register
SMPDefsFlags[NN_wait] = false; // Wait until BUSY# Pin is Inactive (HIGH)
SMPDefsFlags[NN_xchg] = false; // Exchange Register/Memory with Register
//
// 486 instructions
//
SMPDefsFlags[NN_bswap] = false; // Swap bytes in register
SMPDefsFlags[NN_invd] = false; // Invalidate Data Cache
SMPDefsFlags[NN_wbinvd] = false; // Invalidate Data Cache (write changes)
SMPDefsFlags[NN_invlpg] = false; // Invalidate TLB entry
//
// Pentium instructions
//
SMPDefsFlags[NN_rdmsr] = false; // Read Machine Status Register
SMPDefsFlags[NN_wrmsr] = false; // Write Machine Status Register
SMPDefsFlags[NN_cpuid] = false; // Get CPU ID
SMPDefsFlags[NN_rdtsc] = false; // Read Time Stamp Counter
//
// Pentium Pro instructions
//
SMPDefsFlags[NN_cmova] = false; // Move if Above (CF=0 & ZF=0)
SMPDefsFlags[NN_cmovb] = false; // Move if Below (CF=1)
SMPDefsFlags[NN_cmovbe] = false; // Move if Below or Equal (CF=1 | ZF=1)
SMPDefsFlags[NN_cmovg] = false; // Move if Greater (ZF=0 & SF=OF)
SMPDefsFlags[NN_cmovge] = false; // Move if Greater or Equal (SF=OF)
SMPDefsFlags[NN_cmovl] = false; // Move if Less (SF!=OF)
SMPDefsFlags[NN_cmovle] = false; // Move if Less or Equal (ZF=1 | SF!=OF)
SMPDefsFlags[NN_cmovnb] = false; // Move if Not Below (CF=0)
SMPDefsFlags[NN_cmovno] = false; // Move if Not Overflow (OF=0)
SMPDefsFlags[NN_cmovnp] = false; // Move if Not Parity (PF=0)
SMPDefsFlags[NN_cmovns] = false; // Move if Not Sign (SF=0)
SMPDefsFlags[NN_cmovnz] = false; // Move if Not Zero (ZF=0)
SMPDefsFlags[NN_cmovo] = false; // Move if Overflow (OF=1)
SMPDefsFlags[NN_cmovp] = false; // Move if Parity (PF=1)
SMPDefsFlags[NN_cmovs] = false; // Move if Sign (SF=1)
SMPDefsFlags[NN_cmovz] = false; // Move if Zero (ZF=1)
SMPDefsFlags[NN_fcmovb] = false; // Floating Move if Below
SMPDefsFlags[NN_fcmove] = false; // Floating Move if Equal
SMPDefsFlags[NN_fcmovbe] = false; // Floating Move if Below or Equal
SMPDefsFlags[NN_fcmovu] = false; // Floating Move if Unordered
SMPDefsFlags[NN_fcmovnb] = false; // Floating Move if Not Below
SMPDefsFlags[NN_fcmovne] = false; // Floating Move if Not Equal
SMPDefsFlags[NN_fcmovnbe] = false; // Floating Move if Not Below or Equal
SMPDefsFlags[NN_fcmovnu] = false; // Floating Move if Not Unordered
SMPDefsFlags[NN_rdpmc] = false; // Read Performance Monitor Counter
//
// FPP instructuions
//
SMPDefsFlags[NN_fld] = false; // Load Real
SMPDefsFlags[NN_fst] = false; // Store Real
SMPDefsFlags[NN_fstp] = false; // Store Real and Pop
SMPDefsFlags[NN_fxch] = false; // Exchange Registers
SMPDefsFlags[NN_fild] = false; // Load Integer
SMPDefsFlags[NN_fist] = false; // Store Integer
SMPDefsFlags[NN_fistp] = false; // Store Integer and Pop
SMPDefsFlags[NN_fbld] = false; // Load BCD
SMPDefsFlags[NN_fbstp] = false; // Store BCD and Pop
SMPDefsFlags[NN_fadd] = false; // Add Real
SMPDefsFlags[NN_faddp] = false; // Add Real and Pop
SMPDefsFlags[NN_fiadd] = false; // Add Integer
SMPDefsFlags[NN_fsub] = false; // Subtract Real
SMPDefsFlags[NN_fsubp] = false; // Subtract Real and Pop
SMPDefsFlags[NN_fisub] = false; // Subtract Integer
SMPDefsFlags[NN_fsubr] = false; // Subtract Real Reversed
SMPDefsFlags[NN_fsubrp] = false; // Subtract Real Reversed and Pop
SMPDefsFlags[NN_fisubr] = false; // Subtract Integer Reversed
SMPDefsFlags[NN_fmul] = false; // Multiply Real
SMPDefsFlags[NN_fmulp] = false; // Multiply Real and Pop
SMPDefsFlags[NN_fimul] = false; // Multiply Integer
SMPDefsFlags[NN_fdiv] = false; // Divide Real
SMPDefsFlags[NN_fdivp] = false; // Divide Real and Pop
SMPDefsFlags[NN_fidiv] = false; // Divide Integer
SMPDefsFlags[NN_fdivr] = false; // Divide Real Reversed
SMPDefsFlags[NN_fdivrp] = false; // Divide Real Reversed and Pop
SMPDefsFlags[NN_fidivr] = false; // Divide Integer Reversed
SMPDefsFlags[NN_fsqrt] = false; // Square Root
SMPDefsFlags[NN_fscale] = false; // Scale: st(0) <- st(0) * 2^st(1)
SMPDefsFlags[NN_fprem] = false; // Partial Remainder
SMPDefsFlags[NN_frndint] = false; // Round to Integer
SMPDefsFlags[NN_fxtract] = false; // Extract exponent and significand
SMPDefsFlags[NN_fabs] = false; // Absolute value
SMPDefsFlags[NN_fchs] = false; // Change Sign
SMPDefsFlags[NN_ficom] = false; // Compare Integer
SMPDefsFlags[NN_ficomp] = false; // Compare Integer and Pop
SMPDefsFlags[NN_ftst] = false; // Test
SMPDefsFlags[NN_fxam] = false; // Examine
SMPDefsFlags[NN_fptan] = false; // Partial tangent
SMPDefsFlags[NN_fpatan] = false; // Partial arctangent