GP-2292: The Decompiler now supports simplification of more forms of

optimized modulo/remainder calculations
This commit is contained in:
caheckman 2022-09-02 16:23:08 -04:00 committed by Ryan Kurtz
parent a438a1e1ea
commit 7a2810a649
6 changed files with 688 additions and 2 deletions

View file

@ -27,6 +27,8 @@ src/decompile/datatests/impliedfield.xml||GHIDRA||||END|
src/decompile/datatests/indproto.xml||GHIDRA||||END|
src/decompile/datatests/loopcomment.xml||GHIDRA||||END|
src/decompile/datatests/mixfloatint.xml||GHIDRA||||END|
src/decompile/datatests/modulo.xml||GHIDRA||||END|
src/decompile/datatests/modulo2.xml||GHIDRA||||END|
src/decompile/datatests/multiret.xml||GHIDRA||||END|
src/decompile/datatests/namespace.xml||GHIDRA||||END|
src/decompile/datatests/nestedoffset.xml||GHIDRA||||END|

View file

@ -5065,9 +5065,14 @@ void ActionDatabase::universalAction(Architecture *conf)
actprop->addRule( new RuleDivTermAdd2("analysis") );
actprop->addRule( new RuleDivOpt("analysis") );
actprop->addRule( new RuleSignForm("analysis") );
actprop->addRule( new RuleSignForm2("analysis") );
actprop->addRule( new RuleSignDiv2("analysis") );
actprop->addRule( new RuleDivChain("analysis") );
actprop->addRule( new RuleSignNearMult("analysis") );
actprop->addRule( new RuleModOpt("analysis") );
actprop->addRule( new RuleSignMod2nOpt("analysis") );
actprop->addRule( new RuleSignMod2nOpt2("analysis") );
actprop->addRule( new RuleSignMod2Opt("analysis") );
actprop->addRule( new RuleSwitchSingle("analysis") );
actprop->addRule( new RuleCondNegate("analysis") );
actprop->addRule( new RuleBoolNegate("analysis") );

View file

