mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch 'origin/caheckman_x86parityflag'
This commit is contained in:
commit
2f1292b174
4 changed files with 175 additions and 2 deletions
|
@ -4745,6 +4745,7 @@ void universal_action(Architecture *conf)
|
||||||
actprop->addRule( new RuleFloatRange("analysis") );
|
actprop->addRule( new RuleFloatRange("analysis") );
|
||||||
actprop->addRule( new RulePiece2Zext("analysis") );
|
actprop->addRule( new RulePiece2Zext("analysis") );
|
||||||
actprop->addRule( new RulePiece2Sext("analysis") );
|
actprop->addRule( new RulePiece2Sext("analysis") );
|
||||||
|
actprop->addRule( new RulePopcountBoolXor("analysis") );
|
||||||
actprop->addRule( new RuleSubvarAnd("subvar") );
|
actprop->addRule( new RuleSubvarAnd("subvar") );
|
||||||
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
||||||
actprop->addRule( new RuleSplitFlow("subvar") );
|
actprop->addRule( new RuleSplitFlow("subvar") );
|
||||||
|
|
|
@ -8470,3 +8470,161 @@ int4 RuleThreeWayCompare::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \class RulePopcountBoolXor
|
||||||
|
/// \brief Simplify boolean expressions that are combined through POPCOUNT
|
||||||
|
///
|
||||||
|
/// Expressions involving boolean values (b1 and b2) are converted, such as:
|
||||||
|
/// - `popcount((b1 << 6) | (b2 << 2)) & 1 => b1 ^ b2`
|
||||||
|
void RulePopcountBoolXor::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
{
|
||||||
|
oplist.push_back(CPUI_POPCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 RulePopcountBoolXor::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *outVn = op->getOut();
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
|
||||||
|
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
|
||||||
|
PcodeOp *baseOp = *iter;
|
||||||
|
if (baseOp->code() != CPUI_INT_AND) continue;
|
||||||
|
Varnode *tmpVn = baseOp->getIn(1);
|
||||||
|
if (!tmpVn->isConstant()) continue;
|
||||||
|
if (tmpVn->getOffset() != 1) continue; // Masking 1 bit means we are checking parity of POPCOUNT input
|
||||||
|
if (tmpVn->getSize() != 1) continue; // Must be boolean sized output
|
||||||
|
Varnode *inVn = op->getIn(0);
|
||||||
|
if (!inVn->isWritten()) return 0;
|
||||||
|
int4 count = popcount(inVn->getNZMask());
|
||||||
|
if (count == 1) {
|
||||||
|
int4 leastPos = leastsigbit_set(inVn->getNZMask());
|
||||||
|
int4 constRes;
|
||||||
|
Varnode *b1 = getBooleanResult(inVn, leastPos, constRes);
|
||||||
|
if (b1 == (Varnode *)0) continue;
|
||||||
|
data.opSetOpcode(baseOp, CPUI_COPY); // Recognized popcount( b1 << #pos ) & 1
|
||||||
|
data.opRemoveInput(baseOp, 1); // Simplify to COPY(b1)
|
||||||
|
data.opSetInput(baseOp, b1, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (count == 2) {
|
||||||
|
int4 pos0 = leastsigbit_set(inVn->getNZMask());
|
||||||
|
int4 pos1 = mostsigbit_set(inVn->getNZMask());
|
||||||
|
int4 constRes0,constRes1;
|
||||||
|
Varnode *b1 = getBooleanResult(inVn, pos0, constRes0);
|
||||||
|
if (b1 == (Varnode *)0 && constRes0 != 1) continue;
|
||||||
|
Varnode *b2 = getBooleanResult(inVn, pos1, constRes1);
|
||||||
|
if (b2 == (Varnode *)0 && constRes1 != 1) continue;
|
||||||
|
if (b1 == (Varnode *)0 && b2 == (Varnode *)0) continue;
|
||||||
|
if (b1 == (Varnode *)0)
|
||||||
|
b1 = data.newConstant(1, 1);
|
||||||
|
if (b2 == (Varnode *)0)
|
||||||
|
b2 = data.newConstant(1, 1);
|
||||||
|
data.opSetOpcode(baseOp, CPUI_INT_XOR); // Recognized popcount ( b1 << #pos1 | b2 << #pos2 ) & 1
|
||||||
|
data.opSetInput(baseOp, b1, 0);
|
||||||
|
data.opSetInput(baseOp, b2, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Extract boolean Varnode producing bit at given Varnode and position
|
||||||
|
///
|
||||||
|
/// The boolean value may be shifted, extended and combined with other booleans through a
|
||||||
|
/// series of operations. We return the Varnode that is the
|
||||||
|
/// actual result of the boolean operation. If the given Varnode is constant, return
|
||||||
|
/// null but pass back whether the given bit position is 0 or 1. If no boolean value can be
|
||||||
|
/// found, return null and pass back -1.
|
||||||
|
/// \param vn is the given Varnode containing the extended/shifted boolean
|
||||||
|
/// \param bitPos is the bit position of the desired boolean value
|
||||||
|
/// \param constRes is used to pass back a constant boolean result
|
||||||
|
/// \return the boolean Varnode producing the desired value or null
|
||||||
|
Varnode *RulePopcountBoolXor::getBooleanResult(Varnode *vn,int4 bitPos,int4 &constRes)
|
||||||
|
|
||||||
|
{
|
||||||
|
constRes = -1;
|
||||||
|
uintb mask = 1;
|
||||||
|
mask <<= bitPos;
|
||||||
|
Varnode *vn0;
|
||||||
|
Varnode *vn1;
|
||||||
|
int4 sa;
|
||||||
|
for(;;) {
|
||||||
|
if (vn->isConstant()) {
|
||||||
|
constRes = (vn->getOffset() >> bitPos) & 1;
|
||||||
|
return (Varnode *)0;
|
||||||
|
}
|
||||||
|
if (!vn->isWritten()) return (Varnode *)0;
|
||||||
|
if (bitPos == 0 && vn->getSize() == 1 && vn->getNZMask() == mask)
|
||||||
|
return vn;
|
||||||
|
PcodeOp *op = vn->getDef();
|
||||||
|
switch(op->code()) {
|
||||||
|
case CPUI_INT_AND:
|
||||||
|
if (!op->getIn(1)->isConstant()) return (Varnode *)0;
|
||||||
|
vn = op->getIn(0);
|
||||||
|
break;
|
||||||
|
case CPUI_INT_XOR:
|
||||||
|
case CPUI_INT_OR:
|
||||||
|
vn0 = op->getIn(0);
|
||||||
|
vn1 = op->getIn(1);
|
||||||
|
if ((vn0->getNZMask() & mask) != 0) {
|
||||||
|
if ((vn1->getNZMask() & mask) != 0)
|
||||||
|
return (Varnode *)0; // Don't have a unique path
|
||||||
|
vn = vn0;
|
||||||
|
}
|
||||||
|
else if ((vn1->getNZMask() & mask) != 0) {
|
||||||
|
vn = vn1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return (Varnode *)0;
|
||||||
|
break;
|
||||||
|
case CPUI_INT_ZEXT:
|
||||||
|
case CPUI_INT_SEXT:
|
||||||
|
vn = op->getIn(0);
|
||||||
|
if (bitPos >= vn->getSize() * 8) return (Varnode *)0;
|
||||||
|
break;
|
||||||
|
case CPUI_SUBPIECE:
|
||||||
|
sa = (int4)op->getIn(1)->getOffset() * 8;
|
||||||
|
bitPos += sa;
|
||||||
|
mask <<= sa;
|
||||||
|
vn = op->getIn(0);
|
||||||
|
break;
|
||||||
|
case CPUI_PIECE:
|
||||||
|
vn0 = op->getIn(0);
|
||||||
|
vn1 = op->getIn(1);
|
||||||
|
sa = (int4)vn1->getSize() * 8;
|
||||||
|
if (bitPos >= sa) {
|
||||||
|
vn = vn0;
|
||||||
|
bitPos -= sa;
|
||||||
|
mask >>= sa;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vn = vn1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CPUI_INT_LEFT:
|
||||||
|
vn1 = op->getIn(1);
|
||||||
|
if (!vn1->isConstant()) return (Varnode *)0;
|
||||||
|
sa = (int4) vn1->getOffset();
|
||||||
|
if (sa > bitPos) return (Varnode *)0;
|
||||||
|
bitPos -= sa;
|
||||||
|
mask >>= sa;
|
||||||
|
vn = op->getIn(0);
|
||||||
|
break;
|
||||||
|
case CPUI_INT_RIGHT:
|
||||||
|
case CPUI_INT_SRIGHT:
|
||||||
|
vn1 = op->getIn(1);
|
||||||
|
if (!vn1->isConstant()) return (Varnode *)0;
|
||||||
|
sa = (int4) vn1->getOffset();
|
||||||
|
vn = op->getIn(0);
|
||||||
|
bitPos += sa;
|
||||||
|
if (bitPos >= vn->getSize() * 8) return (Varnode *)0;
|
||||||
|
mask <<= sa;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return (Varnode *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Varnode *)0; // Never reach here
|
||||||
|
}
|
||||||
|
|
|
@ -1420,4 +1420,16 @@ public:
|
||||||
static int4 testCompareEquivalence(PcodeOp *lessop,PcodeOp *lessequalop);
|
static int4 testCompareEquivalence(PcodeOp *lessop,PcodeOp *lessequalop);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RulePopcountBoolXor : public Rule {
|
||||||
|
public:
|
||||||
|
RulePopcountBoolXor(const string &g) : Rule( g, 0, "popcountboolxor") {} ///< Constructor
|
||||||
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||||
|
return new RulePopcountBoolXor(getGroup());
|
||||||
|
}
|
||||||
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
static Varnode *getBooleanResult(Varnode *vn,int4 bitPos,int4 &constRes);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1233,7 +1233,8 @@ macro subCarryFlags ( op1, op2 ) {
|
||||||
macro resultflags(result) {
|
macro resultflags(result) {
|
||||||
SF = result s< 0;
|
SF = result s< 0;
|
||||||
ZF = result == 0;
|
ZF = result == 0;
|
||||||
# PF, AF not implemented
|
PF = popcount(result) & 1;
|
||||||
|
# AF not implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
macro shiftresultflags(result,count) {
|
macro shiftresultflags(result,count) {
|
||||||
|
@ -1245,7 +1246,8 @@ macro shiftresultflags(result,count) {
|
||||||
|
|
||||||
local newZF = (result == 0);
|
local newZF = (result == 0);
|
||||||
ZF = (!notzero & ZF) | (notzero & newZF);
|
ZF = (!notzero & ZF) | (notzero & newZF);
|
||||||
# PF, AF not implemented
|
PF = popcount(result) & 1;
|
||||||
|
# AF not implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
macro subflags(op1,op2) {
|
macro subflags(op1,op2) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue