mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
An optimized division corner case
This commit is contained in:
parent
90f6b5c7e5
commit
77b1a6bf4b
3 changed files with 89 additions and 15 deletions
|
@ -529,7 +529,22 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
|
||||||
break;
|
break;
|
||||||
case CPUI_SUBPIECE:
|
case CPUI_SUBPIECE:
|
||||||
resmask = getIn(0)->getNZMask();
|
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;
|
resmask &= fullmask;
|
||||||
break;
|
break;
|
||||||
case CPUI_PIECE:
|
case CPUI_PIECE:
|
||||||
|
@ -540,11 +555,11 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const
|
||||||
case CPUI_INT_MULT:
|
case CPUI_INT_MULT:
|
||||||
val = getIn(0)->getNZMask();
|
val = getIn(0)->getNZMask();
|
||||||
resmask = getIn(1)->getNZMask();
|
resmask = getIn(1)->getNZMask();
|
||||||
sz1 = mostsigbit_set(val);
|
sz1 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(val);
|
||||||
if (sz1 == -1)
|
if (sz1 == -1)
|
||||||
resmask = 0;
|
resmask = 0;
|
||||||
else {
|
else {
|
||||||
sz2 = mostsigbit_set(resmask);
|
sz2 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(resmask);
|
||||||
if (sz2 == -1)
|
if (sz2 == -1)
|
||||||
resmask = 0;
|
resmask = 0;
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -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
|
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT
|
||||||
Varnode *inVn = curOp->getIn(0);
|
Varnode *inVn = curOp->getIn(0);
|
||||||
if (!inVn->isWritten()) return (Varnode *)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;
|
Varnode *resVn;
|
||||||
PcodeOp *extOp = inVn->getDef();
|
PcodeOp *extOp = inVn->getDef();
|
||||||
|
@ -7062,29 +7067,81 @@ uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
|
||||||
/// - `V >> 0x1f`
|
/// - `V >> 0x1f`
|
||||||
/// - `V s>> 0x1f`
|
/// - `V s>> 0x1f`
|
||||||
///
|
///
|
||||||
|
/// Allow for the value to be COPYed around.
|
||||||
/// \param firstVn is the first given Varnode
|
/// \param firstVn is the first given Varnode
|
||||||
/// \param replaceVn is the Varnode to replace it with in each extraction
|
/// \param replaceVn is the Varnode to replace it with in each extraction
|
||||||
/// \param data is the function holding the Varnodes
|
/// \param data is the function holding the Varnodes
|
||||||
void RuleDivOpt::moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data)
|
void RuleDivOpt::moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
list<PcodeOp *>::const_iterator iter = firstVn->beginDescend();
|
vector<Varnode *> testList;
|
||||||
while(iter!=firstVn->endDescend()) {
|
testList.push_back(firstVn);
|
||||||
PcodeOp *op = *iter;
|
if (firstVn->isWritten()) {
|
||||||
++iter; // Increment before modifying the op
|
PcodeOp *op = firstVn->getDef();
|
||||||
OpCode opc = op->code();
|
if (op->code() == CPUI_INT_SRIGHT) {
|
||||||
if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) {
|
// Same sign bit could be extracted from previous shifted version
|
||||||
Varnode *constVn = op->getIn(1);
|
testList.push_back(op->getIn(0));
|
||||||
if (constVn->isConstant()) {
|
}
|
||||||
int4 sa = firstVn->getSize() * 8 - 1;
|
}
|
||||||
if (sa == (int4)constVn->getOffset()) {
|
for(int4 i=0;i<testList.size();++i) {
|
||||||
data.opSetInput(op,replaceVn,0);
|
Varnode *vn = testList[i];
|
||||||
|
list<PcodeOp *>::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<PcodeOp *>::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
|
/// \class RuleDivOpt
|
||||||
/// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV
|
/// \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;
|
OpCode extOpc;
|
||||||
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
|
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
|
||||||
if (inVn == (Varnode *)0) return 0;
|
if (inVn == (Varnode *)0) return 0;
|
||||||
|
if (checkFormOverlap(op)) return 0;
|
||||||
if (extOpc == CPUI_INT_SEXT)
|
if (extOpc == CPUI_INT_SEXT)
|
||||||
xsize -= 1; // one less bit for signed, because of signbit
|
xsize -= 1; // one less bit for signed, because of signbit
|
||||||
uintb divisor = calcDivisor(n,y,xsize);
|
uintb divisor = calcDivisor(n,y,xsize);
|
||||||
|
|
|
@ -1194,6 +1194,7 @@ public:
|
||||||
class RuleDivOpt : public Rule {
|
class RuleDivOpt : public Rule {
|
||||||
static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor
|
static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor
|
||||||
static void moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data);
|
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:
|
public:
|
||||||
RuleDivOpt(const string &g) : Rule( g, 0, "divopt") {} ///< Constructor
|
RuleDivOpt(const string &g) : Rule( g, 0, "divopt") {} ///< Constructor
|
||||||
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue