diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index f4b3599703..2385def30d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -4439,28 +4439,23 @@ bool RuleSubCommute::cancelExtensions(PcodeOp *longform,PcodeOp *subOp,Varnode * int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data) { - Varnode *base,*vn,*newvn,*outvn; - PcodeOp *longform,*newsub,*prevop; - int4 i,j,offset,insize; - - base = op->getIn(0); + Varnode *base = op->getIn(0); if (!base->isWritten()) return 0; - offset = op->getIn(1)->getOffset(); - outvn = op->getOut(); + int4 offset = op->getIn(1)->getOffset(); + Varnode *outvn = op->getOut(); if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0; - insize = base->getSize(); - longform = base->getDef(); - j = -1; + int4 insize = base->getSize(); + PcodeOp *longform = base->getDef(); + int4 j = -1; switch( longform->code() ) { // Determine if this op commutes with SUBPIECE // case CPUI_COPY: case CPUI_INT_LEFT: j = 1; // Special processing for shift amount param if (offset != 0) return 0; - if (!longform->getIn(0)->isWritten()) return 0; - prevop = longform->getIn(0)->getDef(); - if (prevop->code()==CPUI_INT_ZEXT) { - } - else if (prevop->code()==CPUI_PIECE) { + if (longform->getIn(0)->isWritten()) { + OpCode opc = longform->getIn(0)->getDef()->code(); + if (opc != CPUI_INT_ZEXT && opc != CPUI_PIECE) + return 0; } else return 0; @@ -4558,17 +4553,24 @@ int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data) } } - for(i=0;inumInput();++i) { - vn = longform->getIn(i); + Varnode *lastIn = (Varnode *)0; + Varnode *newVn = (Varnode *)0; + for(int4 i=0;inumInput();++i) { + Varnode *vn = longform->getIn(i); if (i!=j) { - newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op - data.opSetOpcode(newsub,CPUI_SUBPIECE); - newvn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is subpiece - data.opSetInput(longform,newvn,i); - data.opSetInput(newsub,vn,0); // of old varnode - data.opSetInput(newsub,data.newConstant(4,offset),1); - data.opInsertBefore(newsub,longform); + if (lastIn != vn || newVn == (Varnode *)0) { // Don't duplicate the SUBPIECE if inputs are the same + PcodeOp *newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op + data.opSetOpcode(newsub,CPUI_SUBPIECE); + newVn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is SUBPIECE of old varnode + data.opSetInput(longform,newVn,i); + data.opSetInput(newsub,vn,0); // vn may be free, so set as input after setting newVn + data.opSetInput(newsub,data.newConstant(4,offset),1); + data.opInsertBefore(newsub,longform); + } + else + data.opSetInput(longform,newVn,i); } + lastIn = vn; } data.opSetOutput(longform,outvn); data.opDestroy(op); // Get rid of old SUBPIECE diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc index 880d198bbb..5c6d661a72 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc @@ -443,6 +443,16 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn) if (!createLink(rop,rvn->mask<mask & 1)==0) return false; // Logical value must be least sig bits + if ((bitsize & 7)!=0) return false; // Must be a whole number of bytes + if (!op->getIn(0)->isZeroExtended(flowsize)) return false; + if (!op->getIn(1)->isZeroExtended(flowsize)) return false; + rop = createOpDown(op->code(),2,op,rvn,slot); + if (!createLink(rop,rvn->mask,-1,outvn)) return false; + hcount += 1; + break; case CPUI_INT_ADD: if ((rvn->mask & 1)==0) return false; // Cannot account for carry @@ -768,6 +778,16 @@ bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn) if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false; } return true; + case CPUI_INT_DIV: + case CPUI_INT_REM: + if ((rvn->mask & 1) == 0) return false; + if ((bitsize & 7)!=0) return false; // Must be a whole number of bytes + if (!op->getIn(0)->isZeroExtended(flowsize)) return false; + if (!op->getIn(1)->isZeroExtended(flowsize)) return false; + rop = createOp(op->code(),2,rvn); + if (!createLink(rop,rvn->mask,0,op->getIn(0))) return false; + if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false; + return true; case CPUI_SUBPIECE: sa = (int4)op->getIn(1)->getOffset() * 8; newmask = rvn->mask << sa; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc index 4079c2661d..b90fc0e047 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -940,6 +940,22 @@ bool Varnode::isBooleanValue(bool useAnnotation) const return false; } +/// If we can prove that the upper bits of \b this are zero, return \b true. +/// \param baseSize is the maximum number of least significant bytes that are allowed to be non-zero +/// \return \b true if all the most significant bytes are zero +bool Varnode::isZeroExtended(int4 baseSize) const + +{ + if (baseSize >= size) return false; + if (size > sizeof(uintb)) { + if (!isWritten()) return false; + if (def->code() != CPUI_INT_ZEXT) return false; + if (def->getIn(0)->getSize() > baseSize) return false; + return true; + } + uintb mask = nzm >> 8*baseSize; + return (mask == 0); +} /// Make a local determination if \b this and \b op2 hold the same value. We check if /// there is a common ancester for which both \b this and \b op2 are created from a direct diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh index 17ca4995d6..e1bc358024 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh @@ -340,6 +340,7 @@ public: void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value + bool isZeroExtended(int4 baseSize) const; ///< Is \b this zero extended from something of the given size bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source? bool findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const; bool findPieceShadow(int4 leastByte,const Varnode *piece) const;