mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-28 05:20:21 +00:00
GP-2292: The Decompiler now supports simplification of more forms of
optimized modulo/remainder calculations
This commit is contained in:
parent
a438a1e1ea
commit
7a2810a649
|
@ -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|
|
||||
|
|
|
@ -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") );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
129
Ghidra/Features/Decompiler/src/decompile/datatests/modulo.xml
Normal file
129
Ghidra/Features/Decompiler/src/decompile/datatests/modulo.xml
Normal 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 & 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\] & 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\] & 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 & 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\] & 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\] & 0x7f;</stringmatch>
|
||||
<stringmatch name="Modulo #40" min="1" max="1">ptrui\[9\] = ptrui\[9\] % 1000;</stringmatch>
|
||||
</decompilertest>
|
|
@ -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>
|
Loading…
Reference in a new issue