mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02: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
6 changed files with 688 additions and 2 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue