diff -r 820b22e13ff1 -r 39c28ec933dd imgtools/romtools/rombuild/r_collapse.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imgtools/romtools/rombuild/r_collapse.cpp Mon May 10 19:54:49 2010 +0100 @@ -0,0 +1,365 @@ +/* +* Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include +#include "h_utl.h" +#include +#include +#include "r_global.h" +#include "r_obey.h" +#include "r_rom.h" +#include "r_dir.h" + +// Routines for optimising the ROM by improving the code +// +// NB. Largely untouched since ER5, so not likely to work without +// some significant effort. Doesn't know about ARMv4T or ARMv5 instructions. + + +TInt E32Rom::CollapseImportThunks(TRomBuilderEntry* aFile) +// +// Collapse 3-word import thunks into a single branch +// + { + TRomImageHeader *pI=aFile->iRomImageHeader; + TUint32 *pE=(TUint32*)RomToActualAddress(pI->iCodeAddress); // address of code section + TUint32 codeSize=pI->iCodeSize; + TUint32 *pC=pE+(codeSize>>2)-3; + TUint32 low=0; + TUint32 high=0; + TUint32 romLow=0; + TUint32 romHigh=0; + TBool block=EFalse; + TInt blocknum=0; + TRACE(TCOLLAPSE1,Print(ELog,"CollapseImportThunks() File %s[%08x]\n",aFile->iFileName, + pI->iHardwareVariant)); + while(pC>=pE) + { + if (pC[0]==0xe59fc000 && pC[1]==0xe59cf000 && (pC[2]&0xf0000000)==0x50000000) + { +// assume this is an import thunk + if (!block) + { + high=(TUint32)(pC+3); + block=ETrue; + } + pC-=3; + } + else + { + if (block) + { + low=(TUint32)(pC+3); + block=EFalse; + TInt numImports=(high-low)/12; + TRACE(TCOLLAPSE2,Print(ELog,"?Import thunk block %08x-%08x %d %d\n",ActualToRomAddress((TAny*)low),ActualToRomAddress((TAny*)high),numImports,aFile->iImportCount)); + if (numImports==aFile->iImportCount) + { + if (blocknum==0) + { + romLow=(TUint32)ActualToRomAddress((TAny*)low); + romHigh=(TUint32)ActualToRomAddress((TAny*)high); + } + blocknum++; + } + } + pC--; + } + } + if (blocknum==0) + { + Print(EWarning,"Import thunk block for %s[%08x] not found\n",aFile->iFileName, + pI->iHardwareVariant); + } + else if (blocknum==1) + { + low=(TUint32)RomToActualAddress(romLow); + high=(TUint32)RomToActualAddress(romHigh); + TRACE(TCOLLAPSE1,Print(ELog,"Import thunk block %08x-%08x\n",romLow,romHigh)); + TUint32 *pX; + for (pX=(TUint32*)low; pX<(TUint32*)high; pX+=3) + { + TUint32 *pA=(TUint32*)RomToActualAddress(pX[2]); + TUint32 jumpAddr=*pA; + jumpAddr=FindFinalJumpDestination(jumpAddr); + TInt offset=(TInt)jumpAddr-(TInt)ActualToRomAddress(pX)-8; + if (offset<33554432 && offset>-33554432) + { + pX[0]=0xea000000 | ((offset&0x03ffffff)>>2); + iImportsFixedUp++; + } + } + aFile->iImportBlockStartAddress=romLow; + aFile->iImportBlockEndAddress=romHigh; + } + else + Print(EWarning,"??Import thunk block ambiguous - not changed\n"); + return KErrNone; + } + +TInt E32Rom::CollapseBranches() +// +// Collapse chained branches +// + { + + Print(ELog, "\nCollapsing Chained Branches.\n"); + TInt i; + for (i=0; iiNumberOfPeFiles; i++) + { + TRomBuilderEntry* file=iPeFiles[i]; + if (file->iOrigHdr->iImportOffset && file->iImportBlockEndAddress!=0) + { + TInt r=CollapseBranches(file); + if (r!=KErrNone) + return r; + } + } + return KErrNone; + } + +inline void SetBit(TUint32* aBitmap, TInt aOffset) + { + aOffset>>=2; + aBitmap[aOffset>>5] |= (1<<(aOffset&0x1f)); + } + +inline TInt BitTest(TUint32* aBitmap, TInt aOffset) + { + aOffset>>=2; + return(aBitmap[aOffset>>5]&(1<<(aOffset&0x1f))); + } + +TUint32 E32Rom::FindFinalJumpDestination(TUint32 ja) + { +// follow a chain of branches to final destination + TUint32 initja=ja; + TUint8* aja=(TUint8*)RomToActualAddress(ja); + FOREVER + { + if ((*(TUint32*)aja &0xff000000)==0xea000000) + { +// branch to an unconditional branch + TInt off=(*(TUint32*)aja & 0x00ffffff)<<8; + off>>=6; + if (off==-8) + { +// branch to same address + break; + } + ja+=(off+8); + aja+=(off+8); + TRACE(TCOLLAPSE2,Print(ELog,"Chain branch %08x to %08x\n",initja,ja)); + } + else + break; + } + return ja; + } + + +TInt E32Rom::CollapseBranches(TRomBuilderEntry* aFile) + { +// Main code section is between pI->iCodeAddress and aImportThunkStart. This contains +// all the explicit code and interspersed literals. +// aImportThunkStart-aImportThunkEnd contains import thunks (already collapsed) +// aImportThunkEnd-iat contains template instantiations and virtual destructors +// iat-rdata contains import addresses - no need to touch these +// rdata-expdir contains constant data and vtables +// expdir-end contains exported addresses - no need to touch these + TUint32 impStart=aFile->iImportBlockStartAddress; + TUint32 impEnd=aFile->iImportBlockEndAddress; + TRomImageHeader *pI=aFile->iRomImageHeader; + TRACE(TCOLLAPSE1,Print(ELog,"CollapseBranches() File %s[%08x]\n",aFile->iFileName, + pI->iHardwareVariant)); + TUint32 codeStart=pI->iCodeAddress; + TUint32 codeSize=pI->iCodeSize; + TUint32 codeEnd=codeStart+codeSize; + TUint32 *pC=(TUint32*)RomToActualAddress(codeStart); // address of code section + TUint32 *pE=(TUint32*)RomToActualAddress(codeEnd); + TUint32 romIat=codeStart+aFile->iHdr->iTextSize; + TUint32 romRdata=romIat+aFile->iImportCount*4; + TUint32 exportDir=pI->iExportDir; + if (exportDir==0) + exportDir=codeEnd; + TRACE(TCOLLAPSE1,Print(ELog,"iat=%08x, rdata=%08x, expdir=%08x, end=%08x\n",romIat,romRdata,exportDir,codeEnd)); + TUint32 *pD=new TUint32[(codeSize+127)>>7]; + if (!pD) + return KErrNoMemory; + TInt rdataSize=TInt(exportDir)-TInt(romRdata); + TUint32 *pR=new TUint32[(rdataSize+127)>>7]; + if (!pR) + return KErrNoMemory; + TInt i; + for (i=0; i>7); i++) + pD[i]=0; + for (i=0; i>7); i++) + pR[i]=0; + TUint32 *pX; +// go through code looking for data references + for (pX=pC; pX=codeStart && eff=romRdata && dataiCollapseMode==ECollapseImportThunksAndVtables) + goto vtablesonly; + + // go through .text looking for Bcc and BLcc intstructions + for (pX=pC; pX>=6; + TUint32 pc=ActualToRomAddress(pX)+8; + TUint32 ja=pc+off; + TUint32 initja=ja; + if (ja=codeEnd) + { + TRACE(TCOLLAPSE2,Print(ELog,"??Branch at %08x to %08x??\n",pc-8,ja)); + goto notthismodule; + } + TRACE(TCOLLAPSE4,Print(ELog,"Branch at %08x opcode %08x ja=%08x\n",pc-8,*pX,ja)); + ja=FindFinalJumpDestination(ja); + if (ja!=initja) + { + off=(TInt(ja)-TInt(pc))>>2; + if (off>-33554432 && off<33554432) + { + TUint32 oldOpc=*pX; + *pX=(*pX & 0xff000000)|(off&0x00ffffff); // fix up branch + TRACE(TCOLLAPSE2,Print(ELog,"Opcode at %08x fixed up from %08x to %08x\n",pc-8,oldOpc,*pX)); + iBranchesFixedUp++; + } + } + notthismodule: ; + } + } +// go through template instantiations and virtual destructors +// looking for Bcc and BLcc intstructions to import thunks + pX=(TUint32*)RomToActualAddress(impEnd); + for (; pX>=6; + TUint32 pc=ActualToRomAddress(pX)+8; + TUint32 ja=pc+off; + TUint32 initja=ja; + TRACE(TCOLLAPSE4,Print(ELog,"Branch at %08x opcode %08x ja=%08x\n",pc-8,*pX,ja)); + if (ja=codeEnd) + { + TRACE(TCOLLAPSE2,Print(ELog,"??Branch at %08x to %08x??\n",pc-8,ja)); + goto notthismodule2; + } + ja=FindFinalJumpDestination(ja); + if (ja!=initja) + { + off=(TInt(ja)-TInt(pc))>>2; + if (off>-33554432 && off<33554432) + { + TUint32 oldOpc=*pX; + *pX=(*pX & 0xff000000)|(off&0x00ffffff); // fix up branch + TRACE(TCOLLAPSE2,Print(ELog,"Opcode at %08x fixed up from %08x to %08x\n",pc-8,oldOpc,*pX)); + iBranchesFixedUp++; + } + } + notthismodule2: ; + } + } +vtablesonly: +// go through rdata section looking for vtables with references to import thunks + TUint32 *expStart=(TUint32*)RomToActualAddress(exportDir); + TUint32* pW=(TUint32*)RomToActualAddress(romRdata); + pX=pW; + while(pX=codeEnd) + break; + } + if (pZ==pY) + { +// this is a vtable +// check each address to see if it is an import thunk and if so fix it up + TRACE(TCOLLAPSE3,Print(ELog,"!vtable at %08x to %08x\n",ActualToRomAddress(pX),ActualToRomAddress(pY))); + for (pZ=pX+2; pZ