@ -2957,7 +2957,7 @@ int4 RuleMultiCollapse::applyOp(PcodeOp *op,Funcdata &data)
else
nofunc = true; // Unwritten cannot match by functional equal
}
else if (*defcopyr == *copyr) continue; // A matching branch
else if (defcopyr == copyr) continue; // A matching branch
else if ((defcopyr!=copyr)&&(!nofunc)&&functionalEquality(defcopyr,copyr)) {
// Cannot match MULTIEQUAL by functional equality
// if (nofunc) return 0; // Not allowed to match by func equal
@ -6710,6 +6710,11 @@ int4 RuleSubRight::applyOp(PcodeOp *op,Funcdata &data)
if (outvn->getSize() + c == a->getSize()) {
// If SUB is "hi" lump the SUB and shift together
d += lone->getIn(1)->getOffset();
if (d >= a->getSize() * 8) {
if (opc2 == CPUI_INT_RIGHT)
return 0; // Result should have been 0
d = a->getSize() * 8 - 1; // sign extraction
}
data.opUnlink(op);
op = lone;
data.opSetOpcode(op,CPUI_SUBPIECE);
@ -6932,7 +6937,7 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
else
k = insize-c-outsize; // Or we can shrunk the cut
k = insize-c-outsize; // Or we can shrink the cut
}
// if n == k*8, then a shift is unnecessary
@ -6943,6 +6948,11 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
data.opSetInput(op,data.newConstant(4,c),1);
return 1;
}
else if (n >= outsize * 8) {
n = outsize * 8; // Can only shift so far
if (opc == CPUI_INT_SRIGHT)
n -= 1;
}
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_SUBPIECE);
@ -7570,6 +7580,59 @@ int4 RuleSignDiv2::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \class RuleDivChain
/// \brief Collapse two consecutive divisions: `(x / c1) / c2 => x / (c1*c2)`
void RuleDivChain::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_DIV);
oplist.push_back(CPUI_INT_SDIV);
}
int4 RuleDivChain::applyOp(PcodeOp *op,Funcdata &data)
{
OpCode opc2 = op->code();
Varnode *constVn2 = op->getIn(1);
if (!constVn2->isConstant()) return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
PcodeOp *divOp = vn->getDef();
OpCode opc1 = divOp->code();
if (opc1 != opc2 && (opc2 != CPUI_INT_DIV || opc1 != CPUI_INT_RIGHT))
return 0;
Varnode *constVn1 = divOp->getIn(1);
if (!constVn1->isConstant()) return 0;
// If the intermediate result is being used elsewhere, don't apply
// Its likely collapsing the divisions will interfere with the modulo rules
if (vn->loneDescend() == (PcodeOp *)0) return 0;
uintb val1;
if (opc1 == opc2) {
val1 = constVn1->getOffset();
}
else { // Unsigned case with INT_RIGHT
int4 sa = constVn1->getOffset();
val1 = 1;
val1 <<= sa;
}
Varnode *baseVn = divOp->getIn(0);
if (baseVn->isFree()) return 0;
int4 sz = vn->getSize();
uintb val2 = constVn2->getOffset();
uintb resval = (val1 * val2) & calc_mask(sz);
if (resval == 0) return 0;
if (signbit_negative(val1, sz))
val1 = (~val1 + 1) & calc_mask(sz);
if (signbit_negative(val2, sz))
val2 = (~val2 + 1) & calc_mask(sz);
int4 bitcount = mostsigbit_set(val1) + mostsigbit_set(val2) + 2;
if (opc2 == CPUI_INT_DIV && bitcount > sz * 8 ) return 0; // Unsigned overflow
if (opc2 == CPUI_INT_SDIV && bitcount > sz * 8 - 2) return 0; // Signed overflow
data.opSetInput(op, baseVn, 0);
data.opSetInput(op,data.newConstant(sz, resval), 1);
return 1;
}
/// \class RuleSignForm
/// \brief Normalize sign extraction: `sub(sext(V),c) => V s>> 31`
void RuleSignForm::getOpList(vector<uint4> &oplist) const
@ -7601,6 +7664,63 @@ int4 RuleSignForm::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \class RuleSignForm2
/// \brief Normalize sign extraction: `sub(sext(V) * small,c) s>> 31 => V s>> 31`
///
/// V and small must be small enough so that there is no overflow in the INT_MULT.
/// The SUBPIECE must be extracting the high part of the INT_MULT.
void RuleSignForm2::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleSignForm2::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant()) return 0;
Varnode *inVn = op->getIn(0);
int4 sizeout = inVn->getSize();
if ((int4)constVn->getOffset() != sizeout*8 -1) return 0;
if (!inVn->isWritten()) return 0;
PcodeOp *subOp = inVn->getDef();
if (subOp->code() != CPUI_SUBPIECE) return 0;
int4 c = subOp->getIn(1)->getOffset();
Varnode *multOut = subOp->getIn(0);
int4 multSize = multOut->getSize();
if (c + sizeout != multSize) return 0; // Must be extracting high part
if (!multOut->isWritten()) return 0;
PcodeOp *multOp = multOut->getDef();
if (multOp->code() != CPUI_INT_MULT) return 0;
int4 slot;
PcodeOp *sextOp;
for(slot=0;slot<2;++slot) { // Search for the INT_SEXT
Varnode *vn = multOp->getIn(slot);
if (!vn->isWritten()) continue;
sextOp = vn->getDef();
if (sextOp->code() == CPUI_INT_SEXT) break;
}
if (slot > 1) return 0;
Varnode *a = sextOp->getIn(0);
if (a->isFree() || a->getSize() != sizeout) return 0;
Varnode *otherVn = multOp->getIn(1-slot);
// otherVn must be a positive integer and small enough so the INT_MULT can't overflow into the sign-bit
if (otherVn->isConstant()) {
if (otherVn->getOffset() > calc_mask(sizeout)) return 0;
if (2 * sizeout > multSize) return 0;
}
else if (otherVn->isWritten()) {
PcodeOp *zextOp = otherVn->getDef();
if (zextOp->code() != CPUI_INT_ZEXT) return 0;
if (zextOp->getIn(0)->getSize() + sizeout > multSize) return 0;
}
else
return 0;
data.opSetInput(op, a, 0);
return 0;
}
/// \class RuleSignNearMult
/// \brief Simplify division form: `(V + (V s>> 0x1f)>>(32-n)) & (-1<<n) => (V s/ 2^n) * 2^n`
void RuleSignNearMult::getOpList(vector<uint4> &oplist) const
@ -7723,6 +7843,338 @@ int4 RuleModOpt::applyOp(PcodeOp *op,Funcdata &data)
return 0;
}
/// \class RuleSignMod2nOpt
/// \brief Convert INT_SREM forms: `(V + (sign >> (64-n)) & (2^n-1)) - (sign >> (64-n) => V s% 2^n`
///
/// Note: `sign = V s>> 63` The INT_AND may be performed on a truncated result and then reextended.
void RuleSignMod2nOpt::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSignMod2nOpt::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
int4 shiftAmt = op->getIn(1)->getOffset();
Varnode *a = checkSignExtraction(op->getIn(0));
if (a == (Varnode *)0 || a->isFree()) return 0;
Varnode *correctVn = op->getOut();
int4 n = a->getSize() * 8 - shiftAmt;
uintb mask = 1;
mask = (mask << n) - 1;
list<PcodeOp *>::const_iterator iter;
for(iter=correctVn->beginDescend();iter!=correctVn->endDescend();++iter) {
PcodeOp *multop = *iter;
if (multop->code() != CPUI_INT_MULT) continue;
Varnode *negone = multop->getIn(1);
if (!negone->isConstant()) continue;
if (negone->getOffset() != calc_mask(correctVn->getSize())) continue;
PcodeOp *baseOp = multop->getOut()->loneDescend();
if (baseOp == (PcodeOp *)0) continue;
if (baseOp->code() != CPUI_INT_ADD) continue;
int4 slot = 1 - baseOp->getSlot(multop->getOut());
Varnode *andOut = baseOp->getIn(slot);
if (!andOut->isWritten()) continue;
PcodeOp *andOp = andOut->getDef();
int4 truncSize = -1;
if (andOp->code() == CPUI_INT_ZEXT) { // Look for intervening extension after INT_AND
andOut = andOp->getIn(0);
if (!andOut->isWritten()) continue;
andOp = andOut->getDef();
if (andOp->code() != CPUI_INT_AND) continue;
truncSize = andOut->getSize(); // If so we have a truncated form
}
else if (andOp->code() != CPUI_INT_AND)
continue;
Varnode *constVn = andOp->getIn(1);
if (!constVn->isConstant()) continue;
if (constVn->getOffset() != mask) continue;
Varnode *addOut = andOp->getIn(0);
if (!addOut->isWritten()) continue;
PcodeOp *addOp = addOut->getDef();
if (addOp->code() != CPUI_INT_ADD) continue;
// Search for "a" as one of the inputs to addOp
int4 aSlot;
for(aSlot=0;aSlot < 2;++aSlot) {
Varnode *vn = addOp->getIn(aSlot);
if (truncSize >= 0) {
if (!vn->isWritten()) continue;
PcodeOp *subOp = vn->getDef();
if (subOp->code() != CPUI_SUBPIECE) continue;
if (subOp->getIn(1)->getOffset() != 0) continue;
vn = subOp->getIn(0);
}
if (a == vn) break;
}
if (aSlot > 1) continue;
// Verify that the other input to addOp is an INT_RIGHT by shiftAmt
Varnode *extVn = addOp->getIn(1-aSlot);
if (!extVn->isWritten()) continue;
PcodeOp *shiftOp = extVn->getDef();
if (shiftOp->code() != CPUI_INT_RIGHT) continue;
constVn = shiftOp->getIn(1);
if (!constVn->isConstant()) continue;
int4 shiftval = constVn->getOffset();
if (truncSize >= 0)
shiftval += (a->getSize() - truncSize) * 8;
if (shiftval != shiftAmt) continue;
// Verify that the input to INT_RIGHT is a sign extraction of "a"
extVn = checkSignExtraction(shiftOp->getIn(0));
if (extVn == (Varnode *)0) continue;
if (truncSize >= 0) {
if (!extVn->isWritten()) continue;
PcodeOp *subOp = extVn->getDef();
if (subOp->code() != CPUI_SUBPIECE) continue;
if ((int4)subOp->getIn(1)->getOffset() != truncSize) continue;
extVn = subOp->getIn(0);
}
if (a != extVn) continue;
data.opSetOpcode(baseOp, CPUI_INT_SREM);
data.opSetInput(baseOp, a, 0);
data.opSetInput(baseOp, data.newConstant(a->getSize(), mask+1), 1);
return 1;
}
return 0;
}
/// \brief Verify that the given Varnode is a sign extraction of the form `V s>> 63`
///
/// If not, null is returned. Otherwise the Varnode whose sign is extracted is returned.
/// \param outVn is the given Varnode
/// \return the Varnode being extracted or null
Varnode *RuleSignMod2nOpt::checkSignExtraction(Varnode *outVn)
{
if (!outVn->isWritten()) return 0;
PcodeOp *signOp = outVn->getDef();
if (signOp->code() != CPUI_INT_SRIGHT)
return (Varnode *)0;
Varnode *constVn = signOp->getIn(1);
if (!constVn->isConstant())
return (Varnode *)0;
int4 val = constVn->getOffset();
Varnode *resVn = signOp->getIn(0);
int4 insize = resVn->getSize();
if (val != insize*8 - 1)
return (Varnode *)0;
return resVn;
}
/// \class RuleSignMod2Opt
/// \brief Convert INT_SREM form: `(V - sign)&1 + sign => V s% 2`
///
/// Note: `sign = V s>> 63` The INT_AND may be performed on a truncated result and then reextended.
/// This is a specialized form of RuleSignMod2nOpt.
void RuleSignMod2Opt::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSignMod2Opt::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant()) return 0;
if (constVn->getOffset() != 1) return 0;
Varnode *addOut = op->getIn(0);
if (!addOut->isWritten()) return 0;
PcodeOp *addOp = addOut->getDef();
if (addOp->code() != CPUI_INT_ADD) return 0;
int4 multSlot;
PcodeOp *multOp;
bool trunc = false;
for(multSlot = 0;multSlot < 2;++multSlot) {
Varnode *vn = addOp->getIn(multSlot);
if (!vn->isWritten()) continue;
multOp = vn->getDef();
if (multOp->code() != CPUI_INT_MULT) continue;
constVn = multOp->getIn(1);
if (!constVn->isConstant()) continue;
if (constVn->getOffset() == calc_mask(constVn->getSize())) break; // Check for INT_MULT by -1
}
if (multSlot > 1) return 0;
Varnode *base = RuleSignMod2nOpt::checkSignExtraction(multOp->getIn(0));
if (base == (Varnode *)0) return 0;
Varnode *otherBase = addOp->getIn(1-multSlot);
if (base != otherBase) {
if (!base->isWritten() || !otherBase->isWritten()) return 0;
PcodeOp *subOp = base->getDef();
if (subOp->code() != CPUI_SUBPIECE) return 0;
int4 truncAmt = subOp->getIn(1)->getOffset();
if (truncAmt + base->getSize() != subOp->getIn(0)->getSize()) return 0; // Must truncate all but high part
base = subOp->getIn(0);
subOp = otherBase->getDef();
if (subOp->code() != CPUI_SUBPIECE) return 0;
if (subOp->getIn(1)->getOffset() != 0) return 0;
otherBase = subOp->getIn(0);
if (otherBase != base) return 0;
trunc = true;
}
if (base->isFree()) return 0;
Varnode *andOut = op->getOut();
if (trunc) {
PcodeOp *extOp = andOut->loneDescend();
if (extOp == (PcodeOp *)0 || extOp->code() != CPUI_INT_ZEXT) return 0;
andOut = extOp->getOut();
}
list<PcodeOp *>::const_iterator iter;
for(iter=andOut->beginDescend();iter!=andOut->endDescend();++iter) {
PcodeOp *rootOp = *iter;
if (rootOp->code() != CPUI_INT_ADD) continue;
int4 slot = rootOp->getSlot(andOut);
otherBase = RuleSignMod2nOpt::checkSignExtraction(rootOp->getIn(1-slot));
if (otherBase != base) continue;
data.opSetOpcode(rootOp, CPUI_INT_SREM);
data.opSetInput(rootOp,base,0);
data.opSetInput(rootOp,data.newConstant(base->getSize(), 2),1);
return 1;
}
return 0;
}
/// \class RuleSignMod2nOpt2
/// \brief Convert INT_SREM form: `V - (Vadj & ~(2^n-1)) => V s% 2^n`
///
/// Note: `Vadj = (V<0) ? V + 2^n-1 : V`
void RuleSignMod2nOpt2::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_MULT);
}
int4 RuleSignMod2nOpt2::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant()) return 0;
uintb mask = calc_mask(constVn->getSize());
if (constVn->getOffset() != mask) return 0; // Must be INT_MULT by -1
Varnode *andOut = op->getIn(0);
if (!andOut->isWritten()) return 0;
PcodeOp *andOp = andOut->getDef();
if (andOp->code() != CPUI_INT_AND) return 0;
constVn = andOp->getIn(1);
if (!constVn->isConstant()) return 0;
uintb npow = (~constVn->getOffset() + 1) & mask;
if (popcount(npow) != 1) return 0; // constVn must be of form 11111..000..
if (npow == 1) return 0;
Varnode *adjVn = andOp->getIn(0);
if (!adjVn->isWritten()) return 0;
PcodeOp *adjOp = adjVn->getDef();
Varnode *base;
if (adjOp->code() == CPUI_INT_ADD) {
if (npow != 2) return 0; // Special mod 2 form
base = checkSignExtForm(adjOp);
}
else if (adjOp->code() == CPUI_MULTIEQUAL) {
base = checkMultiequalForm(adjOp, npow);
}
else
return 0;
if (base == (Varnode *)0) return 0;
if (base->isFree()) return 0;
Varnode *multOut = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=multOut->beginDescend();iter!=multOut->endDescend();++iter) {
PcodeOp *rootOp = *iter;
if (rootOp->code() != CPUI_INT_ADD) continue;
int4 slot = rootOp->getSlot(multOut);
if (rootOp->getIn(1-slot) != base) continue;
if (slot == 0)
data.opSetInput(rootOp,base,0);
data.opSetInput(rootOp, data.newConstant(base->getSize(),npow), 1);
data.opSetOpcode(rootOp, CPUI_INT_SREM);
return 1;
}
return 0;
}
/// \brief Verify a form of `V - (V s>> 0x3f)`
///
/// \param op is the possible root INT_ADD of the form
/// \return the Varnode V in the form, or null if the form doesn't match
Varnode *RuleSignMod2nOpt2::checkSignExtForm(PcodeOp *op)
{
int4 slot;
for(slot=0;slot<2;++slot) {
Varnode *minusVn = op->getIn(slot);
if (!minusVn->isWritten()) continue;
PcodeOp *multOp = minusVn->getDef();
if (multOp->code() != CPUI_INT_MULT) continue;
Varnode *constVn = multOp->getIn(1);
if (!constVn->isConstant()) continue;
if (constVn->getOffset() != calc_mask(constVn->getSize())) continue;
Varnode *base = op->getIn(1-slot);
Varnode *signExt = multOp->getIn(0);
if (!signExt->isWritten()) continue;
PcodeOp *shiftOp = signExt->getDef();
if (shiftOp->code() != CPUI_INT_SRIGHT) continue;
if (shiftOp->getIn(0) != base) continue;
constVn = shiftOp->getIn(1);
if (!constVn->isConstant()) continue;
if ((int4)constVn->getOffset() != 8*base->getSize() - 1) continue;
return base;
}
return (Varnode *)0;
}
/// \brief Verify an \e if block like `V = (V s< 0) ? V + 2^n-1 : V`
///
/// \param op is the MULTIEQUAL
/// \param npos is the constant 2^n
/// \return the Varnode V in the form, or null if the form doesn't match
Varnode *RuleSignMod2nOpt2::checkMultiequalForm(PcodeOp *op,uintb npow)
{
if (op->numInput() != 2) return (Varnode *)0;
npow -= 1; // 2^n - 1
int4 slot;
Varnode *base;
for(slot=0;slot<op->numInput();++slot) {
Varnode *addOut = op->getIn(slot);
if (!addOut->isWritten()) continue;
PcodeOp *addOp = addOut->getDef();
if (addOp->code() != CPUI_INT_ADD) continue;
Varnode *constVn = addOp->getIn(1);
if (!constVn->isConstant()) continue;
if (constVn->getOffset() != npow) continue;
base = addOp->getIn(0);
Varnode *otherBase = op->getIn(1-slot);
if (otherBase == base)
break;
}
if (slot > 1) return (Varnode *)0;
BlockBasic *bl = op->getParent();
int4 innerSlot = 0;
BlockBasic *inner = (BlockBasic*)bl->getIn(innerSlot);
if (inner->sizeOut() != 1 || inner->sizeIn() != 1) {
innerSlot = 1;
inner = (BlockBasic*)bl->getIn(innerSlot);
if (inner->sizeOut() != 1 || inner->sizeIn() != 1)
return (Varnode *)0;
}
BlockBasic *decision = (BlockBasic*)inner->getIn(0);
if (bl->getIn(1 - innerSlot) != decision) return (Varnode *)0;
PcodeOp *cbranch = decision->lastOp();
if (cbranch == (PcodeOp*)0 || cbranch->code() != CPUI_CBRANCH) return (Varnode *)0;
Varnode *boolVn = cbranch->getIn(1);
if (!boolVn->isWritten()) return (Varnode *)0;
PcodeOp *lessOp = boolVn->getDef();
if (lessOp->code() != CPUI_INT_SLESS) return (Varnode *)0;
if (!lessOp->getIn(1)->isConstant()) return (Varnode *)0;
if (lessOp->getIn(1)->getOffset() != 0) return (Varnode *)0;
FlowBlock *negBlock = cbranch->isBooleanFlip() ? decision->getFalseOut() : decision->getTrueOut();
int4 negSlot = (negBlock == inner) ? innerSlot : (1-innerSlot);
if (negSlot != slot) return (Varnode *)0;
return base;
}
/// \class RuleSegment
/// \brief Propagate constants through a SEGMENTOP
void RuleSegment::getOpList(vector<uint4> &oplist) const

