From 8758e817dcff279f8f90f8b883835e64c7db72a4 Mon Sep 17 00:00:00 2001 From: jdh8d <jdh8d@git.zephyr-software.com> Date: Thu, 8 Oct 2015 19:18:50 +0000 Subject: [PATCH] Updates for SIB and IsEqOp rewrite to use op_t::operator< Former-commit-id: ececbd7b378e90677b7f9bf3a5fbbc824009295d --- include/interfaces/irdb/STARSOp.h | 18 +++---- src/base/SMPDataFlowAnalysis.cpp | 44 +++++----------- src/interfaces/irdb/STARS_IRDB_Op.cpp | 76 +++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 45 deletions(-) diff --git a/include/interfaces/irdb/STARSOp.h b/include/interfaces/irdb/STARSOp.h index b1e333f8..665f9af0 100644 --- a/include/interfaces/irdb/STARSOp.h +++ b/include/interfaces/irdb/STARSOp.h @@ -111,14 +111,16 @@ class STARS_IRDB_op_t : public STARS_op_t virtual uint16_t GetSegReg(void) const { return SegReg; } // Get segment register of operand; R_none if no segment register // return SIB byte if exists. - virtual char GetSIB(void) const { return SIB; } // Get x86 SIB byte (dense encoding of base reg, index reg, and scale factor) + // Get x86 SIB byte (dense encoding of base reg, index reg, and scale factor) + virtual char GetSIB(void) const; + virtual int MDGetSIBBaseReg(void) const { return operand.mem.base; } // Get x86 SIB byte base register virtual short MDGetSIBIndexReg(void) const { return operand.mem.index; } // Get x86 SIB byte index register virtual int GetSIBScaleFactor(void) const { return operand.mem.scale; } // Extract scale factor from SIB byte // clc to investigate removing need for this function in base class // probably will still use in STARS_IDA_Op_t. - virtual char GetSpecFlag4(void) const { assert(0); } // Get specflag4 byte, used to hold a copy of the auxpref byte in x86-64 programs. + virtual char GetSpecFlag4(void) const { return 0; } // Get specflag4 byte, used to hold a copy of the auxpref byte in x86-64 programs. // Get value field for immediate operands; uint32 for x86-32, uint64 for x86-64 virtual STARS_uval_t GetImmedValue(void) const { assert(OpType==op_Imm); return operand.imm.imm; } @@ -140,10 +142,10 @@ class STARS_IRDB_op_t : public STARS_op_t virtual void SetReg(uint16_t NewReg) { assert(OpType==op_Reg); operand.reg.RegNum=(STARS_RegNo)NewReg; } virtual void SetAddr(STARS_ea_t NewAddr) { assert(OpType==op_Mem); operand.mem.disp=NewAddr; } - virtual void SetSIB(char value) { assert(OpType==op_Mem); operand.mem.sib_byte=value; operand.mem.hasSIB=true; } + virtual void SetSIB(char value); // clc to review, going away? - virtual void SetSpecFlag4(char value) { assert(0); } + virtual void SetSpecFlag4(char value) { /* intentionally empty */ } virtual void SetBitInSpecFlag4(char value) { assert(0); } // OR in the value to set a bit @@ -232,8 +234,7 @@ class STARS_IRDB_op_t : public STARS_op_t STARS_RegNo SegReg; int byteWidth; - char hasSIB:1; - char SIB; + char AuxPrefix4; // REX byte. enum OperandType_t { op_Reg, op_Mem, op_Imm, op_Void, op_CrReg, op_DrReg, op_Eflags, op_MMXReg, op_XMMReg, op_YMMReg, op_FPReg, op_Mxcsr, op_SegReg, op_Addr } OpType; union @@ -246,10 +247,9 @@ class STARS_IRDB_op_t : public STARS_op_t { STARS_RegNo base; STARS_RegNo index; - int scale:2; + unsigned int scale:4; // can take values 0, 1, 2, 4, 8. libIRDB::virtual_offset_t disp; // may be 64-bit imm in some x86-64 instructions. bool hasSIB:1; - unsigned char sib_byte; } mem; struct { @@ -276,8 +276,6 @@ class STARS_IRDB_op_t : public STARS_op_t visible=0; byteWidth=0; - hasSIB=0; - SIB=0; } diff --git a/src/base/SMPDataFlowAnalysis.cpp b/src/base/SMPDataFlowAnalysis.cpp index 2dc07efa..8cf77931 100644 --- a/src/base/SMPDataFlowAnalysis.cpp +++ b/src/base/SMPDataFlowAnalysis.cpp @@ -328,40 +328,24 @@ bool MDIsGeneralPurposeReg(const STARSOpndTypePtr &CurrOp) { } // Are operands equal? -bool IsEqOp(const STARSOpndTypePtr &Opnd1, const STARSOpndTypePtr &Opnd2) { +bool IsEqOp(const STARSOpndTypePtr &Opnd1, const STARSOpndTypePtr &Opnd2) +{ + if ((nullptr == Opnd1) && (nullptr == Opnd2)) + return true; if ((nullptr == Opnd1) || (nullptr == Opnd2)) return false; - if (Opnd1->GetOpType() != Opnd2->GetOpType()) - return false; + // this expression is logically equiv. to "equal" + // + // truth table: + // + // O1 O2 O1<O2 !(O1<O2) O2<O1 !(O2<O1) !(O1<O2)&&!(O2<O1) == + // 0 0 0 1 0 1 1 1 + // 0 1 1 0 0 0 0 0 + // 1 0 0 1 1 0 0 0 + // 1 1 0 1 0 0 1 1 + return !(*Opnd1 < *Opnd2) && !(*Opnd2 < *Opnd1); - if (Opnd1->IsVoidOp()) - return true; - if (Opnd1->IsRegOp()) - return ((Opnd1->GetReg() == Opnd2->GetReg()) && (Opnd1->GetByteWidth() == Opnd2->GetByteWidth())); - if (Opnd1->IsStaticMemOp()) - return (Opnd1->GetAddr() == Opnd2->GetAddr()); - if (Opnd1->IsMemNoDisplacementOp()) { - if (Opnd1->HasSIBByte() && Opnd2->HasSIBByte()) return ((Opnd1->GetSIB() == Opnd2->GetSIB()) && (Opnd1->GetSpecFlag4() == Opnd2->GetSpecFlag4())); - else if (Opnd1->HasSIBByte() || Opnd2->HasSIBByte()) return false; // no SIB != has SIB - else return (Opnd1->GetReg() == Opnd2->GetReg()); // neither has SIB; compare register, e.g. [ebx] to [edx] - } - if (Opnd1->IsMemDisplacementOp()) { - if (Opnd1->HasSIBByte() && Opnd2->HasSIBByte()) - return ((Opnd1->GetSIB() == Opnd2->GetSIB()) && (Opnd1->GetAddr() == Opnd2->GetAddr()) && (Opnd1->GetSpecFlag4() == Opnd2->GetSpecFlag4())); - else if ((!Opnd1->HasSIBByte()) && (!Opnd2->HasSIBByte())) - return ((Opnd1->GetAddr() == Opnd2->GetAddr()) && (Opnd1->GetReg() == Opnd2->GetReg())); - else return false; // no SIB != has SIB - } - if (Opnd1->IsImmedOp()) - return (Opnd1->GetImmedValue() == Opnd2->GetImmedValue()); - if (Opnd1->IsFarPointer() || Opnd1->IsNearPointer()) - return (Opnd1->GetAddr() == Opnd2->GetAddr()); - if (Opnd1->MDIsKnownOpType()) // compare regs for all special-register cases, e.g. MMX, XMM, YMM, debug regs, etc. - return (Opnd1->GetReg() == Opnd2->GetReg()); // no subword regs to deal with - - SMP_msg("ERROR: Unknown operand type in IsEqOp.\n"); - return false; } // end of function IsEqOp() // Are operands equal, ignoring bitwidth differences for register operands? diff --git a/src/interfaces/irdb/STARS_IRDB_Op.cpp b/src/interfaces/irdb/STARS_IRDB_Op.cpp index 1900ffed..cf15cb62 100644 --- a/src/interfaces/irdb/STARS_IRDB_Op.cpp +++ b/src/interfaces/irdb/STARS_IRDB_Op.cpp @@ -5,19 +5,28 @@ using namespace std; -static int log2int(int index) +static int log2int(unsigned int index) { + assert(index>0); int targetlevel = 0; while (index >>= 1) ++targetlevel; return targetlevel; } +static int log2int_or_err(unsigned int index) +{ + if(index==0) + return -1; + return log2int(index); +} + STARS_IRDB_op_t::STARS_IRDB_op_t(const DISASM &d, int indx, const ARGTYPE &the_arg) { Init(); // make void - int bea_regno=log2int(the_arg.ArgType&0xFFFF); + int bea_regno=bea_regno=log2int_or_err(the_arg.ArgType&0xFFFF); + visible=1; switch((the_arg.ArgType&0xFFFF0000)) { @@ -44,7 +53,7 @@ STARS_IRDB_op_t::STARS_IRDB_op_t(const DISASM &d, int indx, const ARGTYPE &the_a else { // set the operand.reg.RegNum appropriately. - operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_ax+bea_regno); + operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_ax+bea_regno); // regno may be -1, but ax-1==none, which is right. // if the first character is an r, it's a 64-bit reg. // e.g. rax, rsp, rdi @@ -67,11 +76,13 @@ STARS_IRDB_op_t::STARS_IRDB_op_t(const DISASM &d, int indx, const ARGTYPE &the_a case REGISTER_TYPE + MMX_REG : byteWidth=8; OpType=op_MMXReg; + assert(bea_regno!=-1); operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_mm0+bea_regno); break; case REGISTER_TYPE + FPU_REG : byteWidth=8; OpType=op_MMXReg; + assert(bea_regno!=-1); operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_st0+bea_regno); break; case REGISTER_TYPE + SSE_REG : @@ -79,6 +90,7 @@ STARS_IRDB_op_t::STARS_IRDB_op_t(const DISASM &d, int indx, const ARGTYPE &the_a { byteWidth=8; OpType=op_XMMReg; + assert(bea_regno!=-1); operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_xmm0+bea_regno); break; } @@ -86,6 +98,7 @@ STARS_IRDB_op_t::STARS_IRDB_op_t(const DISASM &d, int indx, const ARGTYPE &the_a { byteWidth=16; OpType=op_YMMReg; + assert(bea_regno!=-1); operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_ymm0+bea_regno); break; } @@ -135,16 +148,39 @@ no operands for eflags or mxcsr? break; case REGISTER_TYPE + SEGMENT_REG : OpType=op_SegReg; + assert(bea_regno!=-1); operand.reg.RegNum=(STARS_RegNo)(STARS_x86_R_es+bea_regno); break; case MEMORY_TYPE: case MEMORY_TYPE + RELATIVE_: case MEMORY_TYPE + ABSOLUTE_: { - operand.mem.base=(STARS_RegNo)log2int(the_arg.Memory.BaseRegister); - operand.mem.index=(STARS_RegNo)log2int(the_arg.Memory.IndexRegister); + // log2int_or_err returns -1 if the value is 0 (since you can't log2(0) + // which maps nicely to STARS_NN_None for no-register. + operand.mem.base=(STARS_RegNo)log2int_or_err(the_arg.Memory.BaseRegister); + operand.mem.index=(STARS_RegNo)log2int_or_err(the_arg.Memory.IndexRegister); operand.mem.scale=the_arg.Memory.Scale; + assert(operand.mem.scale==the_arg.Memory.Scale); operand.mem.disp=the_arg.Memory.Displacement; + + // if there's no base reg, and an index reg with scale==1, + // ida represents this oddly as a base with no sib. + if(operand.mem.base == STARS_x86_R_none && operand.mem.scale==1 && operand.mem.index!=STARS_x86_R_none) + { + // change representation. + operand.mem.base=operand.mem.index; + operand.mem.index=STARS_x86_R_none; + operand.mem.scale=0; + } + + // if the scale >0, we have a sib byte. + if(operand.mem.scale > 0) + operand.mem.hasSIB=1; + // if there's both a base and an index, then there's a sib byte. + if(operand.mem.base != STARS_x86_R_none && operand.mem.index != STARS_x86_R_none) + operand.mem.hasSIB=1; + + byteWidth=the_arg.ArgSize; OpType=op_Mem; break; @@ -246,3 +282,33 @@ bool STARS_IRDB_op_t::operator<(const STARS_op_t &rOp_param) const } } + +char STARS_IRDB_op_t::GetSIB(void) const +{ + char ret=0; + ret|=((int)operand.mem.base&0x7)<<0; + ret|=((int)operand.mem.index&0x7)<<3; + ret|=(log2int((int)operand.mem.scale)&0x3)<<6; + return ret; +} // Get x86 SIB byte (dense encoding of base reg, index reg, and scale factor) + + +void STARS_IRDB_op_t::SetSIB(char value) +{ + assert(OpType==op_Mem); + operand.mem.hasSIB=true; + + // update the base register. Odd casting to avoid compiler error bcause base is a STARS_RegNo + (*(int*)&operand.mem.base)&=0x7; + (*(int*)&operand.mem.base)|=(value&0x7); + + // Set scale. Odd casting to avoid compiler error bcause base is a STARS_RegNo + (*(int*)&operand.mem.index)&=(0x7<<3); + (*(int*)&operand.mem.index)|=(value>>3)&0x7; + + // set scale + operand.mem.scale= (STARS_RegNo)1<<((value>>6)&0x3); + if(operand.mem.index==STARS_x86_R_sp) + operand.mem.scale=(STARS_RegNo)0; +} + -- GitLab