diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index 1d0064ccf6..f8fb03b541 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -290,7 +290,6 @@ Varnode *Funcdata::findSpacebaseInput(AddrSpace *id) const void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const Address &rampoint,uintb origval,int4 origsize) { - PcodeOp *addop; int4 sz = rampoint.getAddrSize(); AddrSpace *spaceid = rampoint.getSpace(); Datatype *sb_type = glb->types->getTypeSpacebase(spaceid,Address()); @@ -300,21 +299,47 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const uintb extra = rampoint.getOffset() - entry->getAddr().getOffset(); // Offset from beginning of entry extra = AddrSpace::byteToAddress(extra,rampoint.getSpace()->getWordSize()); // Convert to address units + PcodeOp *addOp = (PcodeOp *)0; + PcodeOp *extraOp = (PcodeOp *)0; + PcodeOp *zextOp = (PcodeOp *)0; + PcodeOp *subOp = (PcodeOp *)0; + bool isCopy = false; + if (op->code() == CPUI_COPY) { // We replace COPY with final op of this calculation + isCopy = true; + if (sz < origsize) + zextOp = op; + else { + op->insertInput(1); // PTRSUB, ADD, SUBPIECE all take 2 parameters + if (origsize < sz) + subOp = op; + else if (extra != 0) + extraOp = op; + else + addOp = op; + } + } spacebase_vn = newConstant(sz,0); spacebase_vn->updateType(sb_type,true,true); spacebase_vn->setFlags(Varnode::spacebase); - addop = newOp(2,op->getAddr()); - opSetOpcode(addop,CPUI_PTRSUB); - outvn = newUniqueOut(sz,addop); + if (addOp == (PcodeOp *)0) { + addOp = newOp(2,op->getAddr()); + opSetOpcode(addOp,CPUI_PTRSUB); + newUniqueOut(sz,addOp); + opInsertBefore(addOp,op); + } + else { + opSetOpcode(addOp,CPUI_PTRSUB); + } + outvn = addOp->getOut(); // Make sure newconstant and extra preserve origval in address units uintb newconstoff = origval - extra; // everything is already in address units newconst = newConstant(sz,newconstoff); newconst->setPtrCheck(); // No longer need to check this constant as a pointer if (spaceid->isTruncated()) - addop->setPtrFlow(); - opSetInput(addop,spacebase_vn,0); - opSetInput(addop,newconst,1); - opInsertBefore(addop,op); + addOp->setPtrFlow(); + opSetInput(addOp,spacebase_vn,0); + opSetInput(addOp,newconst,1); + Symbol *sym = entry->getSymbol(); Datatype *entrytype = sym->getType(); Datatype *ptrentrytype = glb->types->getTypePointer(sz,entrytype,spaceid->getWordSize()); @@ -323,34 +348,47 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const typelock = false; outvn->updateType(ptrentrytype,typelock,true); if (extra != 0) { - PcodeOp *extraop = newOp(2,op->getAddr()); - opSetOpcode(extraop,CPUI_INT_ADD); - Varnode *outvn2 = newUniqueOut(sz,extraop); + if (extraOp == (PcodeOp *)0) { + extraOp = newOp(2,op->getAddr()); + opSetOpcode(extraOp,CPUI_INT_ADD); + newUniqueOut(sz,extraOp); + opInsertBefore(extraOp,op); + } + else + opSetOpcode(extraOp,CPUI_INT_ADD); Varnode *extconst = newConstant(sz,extra); extconst->setPtrCheck(); - opSetInput(extraop,outvn,0); - opSetInput(extraop,extconst,1); - outvn = outvn2; - opInsertBefore(extraop,op); + opSetInput(extraOp,outvn,0); + opSetInput(extraOp,extconst,1); + outvn = extraOp->getOut(); } if (sz < origsize) { // The new constant is smaller than the original varnode, so we extend it - PcodeOp *zextop = newOp(1,op->getAddr()); - Varnode *outvn2 = newUniqueOut(origsize,zextop); - opSetOpcode(zextop,CPUI_INT_ZEXT); // Create an extension to get back to original varnode size - opSetInput(zextop,outvn,0); - opInsertBefore(zextop,op); - outvn = outvn2; + if (zextOp == (PcodeOp *)0) { + zextOp = newOp(1,op->getAddr()); + opSetOpcode(zextOp,CPUI_INT_ZEXT); // Create an extension to get back to original varnode size + newUniqueOut(origsize,zextOp); + opInsertBefore(zextOp,op); + } + else + opSetOpcode(extraOp,CPUI_INT_ZEXT); + opSetInput(zextOp,outvn,0); + outvn = zextOp->getOut(); } else if (origsize < sz) { // The new constant is bigger than the original varnode, truncate it - PcodeOp *subOp = newOp(2,op->getAddr()); - Varnode *outvn3 = newUniqueOut(origsize,subOp); - opSetOpcode(subOp,CPUI_SUBPIECE); + if (subOp == (PcodeOp *)0) { + subOp = newOp(2,op->getAddr()); + opSetOpcode(subOp,CPUI_SUBPIECE); + newUniqueOut(origsize,subOp); + opInsertBefore(subOp,op); + } + else + opSetOpcode(subOp,CPUI_SUBPIECE); opSetInput(subOp,outvn,0); opSetInput(subOp,newConstant(4, 0), 1); // Take least significant piece - opInsertBefore(subOp,op); - outvn = outvn3; + outvn = subOp->getOut(); } - opSetInput(op,outvn,slot); + if (!isCopy) + opSetInput(op,outvn,slot); } void Funcdata::clearCallSpecs(void)