mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Collapse double multiplies during ptrarith
This commit is contained in:
parent
9802ba970e
commit
6df091eeee
3 changed files with 70 additions and 35 deletions
|
@ -507,8 +507,9 @@ public:
|
|||
void switchEdge(FlowBlock *inblock,BlockBasic *outbefore,FlowBlock *outafter);
|
||||
void spliceBlockBasic(BlockBasic *bl); ///< Merge the given basic block with the block it flows into
|
||||
void installSwitchDefaults(void); ///< Make sure default switch cases are properly labeled
|
||||
static bool replaceLessequal(Funcdata &data,PcodeOp *op); ///< Replace INT_LESSEQUAL and INT_SLESSEQUAL expressions
|
||||
static bool distributeIntMult(Funcdata &data,PcodeOp *op); ///< Distribute constant coefficient to additive input
|
||||
bool replaceLessequal(PcodeOp *op); ///< Replace INT_LESSEQUAL and INT_SLESSEQUAL expressions
|
||||
bool distributeIntMultAdd(PcodeOp *op); ///< Distribute constant coefficient to additive input
|
||||
bool collapseIntMultMult(Varnode *vn); ///< Collapse constant coefficients for two chained CPUI_INT_MULT
|
||||
static bool compareCallspecs(const FuncCallSpecs *a,const FuncCallSpecs *b);
|
||||
|
||||
#ifdef OPACTION_DEBUG
|
||||
|
|
|
@ -969,10 +969,9 @@ void Funcdata::overrideFlow(const Address &addr,uint4 type)
|
|||
/// - `c <= x` with `c-1 < x` OR
|
||||
/// - `x <= c` with `x < c+1`
|
||||
///
|
||||
/// \param data is the function being analyzed
|
||||
/// \param op is comparison PcodeOp
|
||||
/// \return true if a valid replacement was performed
|
||||
bool Funcdata::replaceLessequal(Funcdata &data,PcodeOp *op)
|
||||
bool Funcdata::replaceLessequal(PcodeOp *op)
|
||||
|
||||
{
|
||||
Varnode *vn;
|
||||
|
@ -995,17 +994,17 @@ bool Funcdata::replaceLessequal(Funcdata &data,PcodeOp *op)
|
|||
if (op->code() == CPUI_INT_SLESSEQUAL) {
|
||||
if ((val<0)&&(val+diff>0)) return false; // Check for sign overflow
|
||||
if ((val>0)&&(val+diff<0)) return false;
|
||||
data.opSetOpcode(op,CPUI_INT_SLESS);
|
||||
opSetOpcode(op,CPUI_INT_SLESS);
|
||||
}
|
||||
else { // Check for unsigned overflow
|
||||
if ((diff==-1)&&(val==0)) return false;
|
||||
if ((diff==1)&&(val==-1)) return false;
|
||||
data.opSetOpcode(op,CPUI_INT_LESS);
|
||||
opSetOpcode(op,CPUI_INT_LESS);
|
||||
}
|
||||
uintb res = (val+diff) & calc_mask(vn->getSize());
|
||||
Varnode *newvn = data.newConstant(vn->getSize(),res);
|
||||
Varnode *newvn = newConstant(vn->getSize(),res);
|
||||
newvn->copySymbol(vn); // Preserve data-type (and any Symbol info)
|
||||
data.opSetInput(op,newvn,i);
|
||||
opSetInput(op,newvn,i);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1013,10 +1012,9 @@ bool Funcdata::replaceLessequal(Funcdata &data,PcodeOp *op)
|
|||
/// in some situations we may need to distribute the coefficient before simplifying further.
|
||||
/// The given PcodeOp is a INT_MULT where the second input is a constant. We also
|
||||
/// know the first input is formed with INT_ADD. Distribute the coefficient to the INT_ADD inputs.
|
||||
/// \param data is the function being analyzed
|
||||
/// \param op is the given PcodeOp
|
||||
/// \return \b truee if the action was performed
|
||||
bool Funcdata::distributeIntMult(Funcdata &data,PcodeOp *op)
|
||||
/// \return \b true if the action was performed
|
||||
bool Funcdata::distributeIntMultAdd(PcodeOp *op)
|
||||
|
||||
{
|
||||
Varnode *newvn0,*newvn1;
|
||||
|
@ -1031,40 +1029,73 @@ bool Funcdata::distributeIntMult(Funcdata &data,PcodeOp *op)
|
|||
if (vn0->isConstant()) {
|
||||
uintb val = coeff * vn0->getOffset();
|
||||
val &= calc_mask(size);
|
||||
newvn0 = data.newConstant(size,val);
|
||||
newvn0 = newConstant(size,val);
|
||||
}
|
||||
else {
|
||||
PcodeOp *newop0 = data.newOp(2,op->getAddr());
|
||||
data.opSetOpcode(newop0,CPUI_INT_MULT);
|
||||
newvn0 = data.newUniqueOut(size,newop0);
|
||||
data.opSetInput(newop0, vn0, 0); // To first input of original add
|
||||
Varnode *newcvn = data.newConstant(size,coeff);
|
||||
data.opSetInput(newop0, newcvn, 1);
|
||||
data.opInsertBefore(newop0, op);
|
||||
PcodeOp *newop0 = newOp(2,op->getAddr());
|
||||
opSetOpcode(newop0,CPUI_INT_MULT);
|
||||
newvn0 = newUniqueOut(size,newop0);
|
||||
opSetInput(newop0, vn0, 0); // To first input of original add
|
||||
Varnode *newcvn = newConstant(size,coeff);
|
||||
opSetInput(newop0, newcvn, 1);
|
||||
opInsertBefore(newop0, op);
|
||||
}
|
||||
|
||||
if (vn1->isConstant()) {
|
||||
uintb val = coeff * vn1->getOffset();
|
||||
val &= calc_mask(size);
|
||||
newvn1 = data.newConstant(size,val);
|
||||
newvn1 = newConstant(size,val);
|
||||
}
|
||||
else {
|
||||
PcodeOp *newop1 = data.newOp(2,op->getAddr());
|
||||
data.opSetOpcode(newop1,CPUI_INT_MULT);
|
||||
newvn1 = data.newUniqueOut(size,newop1);
|
||||
data.opSetInput(newop1, vn1, 0); // To second input of original add
|
||||
Varnode *newcvn = data.newConstant(size,coeff);
|
||||
data.opSetInput(newop1, newcvn, 1);
|
||||
data.opInsertBefore(newop1, op);
|
||||
PcodeOp *newop1 = newOp(2,op->getAddr());
|
||||
opSetOpcode(newop1,CPUI_INT_MULT);
|
||||
newvn1 = newUniqueOut(size,newop1);
|
||||
opSetInput(newop1, vn1, 0); // To second input of original add
|
||||
Varnode *newcvn = newConstant(size,coeff);
|
||||
opSetInput(newop1, newcvn, 1);
|
||||
opInsertBefore(newop1, op);
|
||||
}
|
||||
|
||||
data.opSetInput( op, newvn0, 0); // new ADD's inputs are outputs of new MULTs
|
||||
data.opSetInput( op, newvn1, 1);
|
||||
data.opSetOpcode(op, CPUI_INT_ADD);
|
||||
opSetInput( op, newvn0, 0); // new ADD's inputs are outputs of new MULTs
|
||||
opSetInput( op, newvn1, 1);
|
||||
opSetOpcode(op, CPUI_INT_ADD);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// If:
|
||||
/// - The given Varnode is defined by a CPUI_INT_MULT.
|
||||
/// - The second input to the INT_MULT is a constant.
|
||||
/// - The first input is defined by another CPUI_INT_MULT,
|
||||
/// - This multiply is also by a constant.
|
||||
///
|
||||
/// The constants are combined and \b true is returned.
|
||||
/// Otherwise no change is made and \b false is returned.
|
||||
/// \param vn is the given Varnode
|
||||
/// \return \b true if a change was made
|
||||
bool Funcdata::collapseIntMultMult(Varnode *vn)
|
||||
|
||||
{
|
||||
if (!vn->isWritten()) return false;
|
||||
PcodeOp *op = vn->getDef();
|
||||
if (op->code() != CPUI_INT_MULT) return false;
|
||||
Varnode *constVnFirst = op->getIn(1);
|
||||
if (!constVnFirst->isConstant()) return false;
|
||||
if (!op->getIn(0)->isWritten()) return false;
|
||||
PcodeOp *otherMultOp = op->getIn(0)->getDef();
|
||||
if (otherMultOp->code() != CPUI_INT_MULT) return false;
|
||||
Varnode *constVnSecond = otherMultOp->getIn(1);
|
||||
if (!constVnSecond->isConstant()) return false;
|
||||
Varnode *invn = otherMultOp->getIn(0);
|
||||
if (invn->isFree()) return false;
|
||||
int4 size = invn->getSize();
|
||||
uintb val = (constVnFirst->getOffset() * constVnSecond->getOffset()) & calc_mask(size);
|
||||
Varnode *newvn = newConstant(size,val);
|
||||
opSetInput(op,newvn,1);
|
||||
opSetInput(op,invn,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Trace a boolean value to a set of PcodeOps that can be changed to flip the boolean value
|
||||
///
|
||||
/// The boolean Varnode is either the output of the given PcodeOp or the
|
||||
|
@ -1162,7 +1193,7 @@ void opFlipInPlaceExecute(Funcdata &data,vector<PcodeOp *> &fliplist)
|
|||
data.opSwapInput(op,0,1);
|
||||
|
||||
if ((opc == CPUI_INT_LESSEQUAL)||(opc == CPUI_INT_SLESSEQUAL))
|
||||
Funcdata::replaceLessequal(data,op);
|
||||
data.replaceLessequal(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,9 +126,9 @@ int4 RuleCollectTerms::applyOp(PcodeOp *op,Funcdata &data)
|
|||
vn2 = getMultCoeff(vn2,coef2);
|
||||
if (vn1 == vn2) { // Terms that can be combined
|
||||
if (order[i-1]->getMultiplier() != (PcodeOp *)0)
|
||||
return Funcdata::distributeIntMult(data,order[i-1]->getMultiplier()) ? 1 : 0;
|
||||
return data.distributeIntMultAdd(order[i-1]->getMultiplier()) ? 1 : 0;
|
||||
if (order[i]->getMultiplier() != (PcodeOp *)0)
|
||||
return Funcdata::distributeIntMult(data,order[i]->getMultiplier()) ? 1 : 0;
|
||||
return data.distributeIntMultAdd(order[i]->getMultiplier()) ? 1 : 0;
|
||||
coef1 = (coef1 + coef2) & calc_mask(vn1->getSize()); // The new coefficient
|
||||
Varnode *newcoeff = data.newConstant(vn1->getSize(),coef1);
|
||||
Varnode *zerocoeff = data.newConstant(vn1->getSize(),0);
|
||||
|
@ -609,7 +609,7 @@ void RuleIntLessEqual::getOpList(vector<uint4> &oplist) const
|
|||
int4 RuleIntLessEqual::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
if (Funcdata::replaceLessequal(data,op))
|
||||
if (data.replaceLessequal(op))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -5917,10 +5917,13 @@ bool AddTreeState::apply(void)
|
|||
calcSubtype();
|
||||
if (!valid) return false;
|
||||
while(valid && distributeOp != (PcodeOp *)0) {
|
||||
if (!Funcdata::distributeIntMult(data, distributeOp)) {
|
||||
if (!data.distributeIntMultAdd(distributeOp)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
// Collapse any z = (x * #c) * #d expressions produced by the distribute
|
||||
data.collapseIntMultMult(distributeOp->getIn(0));
|
||||
data.collapseIntMultMult(distributeOp->getIn(1));
|
||||
clear();
|
||||
spanAddTree(baseOp,1);
|
||||
if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue