bintools/petools/pefile/pe_tran.cpp
changeset 607 378360dbbdba
parent 600 6d08f4a05d93
equal deleted inserted replaced
591:22486c9c7b15 607:378360dbbdba
       
     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