|
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <time.h> |
|
17 #include <malloc.h> |
|
18 #include <string.h> |
|
19 #include "e32image.h" |
|
20 #include <e32std.h> |
|
21 #include <e32std_private.h> |
|
22 #include "pe_defs.h" |
|
23 #include "pe_file.h" |
|
24 #include "h_ver.h" |
|
25 #include "h_utl.h" |
|
26 |
|
27 int gAlignConstSection=FALSE; |
|
28 TUint gConstSectionAddressMask=0; |
|
29 static TUint gRequiredConstPadding; |
|
30 |
|
31 extern char* gX86imp; |
|
32 extern int gX86num_imp_dlls; |
|
33 extern int gX86imp_size; |
|
34 extern int gX86num_imports; |
|
35 |
|
36 E32ImageFile* E32ImageFile::New() |
|
37 { |
|
38 return new E32ImageFile_PE; |
|
39 } |
|
40 |
|
41 E32ImageFile_PE::E32ImageFile_PE() |
|
42 { |
|
43 } |
|
44 |
|
45 E32ImageFile_PE::~E32ImageFile_PE() |
|
46 { |
|
47 } |
|
48 |
|
49 TUint E32ImageFile_PE::ImportAddressTableOffset() |
|
50 // |
|
51 // Return the offset of the iat |
|
52 // |
|
53 { |
|
54 return iHdr->iTextSize; |
|
55 } |
|
56 |
|
57 TUint E32ImageFile_PE::ConstOffset() |
|
58 // |
|
59 // return the offset of the const data |
|
60 // |
|
61 { |
|
62 return iConstOffset; |
|
63 } |
|
64 |
|
65 void E32ImageFile_PE::CreateExportDirectory(char *aPtr, PEFile &aPeFile) |
|
66 // |
|
67 // create a new format export directory |
|
68 // |
|
69 { |
|
70 |
|
71 if (iHdr->iExportDirCount==0) |
|
72 return; |
|
73 TUint *src=(TUint *)aPeFile.iSectionData[KExportSection]; |
|
74 TUint *dst=(TUint *)aPtr; |
|
75 PIMAGE_EXPORT_DIRECTORY dir=(PIMAGE_EXPORT_DIRECTORY)src; |
|
76 src+=(((TInt)dir->AddressOfFunctions)-((TInt)aPeFile.iSectionHeader[KExportSection]->VirtualAddress))/4; |
|
77 TUint i; |
|
78 for (i=0; i<dir->NumberOfFunctions; i++) |
|
79 { |
|
80 TUint va=*src++; |
|
81 dst[i]=va; |
|
82 } |
|
83 FixExportDirectory(dst, aPeFile); |
|
84 } |
|
85 |
|
86 void E32ImageFile_PE::FixExportDirectory(TUint *aExportDir, PEFile &aPeFile) |
|
87 // |
|
88 // Fix the export directory |
|
89 // |
|
90 { |
|
91 |
|
92 TUint lb = aPeFile.iLinkedBase; |
|
93 TUint *exportdir=aExportDir; |
|
94 TInt n; |
|
95 for (n=0; n<(TInt)iHdr->iExportDirCount; n++) |
|
96 { |
|
97 TUint va=*exportdir; |
|
98 if (!gLittleEndian) ByteSwap(va); |
|
99 |
|
100 // va is the address of an exported item, so assume it can't have been offset |
|
101 TInt i=aPeFile.FindSectionByVa(va+lb); |
|
102 if (i==KTextSection) |
|
103 va=va-aPeFile.iSectionHeader[i]->VirtualAddress; |
|
104 else if (i==KConstSection) |
|
105 va=va-aPeFile.iSectionHeader[i]->VirtualAddress+ConstOffset(); |
|
106 else if (i==KDataSection) |
|
107 va=va-aPeFile.iSectionHeader[i]->VirtualAddress+DataOffset(); |
|
108 else if (i==KBssSection) |
|
109 va=va-aPeFile.iSectionHeader[i]->VirtualAddress+BssOffset(); |
|
110 else |
|
111 { |
|
112 if (va == 0) |
|
113 Print(EWarning, "No export specified for ordinal %d\n", n+1, va); |
|
114 else |
|
115 Print(EError, "Export %d (address %08x) is not from .text, .rdata, or data sections\n", n+1, va); |
|
116 } |
|
117 if (!gLittleEndian) ByteSwap(va); |
|
118 *exportdir++=va; |
|
119 } |
|
120 } |
|
121 |
|
122 TInt E32ImageFile_PE::DoCodeHeader(PEFile &aPeFile) |
|
123 // |
|
124 // Calculate the code parts of the pefile |
|
125 // |
|
126 { |
|
127 |
|
128 // .text |
|
129 TInt size=ALIGN4(aPeFile.iSectionHeader[KTextSection]->Misc.VirtualSize); |
|
130 |
|
131 // .rdata |
|
132 iConstOffset=0; |
|
133 if (gAlignConstSection) |
|
134 { |
|
135 // Compute the amount of padding to put before the |
|
136 // const section to align it correctly |
|
137 TUint oldAddressBits = aPeFile.iSectionHeader[KConstSection]->VirtualAddress & gConstSectionAddressMask; |
|
138 TUint oldConstAddress = size; |
|
139 TUint newConstAddress = oldConstAddress; |
|
140 // slow but sure |
|
141 while ((newConstAddress & gConstSectionAddressMask) != oldAddressBits) |
|
142 { |
|
143 newConstAddress++; |
|
144 } |
|
145 gRequiredConstPadding = newConstAddress - oldConstAddress; |
|
146 size += gRequiredConstPadding; |
|
147 } |
|
148 if (aPeFile.iSectionHeader[KConstSection]) |
|
149 { |
|
150 iConstOffset = size; |
|
151 size += ALIGN4(aPeFile.iSectionHeader[KConstSection]->Misc.VirtualSize); |
|
152 } |
|
153 |
|
154 // .crt |
|
155 iCrtOffset=0; |
|
156 if (aPeFile.iSectionHeader[KCrtSection]) |
|
157 { |
|
158 iCrtOffset = size; |
|
159 size += ALIGN4(aPeFile.iSectionHeader[KCrtSection]->Misc.VirtualSize); |
|
160 } |
|
161 |
|
162 iHdr->iTextSize=size; // The "text" part of the E32 code section combines PE's .text + .rdata + .crt. |
|
163 // The remainder of the E32 code section is the IAT + export directory. |
|
164 |
|
165 // Import Address Table (IAT) |
|
166 TInt nimports=gX86imp?gX86num_imports:aPeFile.NumberOfImports(); |
|
167 if (nimports!=0) |
|
168 size+=nimports*4+4; // null terminated |
|
169 |
|
170 // Export Dir |
|
171 if (iHdr->iExportDirCount) |
|
172 { |
|
173 iHdr->iExportDirOffset = iHdr->iCodeOffset + size; |
|
174 size += ALIGN4(iHdr->iExportDirCount*4); |
|
175 } |
|
176 iHdr->iCodeSize=size; |
|
177 return size; |
|
178 } |
|
179 |
|
180 TInt E32ImageFile_PE::DoDataHeader(PEFile &aPeFile, TUint aDataBase) |
|
181 // |
|
182 // |
|
183 // |
|
184 { |
|
185 |
|
186 if (aDataBase == (TUint)0) |
|
187 aDataBase=iHdr->iCodeBase+iHdr->iCodeSize; |
|
188 TInt size=0; |
|
189 if (PEFile::HasInitialisedData(aPeFile.iSectionHeader[KDataSection])) |
|
190 { |
|
191 size=ALIGN4(aPeFile.iSectionHeader[KDataSection]->Misc.VirtualSize); |
|
192 iHdr->iDataBase=aDataBase; |
|
193 iHdr->iDataOffset = iHdr->iCodeOffset + iHdr->iCodeSize; |
|
194 TInt bsssize=aPeFile.iSectionHeader[KDataSection]->Misc.VirtualSize-aPeFile.iSectionHeader[KDataSection]->SizeOfRawData; |
|
195 // drop any uninitialised data |
|
196 if (bsssize>0) |
|
197 { |
|
198 iHdr->iBssSize+=bsssize; |
|
199 size=ALIGN4(aPeFile.iSectionHeader[KDataSection]->SizeOfRawData); |
|
200 } |
|
201 iHdr->iDataSize=size; |
|
202 } |
|
203 else if (aPeFile.iSectionHeader[KDataSection]) |
|
204 { // just .bss |
|
205 iHdr->iDataBase=aDataBase; |
|
206 TInt bsssize=aPeFile.iSectionHeader[KDataSection]->Misc.VirtualSize; |
|
207 iHdr->iBssSize+=bsssize; |
|
208 } |
|
209 if (aPeFile.iSectionHeader[KBssSection]) |
|
210 { |
|
211 iHdr->iBssSize+=ALIGN4(aPeFile.iSectionHeader[KBssSection]->Misc.VirtualSize); |
|
212 if (iHdr->iDataBase==0) // .bss but no .data |
|
213 iHdr->iDataBase=aDataBase; |
|
214 } |
|
215 return size; |
|
216 } |
|
217 |
|
218 TInt E32ImageFile_PE::CopyCode(char *p, PEFile &aPeFile) |
|
219 // |
|
220 // Copies the files code sections to p |
|
221 // returns the number of bytes copied or KErrGeneral |
|
222 // |
|
223 { |
|
224 |
|
225 // text |
|
226 TInt size=aPeFile.iSectionHeader[KTextSection]->Misc.VirtualSize; |
|
227 memcpy(p, aPeFile.iSectionData[KTextSection], size); |
|
228 TInt text_offset=ALIGN4(size); |
|
229 p+=text_offset; |
|
230 |
|
231 // rdata |
|
232 if (aPeFile.iSectionData[KConstSection]) |
|
233 { |
|
234 if (gAlignConstSection) |
|
235 { |
|
236 // add padding ahead of const section |
|
237 p += gRequiredConstPadding; |
|
238 } |
|
239 TInt size=ALIGN4(aPeFile.iSectionHeader[KConstSection]->Misc.VirtualSize); |
|
240 memcpy(p, aPeFile.iSectionData[KConstSection], size); |
|
241 p+=size; |
|
242 } |
|
243 if (aPeFile.iSectionData[KCrtSection]) |
|
244 { |
|
245 TInt size=ALIGN4(aPeFile.iSectionHeader[KCrtSection]->Misc.VirtualSize); |
|
246 memcpy(p, aPeFile.iSectionData[KCrtSection], size); |
|
247 p+=size; |
|
248 } |
|
249 |
|
250 // iat |
|
251 TInt nimports=gX86imp?gX86num_imports:aPeFile.NumberOfImports(); |
|
252 // TInt nimports=aPeFile.NumberOfImports(); |
|
253 if (nimports) |
|
254 { |
|
255 if (gX86imp) |
|
256 { |
|
257 TUint *rdata=(TUint*)aPeFile.iSectionData[KConstSection]; |
|
258 int i; |
|
259 int* s=(int*)gX86imp; |
|
260 s++; |
|
261 for (i=0; i<gX86num_imp_dlls; ++i) |
|
262 { |
|
263 ++s; |
|
264 int n=*s++; |
|
265 while (n--) |
|
266 { |
|
267 *(int*)p=rdata[(*s)>>2]&0x7fffffffu; // rdata offset to ordinal |
|
268 ++s; |
|
269 p+=4; |
|
270 } |
|
271 } |
|
272 *(int*)p=0; |
|
273 p+=4; |
|
274 } |
|
275 else |
|
276 { |
|
277 TInt r=CopyImportAddrTable(p, aPeFile); |
|
278 p+=ALIGN4(nimports*4+4); |
|
279 if (r!=KErrNone) |
|
280 return Print(EError, "%s is importing symbols by name.\n", iFileName); |
|
281 } |
|
282 } |
|
283 // export dir |
|
284 CreateExportDirectory(p, aPeFile); |
|
285 p+=iHdr->iExportDirCount*4; |
|
286 return iHdr->iCodeSize; |
|
287 } |
|
288 |
|
289 TInt E32ImageFile_PE::CopyData(char *p, PEFile &aPeFile) |
|
290 { |
|
291 |
|
292 if (iHdr->iDataSize) |
|
293 memcpy(p, aPeFile.iSectionData[KDataSection], iHdr->iDataSize); |
|
294 return iHdr->iDataSize; |
|
295 } |
|
296 |
|
297 TInt E32ImageFile_PE::Translate(const char* aFileName, TUint aDataBase, TBool aAllowDllData, TBool /*aSymLkupEnabled*/) |
|
298 // |
|
299 // Translate a PE format file to a E32Image file |
|
300 // |
|
301 { |
|
302 iSource = EPeFile; |
|
303 PEFile pefile; |
|
304 if (!pefile.Init((const char * const)aFileName)) |
|
305 return KErrGeneral; |
|
306 TInt r=pefile.ReadSectionHeaders(); |
|
307 if (r!=KErrNone) return r; |
|
308 r=pefile.ReadData(); |
|
309 if (r!=KErrNone) return r; |
|
310 pefile.Close(); |
|
311 r=pefile.Normalise(); |
|
312 if (r!=KErrNone) return r; |
|
313 iFileName = strdup(aFileName); |
|
314 |
|
315 Adjust(ALIGN4(sizeof(E32ImageHeaderV))); // fixed for now because holes not supported |
|
316 SetDefaultHeader(); |
|
317 if (gX86imp) |
|
318 iHdr->iDllRefTableCount=gX86num_imp_dlls; |
|
319 else |
|
320 iHdr->iDllRefTableCount=pefile.NumberOfImportDlls(); |
|
321 iHdr->iExportDirCount=pefile.NumberOfExports(); |
|
322 iHdr->iCodeBase=pefile.iLinkedBase; |
|
323 TInt nimports=gX86imp?gX86num_imports:pefile.NumberOfImports(); |
|
324 |
|
325 TInt importSectionSize; |
|
326 char *newImportSection=CreateImportSection(pefile, importSectionSize); |
|
327 |
|
328 TInt size = ALIGN4(sizeof(E32ImageHeaderV)); // fixed for now because holes not supported |
|
329 iHdr->iCodeOffset = size; |
|
330 TInt pos = size; |
|
331 size+=DoCodeHeader(pefile); |
|
332 TInt t=DoDataHeader(pefile, aDataBase); |
|
333 if (t>0) |
|
334 { |
|
335 iHdr->iDataOffset = size; |
|
336 size += t; |
|
337 } |
|
338 if (importSectionSize!=0) |
|
339 { |
|
340 iHdr->iImportOffset = size; |
|
341 size += importSectionSize; |
|
342 } |
|
343 |
|
344 char *newCodeRelocs=NULL; |
|
345 char *newDataRelocs=NULL; |
|
346 TInt codeRelocSize=0, dataRelocSize=0; |
|
347 TInt nrelocs=pefile.NumberOfRelocs(); |
|
348 if (nrelocs) |
|
349 { |
|
350 TUint *relocs=new TUint [nrelocs]; |
|
351 TUint *relocsection=new TUint [nrelocs]; |
|
352 pefile.GetRelocs(relocs, relocsection, nrelocs); |
|
353 FixRelocs(pefile, relocs, relocsection, nrelocs); |
|
354 newCodeRelocs=CreateCodeRelocs(relocs, relocsection, nrelocs, codeRelocSize); |
|
355 newDataRelocs=CreateDataRelocs(relocs, relocsection, nrelocs, dataRelocSize); |
|
356 if (codeRelocSize) |
|
357 { |
|
358 iHdr->iCodeRelocOffset = size; |
|
359 size += codeRelocSize; |
|
360 } |
|
361 if (dataRelocSize) |
|
362 { |
|
363 iHdr->iDataRelocOffset = size; |
|
364 size += dataRelocSize; |
|
365 } |
|
366 delete [] relocs; |
|
367 delete [] relocsection; |
|
368 } |
|
369 |
|
370 Adjust(size); |
|
371 t=CopyCode(iData + pos, pefile); |
|
372 if (t<0) |
|
373 return KErrGeneral; |
|
374 pos += t; |
|
375 pos += CopyData(iData + pos, pefile); |
|
376 if (nimports) |
|
377 { |
|
378 memcpy(iData + pos, newImportSection, importSectionSize); |
|
379 pos += importSectionSize; |
|
380 } |
|
381 if (codeRelocSize) |
|
382 { |
|
383 memcpy(iData + pos, newCodeRelocs, codeRelocSize); |
|
384 pos += codeRelocSize; |
|
385 } |
|
386 if (dataRelocSize) |
|
387 { |
|
388 memcpy(iData + pos, newDataRelocs, dataRelocSize); |
|
389 pos += dataRelocSize; |
|
390 } |
|
391 |
|
392 // locate the entry point |
|
393 // entry point must be in the text section |
|
394 TInt entryPointSectionIndex=pefile.FindSectionByVa(pefile.iEntryPoint+pefile.iLinkedBase); |
|
395 TUint entryPointOffset=pefile.iEntryPoint-pefile.iSectionHeader[entryPointSectionIndex]->VirtualAddress; |
|
396 if (entryPointSectionIndex!=KTextSection) |
|
397 return Print(EError, "Entry Point not in code section\n"); |
|
398 |
|
399 // Arrange a header for this E32 Image |
|
400 switch (pefile.iCpu) |
|
401 { |
|
402 case IMAGE_FILE_MACHINE_I386: |
|
403 iHdr->iCpuIdentifier = (TUint16)ECpuX86; |
|
404 break; |
|
405 case 0x0a00: |
|
406 iHdr->iCpuIdentifier = (TUint16)ECpuArmV4; |
|
407 break; |
|
408 case 0x0b00: |
|
409 iHdr->iCpuIdentifier = (TUint16)ECpuMCore; |
|
410 break; |
|
411 default: |
|
412 iHdr->iCpuIdentifier = (TUint16)ECpuUnknown; |
|
413 break; |
|
414 } |
|
415 |
|
416 // Import format is PE-derived without redundant ordinal lists |
|
417 // ABI is GCC98r2 ABI (on ARM) |
|
418 iHdr->iFlags |= KImageImpFmt_PE2; |
|
419 |
|
420 if (pefile.iImageIsDll) |
|
421 { |
|
422 iHdr->iFlags|=KImageDll; |
|
423 if (iHdr->iDataSize && !aAllowDllData) |
|
424 return Print(EError, "Dll '%s' has initialised data.\n", iFileName); |
|
425 if (iHdr->iBssSize && !aAllowDllData) |
|
426 return Print(EError, "Dll '%s' has uninitialised data.\n", iFileName); |
|
427 } |
|
428 iHdr->iHeapSizeMin=pefile.iHeapCommittedSize; |
|
429 iHdr->iHeapSizeMax=pefile.iHeapReservedSize; |
|
430 iHdr->iStackSize=pefile.iStackCommittedSize; |
|
431 iHdr->iEntryPoint=entryPointOffset; |
|
432 r = DetermineEntryPointType(); |
|
433 if (r == KErrCorrupt) |
|
434 return Print(EError, "File '%s': Bad Entry Point.\n", iFileName); |
|
435 else if (r == KErrNotSupported) |
|
436 return Print(EError, "File '%s': Bad Entry Point Type.\n", iFileName); |
|
437 |
|
438 delete [] newImportSection; |
|
439 delete [] newCodeRelocs; |
|
440 delete [] newDataRelocs; |
|
441 |
|
442 return KErrNone; |
|
443 } |
|
444 |
|
445 TBool E32ImageFile_PE::Translate(PEFile &aPeFile) |
|
446 // |
|
447 // |
|
448 // |
|
449 { |
|
450 |
|
451 return Translate((const char*)aPeFile.iFileName, (TUint)0, EFalse, EFalse); |
|
452 } |
|
453 |