mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-10-13 05:33:02 +00:00
Merge remote-tracking branch 'origin/caheckman_x86parityflag'
This commit is contained in:
commit
2f1292b174
|
@ -4745,6 +4745,7 @@ void universal_action(Architecture *conf)
|
|||
actprop->addRule( new RuleFloatRange("analysis") );
|
||||
actprop->addRule( new RulePiece2Zext("analysis") );
|
||||
actprop->addRule( new RulePiece2Sext("analysis") );
|
||||
actprop->addRule( new RulePopcountBoolXor("analysis") );
|
||||
actprop->addRule( new RuleSubvarAnd("subvar") );
|
||||
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
||||
actprop->addRule( new RuleSplitFlow("subvar") );
|
||||
|
|
|
@ -8470,3 +8470,161 @@ int4 RuleThreeWayCompare::applyOp(PcodeOp *op,Funcdata &data)
|
|||
}
|
||||
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);
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -1233,7 +1233,8 @@ macro subCarryFlags ( op1, op2 ) {
|
|||
macro resultflags(result) {
|
||||
SF = result s< 0;
|
||||
ZF = result == 0;
|
||||
# PF, AF not implemented
|
||||
PF = popcount(result) & 1;
|
||||
# AF not implemented
|
||||
}
|
||||
|
||||
macro shiftresultflags(result,count) {
|
||||
|
@ -1245,7 +1246,8 @@ macro shiftresultflags(result,count) {
|
|||
|
||||
local newZF = (result == 0);
|
||||
ZF = (!notzero & ZF) | (notzero & newZF);
|
||||
# PF, AF not implemented
|
||||
PF = popcount(result) & 1;
|
||||
# AF not implemented
|
||||
}
|
||||
|
||||
macro subflags(op1,op2) {
|
||||
|
|
Loading…
Reference in a new issue