diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 16b0d4fb30..31dc1d4265 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -32,6 +32,7 @@ src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END| src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END| src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END| src/decompile/datatests/offsetarray.xml||GHIDRA||||END| +src/decompile/datatests/packstructaccess.xml||GHIDRA||||END| src/decompile/datatests/pointercmp.xml||GHIDRA||||END| src/decompile/datatests/pointerrel.xml||GHIDRA||||END| src/decompile/datatests/pointersub.xml||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index bb5f05e34a..ec75271cdc 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -4736,7 +4736,7 @@ int4 RuleSubCancel::applyOp(PcodeOp *op,Funcdata &data) } /// \class RuleShiftSub -/// \brief Simplify SUBPIECE applied to INT_LEFT: `sub( V << 8*c, c) => sub(V,0)` +/// \brief Simplify SUBPIECE applied to INT_LEFT: `sub( V << 8*k, c) => sub(V,c-k)` void RuleShiftSub::getOpList(vector &oplist) const { @@ -4749,13 +4749,20 @@ int4 RuleShiftSub::applyOp(PcodeOp *op,Funcdata &data) if (!op->getIn(0)->isWritten()) return 0; PcodeOp *shiftop = op->getIn(0)->getDef(); if (shiftop->code() != CPUI_INT_LEFT) return 0; - if (!shiftop->getIn(1)->isConstant()) return 0; - if (8*op->getIn(1)->getOffset() != shiftop->getIn(1)->getOffset()) - return 0; + Varnode *sa = shiftop->getIn(1); + if (!sa->isConstant()) return 0; + int4 n = sa->getOffset(); + if ((n & 7) != 0) return 0; // Must shift by a multiple of 8 bits + int4 c = op->getIn(1)->getOffset(); Varnode *vn = shiftop->getIn(0); if (vn->isFree()) return 0; + int4 insize = vn->getSize(); + int4 outsize = op->getOut()->getSize(); + c -= n/8; + if (c < 0 || c + outsize > insize) // Check if this is a natural truncation + return 0; data.opSetInput(op,vn,0); - data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),0),1); + data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),c),1); return 1; } @@ -6879,7 +6886,8 @@ int4 RuleExtensionPush::applyOp(PcodeOp *op,Funcdata &data) /// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT /// /// The form looks like: -/// - `sub( V>>c ,d ) => sub( V, d+k/8 ) >> (c-k) where k = (c/8)*8` +/// - `sub( V>>n ,c ) => sub( V, c+k/8 ) >> (n-k) where k = (n/8)*8` or +/// - `sub( V>>n, c ) => ext( sub( V, c+k/8 ) ) if n is big` void RuleSubNormal::getOpList(vector &oplist) const { @@ -6901,13 +6909,35 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data) int4 n = shiftop->getIn(1)->getOffset(); int4 c = op->getIn(1)->getOffset(); int4 k = (n/8); + int4 insize = a->getSize(); int4 outsize = op->getOut()->getSize(); - // If totalcut + remain > original input, shrink cut - if (k+c+outsize > shiftout->getSize()) - k = shiftout->getSize()-c-outsize; // Total shift + outsize must be greater equal to size of input - if ((n+8*c+8*outsize < 8*a->getSize())&&(n != k*8)) return 0; + if ((n+8*c+8*outsize < 8*insize)&&(n != k*8)) return 0; + + // If totalcut + remain > original input + if (k+c+outsize > insize) { + int4 truncSize = insize - c - k; + if (n == k*8 && truncSize > 0 && popcount(truncSize)==1) { + // We need an additional extension + c += k; + PcodeOp *newop = data.newOp(2,op->getAddr()); + opc = (opc == CPUI_INT_SRIGHT) ? CPUI_INT_SEXT : CPUI_INT_ZEXT; + data.opSetOpcode(newop,CPUI_SUBPIECE); + data.newUniqueOut(truncSize,newop); + data.opSetInput(newop,a,0); + data.opSetInput(newop,data.newConstant(4,c),1); + data.opInsertBefore(newop,op); + + data.opSetInput(op,newop->getOut(),0); + data.opRemoveInput(op,1); + data.opSetOpcode(op,opc); + return 1; + } + else + k = insize-c-outsize; // Or we can shrunk the cut + } + // if n == k*8, then a shift is unnecessary c += k; n -= k*8; @@ -6919,7 +6949,7 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data) PcodeOp *newop = data.newOp(2,op->getAddr()); data.opSetOpcode(newop,CPUI_SUBPIECE); - data.newUniqueOut(op->getOut()->getSize(),newop); + data.newUniqueOut(outsize,newop); data.opSetInput(newop,a,0); data.opSetInput(newop,data.newConstant(4,c),1); data.opInsertBefore(newop,op); diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml new file mode 100644 index 0000000000..48505f2b09 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml @@ -0,0 +1,28 @@ + + + + + e8d0ffffff4889c248c1e2 +1048c1fa3001c248c1f83001d0c3 + + + + + +tVar1 = getstruct\(i\); +tVar1\.a +\(int4\)tVar1\.b +\(int4\)tVar1\.c +