View file

@ -1237,6 +1237,17 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleDivChain : public Rule {
public:
RuleDivChain(const string &g) : Rule( g, 0, "divchain") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleDivChain(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSignForm : public Rule {
public:
RuleSignForm(const string &g) : Rule( g, 0, "signform") {} ///< Constructor
@ -1248,6 +1259,17 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSignForm2 : public Rule {
public:
RuleSignForm2(const string &g) : Rule( g, 0, "signform2") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSignForm2(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSignNearMult : public Rule {
public:
RuleSignNearMult(const string &g) : Rule( g, 0, "signnearmult") {} ///< Constructor
@ -1270,6 +1292,42 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSignMod2nOpt : public Rule {
public:
RuleSignMod2nOpt(const string &g) : Rule( g, 0, "signmod2nopt") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSignMod2nOpt(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
static Varnode *checkSignExtraction(Varnode *outVn);
};
class RuleSignMod2Opt : public Rule {
public:
RuleSignMod2Opt(const string &g) : Rule( g, 0, "signmod2opt") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSignMod2Opt(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSignMod2nOpt2 : public Rule {
static Varnode *checkMultiequalForm(PcodeOp *op,uintb npow);
static Varnode *checkSignExtForm(PcodeOp *op);
public:
RuleSignMod2nOpt2(const string &g) : Rule( g, 0, "signmod2nopt2") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSignMod2nOpt2(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSegment : public Rule {
public:
RuleSegment(const string &g) : Rule( g, 0, "segment") {} ///< Constructor

View file

@ -0,0 +1,129 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
Examples of optimized modulo calculations.
-->
<bytechunk space="ram" offset="0x10064a" readonly="true">
415455534989
d0488b074889c248c1ea3f4801d083e0
014829d04889074c8b4f0848ba565555
55555555554c89c848f7ea4c89c848c1
f83f4829c2488d04524929c14c894f08
488b4710489948c1ea3e4801d083e003
4829d0488947104c8b571849b9676666
66666666664c89d049f7e948d1fa4c89
d048c1f83f4829c2488d04924929c24c
8957184c8b572048baabaaaaaaaaaaaa
2a4c89d048f7ea4c89d048c1f83f4829
c2488d04524801c04929c24c8957204c
8b57284c89d049f7e948c1fa024c89d0
48c1f83f4829c2488d04924801c04929
c24c8957284c8b573049b98988888888
8888884c89d049f7e94c01d248c1fa05
4c89d048c1f83f4829c24889d048c1e0
044829d048c1e0024929c24c8957304c
8b573848ba0bd7a3703d0ad7a34c89d0
48f7ea4a8d041248c1f8064c89d248c1
fa3f4829d0488d0480488d048048c1e0
024929c24c895738488b4740489948c1
ea394801d083e07f4829d0488947404c
8b5f4849bacff753e3a59bc4204c89d8
49f7ea48c1fa074c89d848c1f83f4829
c24869d2e80300004929d34c895f488b
0689c2c1ea1f01d083e00129d089068b
7e04ba5655555589f8f7ea89f8c1f81f
29c28d045229c7897e048b460899c1ea
1e01d083e00329d0894608448b5e0cbf
676666664489d8f7efd1fa4489d8c1f8
1f29c28d04924129c344895e0c448b5e
10baabaaaa2a4489d8f7ea4489d8c1f8
1f29c28d045201c04129c344895e1044
8b5e144489d8f7efc1fa024489d8c1f8
1f29c28d049201c04129c344895e1444
8b5e18bb898888884489d8f7eb428d3c
1ac1ff054489d8c1f81f29c76bff3c41
29fb44895e188b7e1c41bb1f85eb5189
f841f7ebc1fa0589f8c1f81f29c26bd2
6429d7897e1c8b462099c1ea1901d083
e07f29d08946208b6e24bfd34d621089
e8f7efc1fa0689e8c1f81f29c269d2e8
03000029d5896e2449832001498b7008
48bdabaaaaaaaaaaaaaa4889f048f7e5
48d1ea488d04524829c6498970084983
6010034d8b601848becdcccccccccccc
cc4c89e048f7e648c1ea02488d049249
29c44d8960184d8b60204c89e048f7e5
48c1ea02488d04524801c04929c44d89
6020498b68284889e848f7e648c1ea03
488d04924801c04829c549896828498b
70304889f049f7e148c1ea054889d048
c1e0044829d048c1e0024829c6498970
30498b70384889f248c1ea0249b9c3f5
285c8fc2f5284889d049f7e148c1ea02
488d0492488d048048c1e0024829c649
897038498360407f498b70484889f248
c1ea034889d049f7e248c1ea044c69d2
e80300004c29d6498970488321018b71
0441b8abaaaaaa89f041f7e0d1ea8d04
5229c689710483610803448b490cbecd
cccccc4489c8f7e6c1ea028d04924129
c14489490c448b49104489c841f7e0c1
ea028d045201c04129c144894910448b
41144489c0f7e6c1ea038d049201c041
29c0448941148b711889f0f7e389d3c1
eb056bdb3c29de8971188b711c89f041
f7e34189d341c1eb05456bdb644429de
89711c8361207f8b712489f0f7e789d7
c1ef0669ffe803000029fe8971245b5d
415cc3
</bytechunk>
<symbol space="ram" offset="0x10064a" name="remtest"/>
</binaryimage>
<script>
<com>parse line extern void remtest(int8 *ptrl,int4 *ptri,uint8 *ptrul,uint4 *ptrui);</com>
<com>lo fu remtest</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Modulo #1" min="1" max="1">\*ptrl = \*ptrl % 2;</stringmatch>
<stringmatch name="Modulo #2" min="1" max="1">ptrl\[1\] = ptrl\[1\] % 3;</stringmatch>
<stringmatch name="Modulo #3" min="1" max="1">ptrl\[2\] = ptrl\[2\] % 4;</stringmatch>
<stringmatch name="Modulo #4" min="1" max="1">ptrl\[3\] = ptrl\[3\] % 5;</stringmatch>
<stringmatch name="Modulo #5" min="1" max="1">ptrl\[4\] = ptrl\[4\] % 6;</stringmatch>
<stringmatch name="Modulo #6" min="1" max="1">ptrl\[5\] = ptrl\[5\] % 10;</stringmatch>
<stringmatch name="Modulo #7" min="1" max="1">ptrl\[6\] = ptrl\[6\] % 0x3c;</stringmatch>
<stringmatch name="Modulo #8" min="1" max="1">ptrl\[7\] = ptrl\[7\] % 100;</stringmatch>
<stringmatch name="Modulo #9" min="1" max="1">ptrl\[8\] = ptrl\[8\] % 0x80;</stringmatch>
<stringmatch name="Modulo #10" min="1" max="1">ptrl\[9\] = ptrl\[9\] % 1000;</stringmatch>
<stringmatch name="Modulo #11" min="1" max="1">\*ptri = \*ptri % 2;</stringmatch>
<stringmatch name="Modulo #12" min="1" max="1">ptri\[1\] = ptri\[1\] % 3;</stringmatch>
<stringmatch name="Modulo #13" min="1" max="1">ptri\[2\] = ptri\[2\] % 4;</stringmatch>
<stringmatch name="Modulo #14" min="1" max="1">ptri\[3\] = ptri\[3\] % 5;</stringmatch>
<stringmatch name="Modulo #15" min="1" max="1">ptri\[4\] = ptri\[4\] % 6;</stringmatch>
<stringmatch name="Modulo #16" min="1" max="1">ptri\[5\] = ptri\[5\] % 10;</stringmatch>
<stringmatch name="Modulo #17" min="1" max="1">ptri\[6\] = ptri\[6\] % 0x3c;</stringmatch>
<stringmatch name="Modulo #18" min="1" max="1">ptri\[7\] = ptri\[7\] % 100;</stringmatch>
<stringmatch name="Modulo #19" min="1" max="1">ptri\[8\] = ptri\[8\] % 0x80;</stringmatch>
<stringmatch name="Modulo #20" min="1" max="1">ptri\[9\] = ptri\[9\] % 1000;</stringmatch>
<stringmatch name="Modulo #21" min="1" max="1">\*ptrul = \*ptrul &amp; 1;</stringmatch>
<stringmatch name="Modulo #22" min="1" max="1">ptrul\[1\] = ptrul\[1\] % 3;</stringmatch>
<stringmatch name="Modulo #23" min="1" max="1">ptrul\[2\] = ptrul\[2\] &amp; 3;</stringmatch>
<stringmatch name="Modulo #24" min="1" max="1">ptrul\[3\] = ptrul\[3\] % 5;</stringmatch>
<stringmatch name="Modulo #25" min="1" max="1">ptrul\[4\] = ptrul\[4\] % 6;</stringmatch>
<stringmatch name="Modulo #26" min="1" max="1">ptrul\[5\] = ptrul\[5\] % 10;</stringmatch>
<stringmatch name="Modulo #27" min="1" max="1">ptrul\[6\] = ptrul\[6\] % 0x3c;</stringmatch>
<stringmatch name="Modulo #28" min="1" max="1">ptrul\[7\] = ptrul\[7\] % 100;</stringmatch>
<stringmatch name="Modulo #29" min="1" max="1">ptrul\[8\] = ptrul\[8\] &amp; 0x7f;</stringmatch>
<stringmatch name="Modulo #30" min="1" max="1">ptrul\[9\] = ptrul\[9\] % 1000;</stringmatch>
<stringmatch name="Modulo #31" min="1" max="1">\*ptrui = \*ptrui &amp; 1;</stringmatch>
<stringmatch name="Modulo #32" min="1" max="1">ptrui\[1\] = ptrui\[1\] % 3;</stringmatch>
<stringmatch name="Modulo #33" min="1" max="1">ptrui\[2\] = ptrui\[2\] &amp; 3;</stringmatch>
<stringmatch name="Modulo #34" min="1" max="1">ptrui\[3\] = ptrui\[3\] % 5;</stringmatch>
<stringmatch name="Modulo #35" min="1" max="1">ptrui\[4\] = ptrui\[4\] % 6;</stringmatch>
<stringmatch name="Modulo #36" min="1" max="1">ptrui\[5\] = ptrui\[5\] % 10;</stringmatch>
<stringmatch name="Modulo #37" min="1" max="1">ptrui\[6\] = ptrui\[6\] % 0x3c;</stringmatch>
<stringmatch name="Modulo #38" min="1" max="1">ptrui\[7\] = ptrui\[7\] % 100;</stringmatch>
<stringmatch name="Modulo #39" min="1" max="1">ptrui\[8\] = ptrui\[8\] &amp; 0x7f;</stringmatch>
<stringmatch name="Modulo #40" min="1" max="1">ptrui\[9\] = ptrui\[9\] % 1000;</stringmatch>
</decompilertest>

View file

@ -0,0 +1,40 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:windows">
<!--
More signed modulo forms
-->
<bytechunk space="ram" offset="0x180007050" readonly="true">
89c8c1e91f01c183e1fe29c8c3000000
4863c14869c8565555554889ca48c1ea
3f48c1e92001d18d0c4929c8c3000000
89c88d480385c00f49c883e1fc29c8c3
</bytechunk>
<bytechunk space="ram" offset="0x1800070b0" readonly="true">
4863c14869c8abaaaa2a4889ca48c1ea
3f48c1e92001d101c98d0c4929c8c3
</bytechunk>
<symbol space="ram" offset="0x180007050" name="mod2"/>
<symbol space="ram" offset="0x180007060" name="mod3"/>
<symbol space="ram" offset="0x180007080" name="mod4"/>
<symbol space="ram" offset="0x1800070b0" name="mod6"/>
</binaryimage>
<script>
<com>lo fu mod2</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu mod3</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu mod4</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu mod6</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="ModuloAlt #1" min="1" max="1">return param_1 % 2</stringmatch>
<stringmatch name="ModuloAlt #2" min="1" max="1">return param_1 % 3</stringmatch>
<stringmatch name="ModuloAlt #3" min="1" max="1">return param_1 % 4</stringmatch>
<stringmatch name="ModuloAlt #4" min="1" max="1">return param_1 % 6</stringmatch>
</decompilertest>