mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-4790 Collapse double precision COPY to address forced storage
This commit is contained in:
parent
be305db930
commit
614f20cfa3
7 changed files with 360 additions and 46 deletions
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -1220,6 +1220,13 @@ int4 SplitVarnode::applyRuleIn(SplitVarnode &in,Funcdata &data)
|
|||
return 1;
|
||||
}
|
||||
break;
|
||||
case CPUI_COPY:
|
||||
if (workop->getOut()->isAddrForce()) {
|
||||
CopyForceForm copyform;
|
||||
if (copyform.applyRule(in, workop, workishi, data))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1385,6 +1392,47 @@ void SplitVarnode::replaceIndirectOp(Funcdata &data,SplitVarnode &out,SplitVarno
|
|||
out.buildHiFromWhole(data);
|
||||
}
|
||||
|
||||
/// \brief Rewrite the double precision version of a COPY to an address forced Varnode
|
||||
///
|
||||
/// This assumes that we have checked that the transformation is possible. The logical input must already
|
||||
/// exist, and after this method is called, the logical output will also exist. The original COPY pieces
|
||||
/// are explicitly destroyed.
|
||||
/// \param data is the function owning the COPYs
|
||||
/// \param addr is the storage address being COPYed
|
||||
/// \param in is the input to the COPYs
|
||||
/// \param copylo is the original least significant COPY
|
||||
/// \param copyhi is the original most significant COPY
|
||||
void SplitVarnode::replaceCopyForce(Funcdata &data,const Address &addr,SplitVarnode &in,PcodeOp *copylo,PcodeOp *copyhi)
|
||||
|
||||
{
|
||||
Varnode *inVn = in.getWhole();
|
||||
bool returnForm = copyhi->stopsCopyPropagation();
|
||||
if (returnForm && inVn->getAddr() != addr) {
|
||||
// Placeholder for global propagation past a RETURN needs an additional COPY
|
||||
PcodeOp *otherPoint1 = copyhi->getIn(0)->getDef();
|
||||
PcodeOp *otherPoint2 = copylo->getIn(0)->getDef();
|
||||
// We know these are COPYs in the same basic block. Compute the later one.
|
||||
if (otherPoint1->getSeqNum().getOrder() < otherPoint2->getSeqNum().getOrder())
|
||||
otherPoint1 = otherPoint2;
|
||||
PcodeOp *otherCopy = data.newOp(1, otherPoint1->getAddr());
|
||||
data.opSetOpcode(otherCopy, CPUI_COPY);
|
||||
Varnode *vn = data.newVarnodeOut(in.getSize(), addr, otherCopy);
|
||||
data.opSetInput(otherCopy,inVn,0);
|
||||
data.opInsertBefore(otherCopy, otherPoint1);
|
||||
inVn = vn;
|
||||
}
|
||||
PcodeOp *wholeCopy = data.newOp(1, copyhi->getAddr());
|
||||
data.opSetOpcode(wholeCopy, CPUI_COPY);
|
||||
Varnode *outVn = data.newVarnodeOut(in.getSize(), addr, wholeCopy);
|
||||
outVn->setAddrForce();
|
||||
if (returnForm)
|
||||
wholeCopy->setStopCopyPropagation();
|
||||
data.opSetInput(wholeCopy,inVn,0);
|
||||
data.opInsertBefore(wholeCopy, copyhi);
|
||||
data.opDestroy(copyhi); // Destroy the original COPYs. Outputs have no descendants.
|
||||
data.opDestroy(copylo);
|
||||
}
|
||||
|
||||
bool AddForm::checkForCarry(PcodeOp *op)
|
||||
|
||||
{ // If -op- matches a CARRY construction based on lo1 (i.e. CARRY(x,lo1) )
|
||||
|
@ -3151,6 +3199,73 @@ bool IndirectForm::applyRule(SplitVarnode &i,PcodeOp *ind,bool workishi,Funcdata
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Starting with the input pieces, identify the matching COPYs and verify that they act as a single
|
||||
/// address forced COPY with no descendants.
|
||||
/// \param h is the most significant input piece
|
||||
/// \param l is the least significant input piece
|
||||
/// \param w is the preexisting logical whole
|
||||
/// \param cpy is the COPY of the most significant piece
|
||||
bool CopyForceForm::verify(Varnode *h,Varnode *l,Varnode *w,PcodeOp *cpy)
|
||||
|
||||
{
|
||||
if (w == (Varnode *)0)
|
||||
return false;
|
||||
copyhi = cpy;
|
||||
if (copyhi->getIn(0) != h) return false;
|
||||
reshi = copyhi->getOut();
|
||||
if (!reshi->isAddrForce() || !reshi->hasNoDescend())
|
||||
return false;
|
||||
list<PcodeOp *>::const_iterator iter,enditer;
|
||||
iter = l->beginDescend();
|
||||
enditer = l->endDescend();
|
||||
while(iter != enditer) {
|
||||
copylo = *iter;
|
||||
++iter;
|
||||
if (copylo->code() != CPUI_COPY || copylo->getParent() != copyhi->getParent())
|
||||
continue;
|
||||
reslo = copylo->getOut();
|
||||
if (!reslo->isAddrForce() || !reslo->hasNoDescend())
|
||||
continue;
|
||||
if (!SplitVarnode::isAddrTiedContiguous(reslo, reshi, addrOut)) // Output MUST be contiguous addresses
|
||||
continue;
|
||||
if (copyhi->stopsCopyPropagation()) { // Special form has additional requirements
|
||||
if (h->loneDescend() == (PcodeOp *)0)
|
||||
continue;
|
||||
if (l->loneDescend() == (PcodeOp *)0)
|
||||
continue;
|
||||
if (w->getAddr() != addrOut) { // Input whole MUST also be the same address
|
||||
// Unless there are addition COPYs from the same basic block
|
||||
if (!h->isWritten() || !l->isWritten())
|
||||
continue;
|
||||
PcodeOp *otherLo = l->getDef();
|
||||
PcodeOp *otherHi = h->getDef();
|
||||
if (otherLo->code() != CPUI_COPY || otherHi->code() != CPUI_COPY)
|
||||
continue;
|
||||
if (otherLo->getParent() != otherHi->getParent())
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \param i is the putative input to the COPYs
|
||||
/// \param cpy is a putative COPY
|
||||
/// \param workishi is \b true if the COPY is of the most significant piece
|
||||
/// \param data is the function
|
||||
bool CopyForceForm::applyRule(SplitVarnode &i,PcodeOp *cpy,bool workishi,Funcdata &data)
|
||||
|
||||
{
|
||||
if (!workishi) return false;
|
||||
if (!i.hasBothPieces()) return false;
|
||||
in = i;
|
||||
if (!verify(in.getHi(),in.getLo(),in.getWhole(),cpy))
|
||||
return false;
|
||||
SplitVarnode::replaceCopyForce(data, addrOut, in, copylo, copyhi);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuleDoubleIn::reset(Funcdata &data)
|
||||
|
||||
{
|
||||
|
@ -3168,10 +3283,10 @@ void RuleDoubleIn::getOpList(vector<uint4> &oplist) const
|
|||
/// If the given Varnode looks like the most significant piece, there is another SUBPIECE that looks
|
||||
/// like the least significant piece, and the whole is from an operation that produces a logical whole,
|
||||
/// then mark the Varnode (and its companion) as double precision pieces and return 1.
|
||||
/// \param data is the function owning the Varnode
|
||||
/// \param vn is the given Varnode
|
||||
/// \param subpieceOp is the SUBPIECE PcodeOp producing the Varnode
|
||||
int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp)
|
||||
/// \return 1 if the pieces are marked, 0 otherwise
|
||||
int4 RuleDoubleIn::attemptMarking(Varnode *vn,PcodeOp *subpieceOp)
|
||||
|
||||
{
|
||||
Varnode *whole = subpieceOp->getIn(0);
|
||||
|
@ -3190,36 +3305,10 @@ int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp
|
|||
}
|
||||
else {
|
||||
// Categorize opcodes as "producing a logical whole"
|
||||
switch(whole->getDef()->code()) {
|
||||
case CPUI_INT_ADD:
|
||||
// Its hard to tell if the bit operators are really being used to act on the "logical whole"
|
||||
// case CPUI_INT_AND:
|
||||
// case CPUI_INT_OR:
|
||||
// case CPUI_INT_XOR:
|
||||
// case CPUI_INT_NEGATE:
|
||||
case CPUI_INT_MULT:
|
||||
case CPUI_INT_DIV:
|
||||
case CPUI_INT_SDIV:
|
||||
case CPUI_INT_REM:
|
||||
case CPUI_INT_SREM:
|
||||
case CPUI_INT_2COMP:
|
||||
case CPUI_FLOAT_ADD:
|
||||
case CPUI_FLOAT_DIV:
|
||||
case CPUI_FLOAT_MULT:
|
||||
case CPUI_FLOAT_SUB:
|
||||
case CPUI_FLOAT_NEG:
|
||||
case CPUI_FLOAT_ABS:
|
||||
case CPUI_FLOAT_SQRT:
|
||||
case CPUI_FLOAT_INT2FLOAT:
|
||||
case CPUI_FLOAT_FLOAT2FLOAT:
|
||||
case CPUI_FLOAT_TRUNC:
|
||||
case CPUI_FLOAT_CEIL:
|
||||
case CPUI_FLOAT_FLOOR:
|
||||
case CPUI_FLOAT_ROUND:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
// Its hard to tell if a logical op is really being used to act on the "logical whole"
|
||||
TypeOp *typeop = whole->getDef()->getOpcode();
|
||||
if (!typeop->isArithmeticOp() && !typeop->isFloatingPointOp())
|
||||
return 0;
|
||||
}
|
||||
Varnode *vnLo = (Varnode *)0;
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
|
@ -3240,11 +3329,11 @@ int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp
|
|||
|
||||
int4 RuleDoubleIn::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{ // Try to push double precision object "down" one level from input
|
||||
{
|
||||
Varnode *outvn = op->getOut();
|
||||
if (!outvn->isPrecisLo()) {
|
||||
if (outvn->isPrecisHi()) return 0;
|
||||
return attemptMarking(data, outvn, op);
|
||||
return attemptMarking(outvn, op);
|
||||
}
|
||||
if (data.hasUnreachableBlocks()) return 0;
|
||||
|
||||
|
@ -3260,6 +3349,82 @@ int4 RuleDoubleIn::applyOp(PcodeOp *op,Funcdata &data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void RuleDoubleOut::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
{
|
||||
oplist.push_back(CPUI_PIECE);
|
||||
}
|
||||
|
||||
/// \brief Determine if the given inputs to a PIECE should marked as double precision pieces
|
||||
///
|
||||
/// If the concatenation of the pieces is used as a logical whole by other ops, the two pieces
|
||||
/// are marked and 1 is returned.
|
||||
/// \param vnhi is the most significant input to the PIECE
|
||||
/// \param vnlo is the least significant input
|
||||
/// \param pieceOp is the op reading the pieces
|
||||
/// \return 1 if the pieces are marked, 0 otherwise
|
||||
int4 RuleDoubleOut::attemptMarking(Varnode *vnhi,Varnode *vnlo,PcodeOp *pieceOp)
|
||||
|
||||
{
|
||||
Varnode *whole = pieceOp->getOut();
|
||||
if (whole->isTypeLock()) {
|
||||
if (!whole->getType()->isPrimitiveWhole())
|
||||
return 0; // Don't mark for double precision if not a primitive type
|
||||
}
|
||||
if (vnhi->getSize() != vnlo->getSize())
|
||||
return 0;
|
||||
|
||||
SymbolEntry *entryhi = vnhi->getSymbolEntry();
|
||||
SymbolEntry *entrylo = vnlo->getSymbolEntry();
|
||||
if (entryhi != (SymbolEntry *)0 || entrylo != (SymbolEntry *)0) {
|
||||
if (entryhi == (SymbolEntry *)0 || entrylo == (SymbolEntry *)0)
|
||||
return 0; // One has a symbol, one doesn't
|
||||
if (entryhi->getSymbol() != entrylo->getSymbol())
|
||||
return 0; // Not from the same symbol
|
||||
}
|
||||
|
||||
bool isWhole = false;
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
for(iter=whole->beginDescend();iter!=whole->endDescend();++iter) {
|
||||
TypeOp *typeop = (*iter)->getOpcode();
|
||||
// Categorize op as "reading a logical whole"
|
||||
if (typeop->isArithmeticOp() || typeop->isFloatingPointOp()) {
|
||||
isWhole = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isWhole)
|
||||
return 0;
|
||||
vnhi->setPrecisHi();
|
||||
vnlo->setPrecisLo();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int4 RuleDoubleOut::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *vnhi= op->getIn(0);
|
||||
Varnode *vnlo = op->getIn(1);
|
||||
|
||||
// Currently this only implements collapsing input varnodes read by CPUI_PIECE
|
||||
// So we put the test for this particular case early
|
||||
if (!vnhi->isInput() || !vnlo->isInput())
|
||||
return 0;
|
||||
if (!vnhi->isPersist() || !vnlo->isPersist())
|
||||
return 0;
|
||||
|
||||
if (!vnhi->isPrecisHi() || !vnlo->isPrecisLo()) {
|
||||
return attemptMarking(vnhi,vnlo,op);
|
||||
}
|
||||
if (data.hasUnreachableBlocks()) return 0;
|
||||
|
||||
Address addr;
|
||||
if (!SplitVarnode::isAddrTiedContiguous(vnlo, vnhi, addr))
|
||||
return 0;
|
||||
data.combineInputVarnodes(vnhi,vnlo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// \brief Scan for conflicts between two LOADs or STOREs that would prevent them from being combined
|
||||
///
|
||||
/// The PcodeOps must be in the same basic block. Each PcodeOp that falls in between is examined
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue