From 77b1a6bf4bde38717b51f6c85af42c2dce77e2c2 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Tue, 4 Aug 2020 15:25:21 -0400 Subject: [PATCH] An optimized division corner case --- .../Decompiler/src/decompile/cpp/op.cc | 21 ++++- .../src/decompile/cpp/ruleaction.cc | 82 ++++++++++++++++--- .../src/decompile/cpp/ruleaction.hh | 1 + 3 files changed, 89 insertions(+), 15 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index 062cebe629..d0e8d10c49 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -529,7 +529,22 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const break; case CPUI_SUBPIECE: resmask = getIn(0)->getNZMask(); - resmask >>= 8*getIn(1)->getOffset(); + sz1 = (int4)getIn(1)->getOffset(); + if ((int4)getIn(0)->getSize() <= sizeof(uintb)) { + if (sz1 < sizeof(uintb)) + resmask >>= 8*sz1; + else + resmask = 0; + } + else { // Extended precision + if (sz1 < sizeof(uintb)) { + resmask >>= 8*sz1; + if (sz1 > 0) + resmask |= fullmask << (8*(sizeof(uintb)-sz1)); + } + else + resmask = fullmask; + } resmask &= fullmask; break; case CPUI_PIECE: @@ -540,11 +555,11 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const case CPUI_INT_MULT: val = getIn(0)->getNZMask(); resmask = getIn(1)->getNZMask(); - sz1 = mostsigbit_set(val); + sz1 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(val); if (sz1 == -1) resmask = 0; else { - sz2 = mostsigbit_set(resmask); + sz2 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(resmask); if (sz2 == -1) resmask = 0; else { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 48c774cb5c..06d98ec41f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -6970,7 +6970,12 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT Varnode *inVn = curOp->getIn(0); if (!inVn->isWritten()) return (Varnode *)0; - if (curOp->getIn(1)->isConstantExtended(y) < 0) return (Varnode *)0; // There MUST be a constant + if (inVn->isConstantExtended(y) >= 0) { + inVn = curOp->getIn(1); + if (!inVn->isWritten()) return (Varnode *)0; + } + else if (curOp->getIn(1)->isConstantExtended(y) < 0) + return (Varnode *)0; // There MUST be a constant Varnode *resVn; PcodeOp *extOp = inVn->getDef(); @@ -7062,29 +7067,81 @@ uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize) /// - `V >> 0x1f` /// - `V s>> 0x1f` /// +/// Allow for the value to be COPYed around. /// \param firstVn is the first given Varnode /// \param replaceVn is the Varnode to replace it with in each extraction /// \param data is the function holding the Varnodes void RuleDivOpt::moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data) { - list::const_iterator iter = firstVn->beginDescend(); - while(iter!=firstVn->endDescend()) { - PcodeOp *op = *iter; - ++iter; // Increment before modifying the op - OpCode opc = op->code(); - if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) { - Varnode *constVn = op->getIn(1); - if (constVn->isConstant()) { - int4 sa = firstVn->getSize() * 8 - 1; - if (sa == (int4)constVn->getOffset()) { - data.opSetInput(op,replaceVn,0); + vector testList; + testList.push_back(firstVn); + if (firstVn->isWritten()) { + PcodeOp *op = firstVn->getDef(); + if (op->code() == CPUI_INT_SRIGHT) { + // Same sign bit could be extracted from previous shifted version + testList.push_back(op->getIn(0)); + } + } + for(int4 i=0;i::const_iterator iter = vn->beginDescend(); + while(iter!=vn->endDescend()) { + PcodeOp *op = *iter; + ++iter; // Increment before modifying the op + OpCode opc = op->code(); + if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) { + Varnode *constVn = op->getIn(1); + if (constVn->isWritten()) { + PcodeOp *constOp = constVn->getDef(); + if (constOp->code() == CPUI_COPY) + constVn = constOp->getIn(0); + else if (constOp->code() == CPUI_INT_AND) { + constVn = constOp->getIn(0); + Varnode *otherVn = constOp->getIn(1); + if (!otherVn->isConstant()) continue; + if (constVn->getOffset() != (constVn->getOffset() & otherVn->getOffset())) continue; + } } + if (constVn->isConstant()) { + int4 sa = firstVn->getSize() * 8 - 1; + if (sa == (int4)constVn->getOffset()) { + data.opSetInput(op,replaceVn,0); + } + } + } + else if (opc == CPUI_COPY) { + testList.push_back(op->getOut()); } } } } +/// A form ending in a SUBPIECE, may be contained in a working form ending at +/// the SUBPIECE followed by INT_SRIGHT. The containing form would supersede. +/// \param op is the root of the form to check +/// \return \b true if it is (possibly) contained in a superseding form +bool RuleDivOpt::checkFormOverlap(PcodeOp *op) + +{ + if (op->code() != CPUI_SUBPIECE) return false; + Varnode *vn = op->getOut(); + list::const_iterator iter; + for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) { + PcodeOp *superOp = *iter; + OpCode opc = superOp->code(); + if (opc != CPUI_INT_RIGHT && opc != CPUI_INT_SRIGHT) continue; + Varnode *cvn = superOp->getIn(1); + if (!cvn->isConstant()) return true; // Might be a form where constant has propagated yet + int4 n,xsize; + uintb y; + OpCode extopc; + Varnode *inVn = findForm(superOp, n, y, xsize, extopc); + if (inVn != (Varnode *)0) return true; + } + return false; +} + /// \class RuleDivOpt /// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV /// @@ -7107,6 +7164,7 @@ int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data) OpCode extOpc; Varnode *inVn = findForm(op,n,y,xsize,extOpc); if (inVn == (Varnode *)0) return 0; + if (checkFormOverlap(op)) return 0; if (extOpc == CPUI_INT_SEXT) xsize -= 1; // one less bit for signed, because of signbit uintb divisor = calcDivisor(n,y,xsize); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh index 7f22e189db..a9ef933fe6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh @@ -1194,6 +1194,7 @@ public: class RuleDivOpt : public Rule { static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor static void moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data); + static bool checkFormOverlap(PcodeOp *op); ///< If form rooted at given PcodeOp is superseded by an overlapping form public: RuleDivOpt(const string &g) : Rule( g, 0, "divopt") {} ///< Constructor virtual Rule *clone(const ActionGroupList &grouplist) const {