|
1 /* |
|
2 * Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32std.h> |
|
20 #include <e32std_private.h> |
|
21 #include <e32uid.h> |
|
22 #include "h_utl.h" |
|
23 #include <string.h> |
|
24 #include <stdlib.h> |
|
25 #include "r_global.h" |
|
26 #include "r_obey.h" |
|
27 #include "r_rom.h" |
|
28 #include "r_dir.h" |
|
29 |
|
30 // Routines for optimising the ROM by improving the code |
|
31 // |
|
32 // NB. Largely untouched since ER5, so not likely to work without |
|
33 // some significant effort. Doesn't know about ARMv4T or ARMv5 instructions. |
|
34 |
|
35 |
|
36 TInt E32Rom::CollapseImportThunks(TRomBuilderEntry* aFile) |
|
37 // |
|
38 // Collapse 3-word import thunks into a single branch |
|
39 // |
|
40 { |
|
41 TRomImageHeader *pI=aFile->iRomImageHeader; |
|
42 TUint32 *pE=(TUint32*)RomToActualAddress(pI->iCodeAddress); // address of code section |
|
43 TUint32 codeSize=pI->iCodeSize; |
|
44 TUint32 *pC=pE+(codeSize>>2)-3; |
|
45 TUint32 low=0; |
|
46 TUint32 high=0; |
|
47 TUint32 romLow=0; |
|
48 TUint32 romHigh=0; |
|
49 TBool block=EFalse; |
|
50 TInt blocknum=0; |
|
51 TRACE(TCOLLAPSE1,Print(ELog,"CollapseImportThunks() File %s[%08x]\n",aFile->iFileName, |
|
52 pI->iHardwareVariant)); |
|
53 while(pC>=pE) |
|
54 { |
|
55 if (pC[0]==0xe59fc000 && pC[1]==0xe59cf000 && (pC[2]&0xf0000000)==0x50000000) |
|
56 { |
|
57 // assume this is an import thunk |
|
58 if (!block) |
|
59 { |
|
60 high=(TUint32)(pC+3); |
|
61 block=ETrue; |
|
62 } |
|
63 pC-=3; |
|
64 } |
|
65 else |
|
66 { |
|
67 if (block) |
|
68 { |
|
69 low=(TUint32)(pC+3); |
|
70 block=EFalse; |
|
71 TInt numImports=(high-low)/12; |
|
72 TRACE(TCOLLAPSE2,Print(ELog,"?Import thunk block %08x-%08x %d %d\n",ActualToRomAddress((TAny*)low),ActualToRomAddress((TAny*)high),numImports,aFile->iImportCount)); |
|
73 if (numImports==aFile->iImportCount) |
|
74 { |
|
75 if (blocknum==0) |
|
76 { |
|
77 romLow=(TUint32)ActualToRomAddress((TAny*)low); |
|
78 romHigh=(TUint32)ActualToRomAddress((TAny*)high); |
|
79 } |
|
80 blocknum++; |
|
81 } |
|
82 } |
|
83 pC--; |
|
84 } |
|
85 } |
|
86 if (blocknum==0) |
|
87 { |
|
88 Print(EWarning,"Import thunk block for %s[%08x] not found\n",aFile->iFileName, |
|
89 pI->iHardwareVariant); |
|
90 } |
|
91 else if (blocknum==1) |
|
92 { |
|
93 low=(TUint32)RomToActualAddress(romLow); |
|
94 high=(TUint32)RomToActualAddress(romHigh); |
|
95 TRACE(TCOLLAPSE1,Print(ELog,"Import thunk block %08x-%08x\n",romLow,romHigh)); |
|
96 TUint32 *pX; |
|
97 for (pX=(TUint32*)low; pX<(TUint32*)high; pX+=3) |
|
98 { |
|
99 TUint32 *pA=(TUint32*)RomToActualAddress(pX[2]); |
|
100 TUint32 jumpAddr=*pA; |
|
101 jumpAddr=FindFinalJumpDestination(jumpAddr); |
|
102 TInt offset=(TInt)jumpAddr-(TInt)ActualToRomAddress(pX)-8; |
|
103 if (offset<33554432 && offset>-33554432) |
|
104 { |
|
105 pX[0]=0xea000000 | ((offset&0x03ffffff)>>2); |
|
106 iImportsFixedUp++; |
|
107 } |
|
108 } |
|
109 aFile->iImportBlockStartAddress=romLow; |
|
110 aFile->iImportBlockEndAddress=romHigh; |
|
111 } |
|
112 else |
|
113 Print(EWarning,"??Import thunk block ambiguous - not changed\n"); |
|
114 return KErrNone; |
|
115 } |
|
116 |
|
117 TInt E32Rom::CollapseBranches() |
|
118 // |
|
119 // Collapse chained branches |
|
120 // |
|
121 { |
|
122 |
|
123 Print(ELog, "\nCollapsing Chained Branches.\n"); |
|
124 TInt i; |
|
125 for (i=0; i<iObey->iNumberOfPeFiles; i++) |
|
126 { |
|
127 TRomBuilderEntry* file=iPeFiles[i]; |
|
128 if (file->iOrigHdr->iImportOffset && file->iImportBlockEndAddress!=0) |
|
129 { |
|
130 TInt r=CollapseBranches(file); |
|
131 if (r!=KErrNone) |
|
132 return r; |
|
133 } |
|
134 } |
|
135 return KErrNone; |
|
136 } |
|
137 |
|
138 inline void SetBit(TUint32* aBitmap, TInt aOffset) |
|
139 { |
|
140 aOffset>>=2; |
|
141 aBitmap[aOffset>>5] |= (1<<(aOffset&0x1f)); |
|
142 } |
|
143 |
|
144 inline TInt BitTest(TUint32* aBitmap, TInt aOffset) |
|
145 { |
|
146 aOffset>>=2; |
|
147 return(aBitmap[aOffset>>5]&(1<<(aOffset&0x1f))); |
|
148 } |
|
149 |
|
150 TUint32 E32Rom::FindFinalJumpDestination(TUint32 ja) |
|
151 { |
|
152 // follow a chain of branches to final destination |
|
153 TUint32 initja=ja; |
|
154 TUint8* aja=(TUint8*)RomToActualAddress(ja); |
|
155 FOREVER |
|
156 { |
|
157 if ((*(TUint32*)aja &0xff000000)==0xea000000) |
|
158 { |
|
159 // branch to an unconditional branch |
|
160 TInt off=(*(TUint32*)aja & 0x00ffffff)<<8; |
|
161 off>>=6; |
|
162 if (off==-8) |
|
163 { |
|
164 // branch to same address |
|
165 break; |
|
166 } |
|
167 ja+=(off+8); |
|
168 aja+=(off+8); |
|
169 TRACE(TCOLLAPSE2,Print(ELog,"Chain branch %08x to %08x\n",initja,ja)); |
|
170 } |
|
171 else |
|
172 break; |
|
173 } |
|
174 return ja; |
|
175 } |
|
176 |
|
177 |
|
178 TInt E32Rom::CollapseBranches(TRomBuilderEntry* aFile) |
|
179 { |
|
180 // Main code section is between pI->iCodeAddress and aImportThunkStart. This contains |
|
181 // all the explicit code and interspersed literals. |
|
182 // aImportThunkStart-aImportThunkEnd contains import thunks (already collapsed) |
|
183 // aImportThunkEnd-iat contains template instantiations and virtual destructors |
|
184 // iat-rdata contains import addresses - no need to touch these |
|
185 // rdata-expdir contains constant data and vtables |
|
186 // expdir-end contains exported addresses - no need to touch these |
|
187 TUint32 impStart=aFile->iImportBlockStartAddress; |
|
188 TUint32 impEnd=aFile->iImportBlockEndAddress; |
|
189 TRomImageHeader *pI=aFile->iRomImageHeader; |
|
190 TRACE(TCOLLAPSE1,Print(ELog,"CollapseBranches() File %s[%08x]\n",aFile->iFileName, |
|
191 pI->iHardwareVariant)); |
|
192 TUint32 codeStart=pI->iCodeAddress; |
|
193 TUint32 codeSize=pI->iCodeSize; |
|
194 TUint32 codeEnd=codeStart+codeSize; |
|
195 TUint32 *pC=(TUint32*)RomToActualAddress(codeStart); // address of code section |
|
196 TUint32 *pE=(TUint32*)RomToActualAddress(codeEnd); |
|
197 TUint32 romIat=codeStart+aFile->iHdr->iTextSize; |
|
198 TUint32 romRdata=romIat+aFile->iImportCount*4; |
|
199 TUint32 exportDir=pI->iExportDir; |
|
200 if (exportDir==0) |
|
201 exportDir=codeEnd; |
|
202 TRACE(TCOLLAPSE1,Print(ELog,"iat=%08x, rdata=%08x, expdir=%08x, end=%08x\n",romIat,romRdata,exportDir,codeEnd)); |
|
203 TUint32 *pD=new TUint32[(codeSize+127)>>7]; |
|
204 if (!pD) |
|
205 return KErrNoMemory; |
|
206 TInt rdataSize=TInt(exportDir)-TInt(romRdata); |
|
207 TUint32 *pR=new TUint32[(rdataSize+127)>>7]; |
|
208 if (!pR) |
|
209 return KErrNoMemory; |
|
210 TInt i; |
|
211 for (i=0; i<TInt((codeSize+127)>>7); i++) |
|
212 pD[i]=0; |
|
213 for (i=0; i<TInt((rdataSize+127)>>7); i++) |
|
214 pR[i]=0; |
|
215 TUint32 *pX; |
|
216 // go through code looking for data references |
|
217 for (pX=pC; pX<pE; pX++) |
|
218 { |
|
219 if ((*pX&0x0f3f0000)==0x051f0000) |
|
220 { |
|
221 // opcode is LDRcc Rn, [PC, #d] |
|
222 TInt offset=*pX & 0xfff; |
|
223 if ((*pX&0x00800000)==0) |
|
224 offset=-offset; |
|
225 TUint32 eff=(ActualToRomAddress(pX)+8+offset)&~3; |
|
226 if (eff>=codeStart && eff<codeEnd) |
|
227 { |
|
228 SetBit(pD,eff-codeStart); |
|
229 if (eff<codeEnd-4) |
|
230 SetBit(pD,eff-codeStart+4); |
|
231 TUint32 data=*(TUint32*)((TUint8*)pX+(offset&~3)+8); // fetch data word |
|
232 if (data>=romRdata && data<exportDir) |
|
233 { |
|
234 // it's an address of something in .rdata, possibly a vtable |
|
235 SetBit(pR,data-romRdata); |
|
236 } |
|
237 } |
|
238 } |
|
239 } |
|
240 |
|
241 TUint32 *importStart=(TUint32*)RomToActualAddress(impStart); |
|
242 TUint32 *iatStart=(TUint32*)RomToActualAddress(romIat); |
|
243 if (iObey->iCollapseMode==ECollapseImportThunksAndVtables) |
|
244 goto vtablesonly; |
|
245 |
|
246 // go through .text looking for Bcc and BLcc intstructions |
|
247 for (pX=pC; pX<importStart; pX++) |
|
248 { |
|
249 if ((*pX&0xfe000000)==0xea000000 && BitTest(pD,TInt(pX)-TInt(pC))==0 ) |
|
250 { |
|
251 TInt off=(*pX & 0x00ffffff)<<8; |
|
252 off>>=6; |
|
253 TUint32 pc=ActualToRomAddress(pX)+8; |
|
254 TUint32 ja=pc+off; |
|
255 TUint32 initja=ja; |
|
256 if (ja<codeStart || ja>=codeEnd) |
|
257 { |
|
258 TRACE(TCOLLAPSE2,Print(ELog,"??Branch at %08x to %08x??\n",pc-8,ja)); |
|
259 goto notthismodule; |
|
260 } |
|
261 TRACE(TCOLLAPSE4,Print(ELog,"Branch at %08x opcode %08x ja=%08x\n",pc-8,*pX,ja)); |
|
262 ja=FindFinalJumpDestination(ja); |
|
263 if (ja!=initja) |
|
264 { |
|
265 off=(TInt(ja)-TInt(pc))>>2; |
|
266 if (off>-33554432 && off<33554432) |
|
267 { |
|
268 TUint32 oldOpc=*pX; |
|
269 *pX=(*pX & 0xff000000)|(off&0x00ffffff); // fix up branch |
|
270 TRACE(TCOLLAPSE2,Print(ELog,"Opcode at %08x fixed up from %08x to %08x\n",pc-8,oldOpc,*pX)); |
|
271 iBranchesFixedUp++; |
|
272 } |
|
273 } |
|
274 notthismodule: ; |
|
275 } |
|
276 } |
|
277 // go through template instantiations and virtual destructors |
|
278 // looking for Bcc and BLcc intstructions to import thunks |
|
279 pX=(TUint32*)RomToActualAddress(impEnd); |
|
280 for (; pX<iatStart; pX++) |
|
281 { |
|
282 if ((*pX&0xfe000000)==0xea000000 && BitTest(pD,TInt(pX)-TInt(pC))==0 ) |
|
283 { |
|
284 TInt off=(*pX & 0x00ffffff)<<8; |
|
285 off>>=6; |
|
286 TUint32 pc=ActualToRomAddress(pX)+8; |
|
287 TUint32 ja=pc+off; |
|
288 TUint32 initja=ja; |
|
289 TRACE(TCOLLAPSE4,Print(ELog,"Branch at %08x opcode %08x ja=%08x\n",pc-8,*pX,ja)); |
|
290 if (ja<codeStart || ja>=codeEnd) |
|
291 { |
|
292 TRACE(TCOLLAPSE2,Print(ELog,"??Branch at %08x to %08x??\n",pc-8,ja)); |
|
293 goto notthismodule2; |
|
294 } |
|
295 ja=FindFinalJumpDestination(ja); |
|
296 if (ja!=initja) |
|
297 { |
|
298 off=(TInt(ja)-TInt(pc))>>2; |
|
299 if (off>-33554432 && off<33554432) |
|
300 { |
|
301 TUint32 oldOpc=*pX; |
|
302 *pX=(*pX & 0xff000000)|(off&0x00ffffff); // fix up branch |
|
303 TRACE(TCOLLAPSE2,Print(ELog,"Opcode at %08x fixed up from %08x to %08x\n",pc-8,oldOpc,*pX)); |
|
304 iBranchesFixedUp++; |
|
305 } |
|
306 } |
|
307 notthismodule2: ; |
|
308 } |
|
309 } |
|
310 vtablesonly: |
|
311 // go through rdata section looking for vtables with references to import thunks |
|
312 TUint32 *expStart=(TUint32*)RomToActualAddress(exportDir); |
|
313 TUint32* pW=(TUint32*)RomToActualAddress(romRdata); |
|
314 pX=pW; |
|
315 while(pX<expStart-1) |
|
316 { |
|
317 // first look for reference to start of vtable |
|
318 // there are always two 0 words at the start of a vtable |
|
319 if (BitTest(pR,TInt(pX)-TInt(pW)) && pX[0]==0 && pX[1]==0) |
|
320 { |
|
321 TRACE(TCOLLAPSE3,Print(ELog,"?vtable at %08x\n",ActualToRomAddress(pX))); |
|
322 // look for next reference - there are no references to |
|
323 // intermediate entries of vtable |
|
324 TUint32* pY; |
|
325 for (pY=pX+1; pY<expStart && BitTest(pR,TInt(pY)-TInt(pW))==0; pY++); |
|
326 |
|
327 // pY should now point to the end of the vtable |
|
328 // check all entries except the first two are valid ROM addresses in this module |
|
329 TRACE(TCOLLAPSE3,Print(ELog,"?vtable at %08x to %08x\n",ActualToRomAddress(pX),ActualToRomAddress(pY))); |
|
330 TUint32 *pZ; |
|
331 for (pZ=pX+2; pZ<pY; pZ++) |
|
332 { |
|
333 if (*pZ<codeStart || *pZ>=codeEnd) |
|
334 break; |
|
335 } |
|
336 if (pZ==pY) |
|
337 { |
|
338 // this is a vtable |
|
339 // check each address to see if it is an import thunk and if so fix it up |
|
340 TRACE(TCOLLAPSE3,Print(ELog,"!vtable at %08x to %08x\n",ActualToRomAddress(pX),ActualToRomAddress(pY))); |
|
341 for (pZ=pX+2; pZ<pY; pZ++) |
|
342 { |
|
343 TUint32 ja=*pZ; |
|
344 TUint32 initja=ja; |
|
345 ja=FindFinalJumpDestination(ja); |
|
346 if (ja!=initja) |
|
347 { |
|
348 *pZ=ja; |
|
349 TRACE(TCOLLAPSE2,Print(ELog,"Vtable entry at %08x fixed up from %08x to %08x\n",ActualToRomAddress(pZ),initja,ja)); |
|
350 iVtableEntriesFixedUp++; |
|
351 } |
|
352 } |
|
353 pX=pY; |
|
354 } |
|
355 else |
|
356 pX++; |
|
357 } |
|
358 else |
|
359 pX++; |
|
360 } |
|
361 delete[] pR; |
|
362 delete[] pD; |
|
363 return KErrNone; |
|
364 } |
|
365 |