imgtools/romtools/rombuild/r_rom.cpp
changeset 0 044383f39525
child 590 360bd6b35136
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imgtools/romtools/rombuild/r_rom.cpp	Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,2708 @@
+/*
+* 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 <e32std.h>
+#include <e32std_private.h>
+#include <e32uid.h>
+#include "h_utl.h"
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
+#include <iomanip>
+#else //!__MSVCDOTNET__
+#include <iomanip.h>
+#endif //__MSVCDOTNET__
+
+#include "r_global.h"
+#include "r_obey.h"
+#include "r_rom.h"
+#include "r_dir.h"
+#include "patchdataprocessor.h"
+#include "memmap.h"
+#include "byte_pair.h"
+
+const TInt KSpareExports=16;
+extern TInt gThreadNum;
+extern char* gDepInfoFile;
+extern TBool gGenDepGraph;
+
+TUint32 DeflateCompressCheck(char *bytes,TInt size,ostream &os);
+void DeflateCompress(char *bytes,TInt size,ostream &os);
+void InflateUnCompress(unsigned char* source, int sourcesize,unsigned char* dest, int destsize);
+
+EntryQueue* LoadImageWorker::m_queue = NULL;
+TInt LoadImageWorker::m_errors = 0;
+TMemModel LoadImageWorker::m_memmodel;
+boost::mutex LoadImageWorker::m_mutex;
+LoadImageWorker::LoadImageWorker(EntryQueue* aQueue, TMemModel aMemModel)
+	{
+	m_queue = aQueue;
+	m_memmodel = aMemModel;
+	}
+void LoadImageWorker::operator()()
+	{
+	while(1)
+		{
+		m_mutex.lock();
+		if(m_queue->size() > 0)
+			{
+			TRomBuilderEntry * current = m_queue->front();
+			m_queue->pop();
+			m_mutex.unlock();
+			TInt err = current->OpenImageFile();
+			if(err)
+				{
+				m_mutex.lock();
+				++m_errors;
+				m_mutex.unlock();
+				continue;
+				}
+			if(current->iOverrideFlags&KOverrideAddress || current->iHdr->iFlags & KImageFixedAddressExe)
+				{
+				if(m_memmodel != E_MM_Multiple && m_memmodel != E_MM_Flexible &&  !current->IsDll())
+					current->iRomImageFlags |=KRomImageFlagFixedAddressExe;
+				}
+			if(gPagedRom)
+				{
+				if(current->iHdr->iFlags&KImageCodePaged)
+					{
+					current->iRomImageFlags&=~KRomImageFlagCodeUnpaged;
+					current->iRomImageFlags|=KRomImageFlagCodePaged;
+					}
+				if(current->iHdr->iFlags&KImageCodeUnpaged)
+					{
+					current->iRomImageFlags|=KRomImageFlagCodeUnpaged;
+					current->iRomImageFlags&=~KRomImageFlagCodePaged;
+					}
+				}
+			if(current->iHdr->iFlags&KImageDataPaged)
+				{
+				current->iRomImageFlags&=~KRomImageFlagDataUnpaged;
+				current->iRomImageFlags|=KRomImageFlagDataPaged;
+				}
+			if(current->iHdr->iFlags&KImageDataUnpaged)
+				{
+				current->iRomImageFlags|=KRomImageFlagDataUnpaged;
+				current->iRomImageFlags&=~KRomImageFlagDataPaged;
+				}
+			if(current->iHdr->iFlags&KImageDebuggable)
+				{
+				current->iRomImageFlags|=KRomImageDebuggable;
+				}
+				else
+				{
+				current->iRomImageFlags&=~KRomImageDebuggable;
+				}
+			}
+			else
+			{
+			m_mutex.unlock();
+			break;
+			}
+		}
+	}
+E32Rom* CompressPageWorker::m_rom = NULL;
+TInt CompressPageWorker::m_nextpage = 0;
+TInt CompressPageWorker::m_totalpages = 0;
+TInt CompressPageWorker::m_pagesize = 0;
+boost::mutex CompressPageWorker::m_mutex;
+TInt CompressPageWorker::m_error = 0;
+CompressPageWorker::CompressPageWorker(E32Rom* aRom, TInt aPageSize, TInt aTotalPages, TInt aNextPage)
+	{
+	m_rom = aRom;
+	m_pagesize = aPageSize;
+	m_totalpages = aTotalPages;
+	m_nextpage = aNextPage;
+	}
+void CompressPageWorker::operator()()
+	{
+	SRomPageInfo* pPageBase = (SRomPageInfo*)((TInt)m_rom->iHeader + m_rom->iHeader->iRomPageIndex);
+	CBytePair bpe(gFastCompress);
+	while(1)
+		{
+		m_mutex.lock();
+		TInt currentPageIndex = m_nextpage++;
+		m_mutex.unlock();
+		if(currentPageIndex < m_totalpages)
+			{
+			TInt inOffset = m_pagesize * currentPageIndex;
+			TUint8 attrib = (TUint8)SRomPageInfo::EPageable;
+			SRomPageInfo info ={ (TUint32)inOffset, (TUint16)m_pagesize, (TUint8)SRomPageInfo::EBytePair, attrib };
+			TUint8* in = (TUint8*) m_rom->iHeader + inOffset;
+			TUint8* out = in;
+			TInt outSize = BytePairCompress(out, in, m_pagesize, &bpe);
+			if(outSize == KErrTooBig)
+				{
+				info.iCompressionType = SRomPageInfo::ENoCompression;
+				memcpy(out, in, m_pagesize);
+				outSize = m_pagesize;
+				}
+				if(outSize < 0 )
+					{
+					m_mutex.lock();
+					m_error = outSize;
+					m_mutex.unlock();
+					break;
+					}
+				info.iDataSize = (TUint16) outSize;
+				*(pPageBase + currentPageIndex) = info;
+				if((currentPageIndex & 255) == 255)
+					{
+					m_mutex.lock();
+					Print(EAlways, ".\n");
+					m_mutex.unlock();
+					}
+				}
+			else
+			{
+			break;
+			}
+		}
+	}
+	
+////////////////////////////////////////////////////////////////////////
+
+TAddressRange::TAddressRange() 
+	: iImagePtr(0), iImageAddr(0), iRunAddr(0), iSize(0) 
+	{
+	}
+
+void TAddressRange::Append(TAddressRange& aRange)
+	{ 
+	if(aRange.iSize) 
+		{ 
+		aRange.iImagePtr = iImagePtr;
+		aRange.iImageAddr = iImageAddr;
+		aRange.iRunAddr = iRunAddr;
+		Extend(aRange.iSize); 
+		} 
+	}
+
+void TAddressRange::Move(TInt aOffset) 
+	{ 
+	iImagePtr = static_cast<char*>(iImagePtr) + aOffset; 
+	iImageAddr += aOffset; 
+	iRunAddr += aOffset;
+	}
+
+void TAddressRange::Extend(TInt aOffset) 
+	{ 
+	Move(aOffset);
+	iSize += aOffset; 
+	}
+
+////////////////////////////////////////////////////////////////////////
+
+inline TUint32 AlignData(TUint32 anAddr)
+	{
+	return ((anAddr+0x0f)&~0x0f);
+	}
+
+TUint32 E32Rom::AlignToPage(TUint32 anAddr)
+	{
+	TUint a=(TUint)iObey->iPageSize-1;
+	return ((anAddr+a)&~a);
+	}
+
+/*
+Allocate virtual memory for static data in rom.
+@param aAddr Base address of last allocated memory.
+@param aSize Size of memory to allocate.
+@return Address allocated. This is below aAddr.
+*/
+TUint32 E32Rom::AllocVirtual(TUint32 aAddr,TUint aSize)
+	{
+	TInt align = iObey->iVirtualAllocSize;
+	if(align<0)
+		{
+		align = -align; // get correct sign
+		// -ve align means also align to next power-of-two >= aSize...
+		while(aSize>(TUint)align)
+			align <<=1;
+		}
+
+	TUint mask = (TUint)align-1;
+	aSize = (aSize+mask)&~mask; // round up
+	aAddr &= ~mask; // round down
+	return aAddr-aSize;
+	}
+
+TUint32 E32Rom::AlignToChunk(TUint32 anAddr)
+	{
+	TUint a=(TUint)iObey->iChunkSize-1;
+	return ((anAddr+a)&~a);
+	}
+
+COrderedFileList::COrderedFileList(TInt aMaxFiles)
+	: iCount(0), iMaxFiles(aMaxFiles), iOrderedFiles(NULL)
+	{}
+
+COrderedFileList::~COrderedFileList()
+	{
+	iCount=0;
+	delete[] iOrderedFiles;
+	}
+
+COrderedFileList* COrderedFileList::New(TInt aMaxFiles)
+	{
+	COrderedFileList *pL=new COrderedFileList(aMaxFiles);
+	pL->iOrderedFiles=new TRomBuilderEntry*[aMaxFiles];
+	return pL;
+	}
+
+void COrderedFileList::Add(TRomBuilderEntry* anEntry)
+	{
+	// note: this routine assumes that the set of kernel-mode files
+	// (primary/extension/device) required by a given variant is linearly ordered by <=
+	// e.g. can't have three variants {A,B,V1} {A,B,C,V2} {A,C,V3} because B and C
+	// are unordered with respect to <=, since neither of
+	// {n | Vn requires B} and {n | Vn requires C} is a subset of the other.
+	// In a case like this, ROMBUILD may fail to resolve the addresses of some global data
+	THardwareVariant& v=anEntry->iHardwareVariant;
+	TInt i=0;
+	while(i<iCount && v<=iOrderedFiles[i]->iHardwareVariant) i++;
+	TInt j=iCount;
+	while(j>i)
+		{
+		iOrderedFiles[j]=iOrderedFiles[j-1];
+		j--;
+		}
+	iOrderedFiles[i]=anEntry;
+	iCount++;
+	}
+
+void GetFileNameAndUid(char *aDllName, TUid &aDllUid, char *aExportName)
+	{	
+	strcpy(aDllName, aExportName);
+	aDllUid=KNullUid;
+	TInt start;
+	for (start=0; start<(TInt)strlen(aExportName) && aExportName[start]!='['; start++)
+		;
+	if (start==(TInt)strlen(aExportName))
+		start=KErrNotFound;
+	TInt end=strlen(aExportName)-1;
+	while (end>=0)
+		{
+		if (aExportName[end]==']')
+			break;
+		--end;
+		}
+	if (end<0)
+		end=KErrNotFound;
+
+	if ((start!=KErrNotFound) && (end!=KErrNotFound) && (end>start))
+		{
+		// Importing from DLL with Uid
+		char uidStr[0x100];
+		strcpy(uidStr, "0x");
+		strncat(uidStr, aExportName+start+1, end-start-1);
+		#ifdef __TOOLS2__
+		istringstream val(uidStr);
+		#else
+		istrstream val(uidStr,strlen(uidStr));
+		#endif
+
+#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
+		val >> setbase(0);
+#endif //__MSVCDOTNET__
+
+		TUint32 u;
+		val >> u;
+		val.peek();
+		if (val.eof())
+			{
+			aDllUid=TUid::Uid(u);
+			char *dot=aExportName+strlen(aExportName)-1;
+			while (dot>=aExportName)
+				{
+				if (*dot=='.')
+					break;
+				dot--;
+				}
+			if (dot<aExportName) // no dot
+				aDllName[start]=0;
+			else
+				{
+				aDllName[start]=0;
+				strcat(aDllName, dot);
+				}
+			}
+		}
+	}
+
+E32Rom::E32Rom(CObeyFile *aObey)
+//
+// Constructor
+//
+	{
+
+	iSize=sizeof(TRomLoaderHeader)+aObey->iRomSize;
+	iObey=aObey;
+	iPeFiles=NULL;
+
+	if(gLowMem)
+	{
+		iImageMap = new Memmap();
+
+		if(iImageMap == NULL)
+		{
+			iSize = 0;
+			Print(EError, "Out of memory.\n");
+		}
+		else
+		{
+			iImageMap->SetMaxMapSize(iSize);
+			if(iImageMap->CreateMemoryMap(0, 0xff) == EFalse)
+			{
+				iSize = 0;
+				Print(EError, "Failed to create image map object");
+
+				iImageMap->CloseMemoryMap(ETrue);
+				delete iImageMap;
+				iImageMap = NULL;
+			}
+			else
+			{
+				iData = iImageMap->GetMemoryMapPointer();
+			}
+		}
+	}
+	else
+	{
+		iData=new char [iSize];
+		if (iData==NULL)
+			{
+			iSize=0;
+			Print(EError, "Out of memory.\n");
+			}
+		HMem::Set(iData, 0xff, iSize);
+	}
+	iHeader=(TRomHeader *)(iData+sizeof(TRomLoaderHeader));
+	iExtensionRomHeader=NULL;
+	iLoaderHeader=(TRomLoaderHeader *)iData;
+	iSectionPtr=(char *)iHeader+aObey->iSectionStart-aObey->iRomLinearBase+sizeof(TRomSectionHeader);
+	TheRomHeader=(ImpTRomHeader *)iHeader;
+	TheRomMem=(TUint32)iHeader;
+	iNextDataChunkBase=aObey->iKernDataRunAddress;
+	iTotalSvDataSize=0;
+	iNextDllDataAddr=aObey->iDllDataTop;
+	iPrevPrimaryAddress=NULL;
+	iPrevVariantAddress=NULL;
+	iVariantFileLists=NULL;
+	iImportsFixedUp=0;
+	iBranchesFixedUp=0;
+	iVtableEntriesFixedUp=0;
+	iOverhead=0;
+	}
+
+E32Rom::~E32Rom()
+//
+// Destructor
+//
+	{
+
+	if(gLowMem)
+	{
+		iImageMap->CloseMemoryMap(ETrue);
+		delete iImageMap;
+	}
+	else
+		delete iData;
+	delete [] iPeFiles;
+	if (iVariantFileLists)
+		{
+		TInt i;
+		for (i=0; i<iObey->iNumberOfVariants; i++)
+			delete iVariantFileLists[i];
+		delete [] iVariantFileLists;
+		}
+	}
+
+TInt E32Rom::Align(TInt aVal)
+//
+// Align to romalign
+//
+	{
+ 	
+	return ((aVal+iObey->iRomAlign-1)/iObey->iRomAlign)*iObey->iRomAlign;
+	}
+
+TInt E32Rom::LoadContents(char*& anAddr, TRomHeader* aHeader)
+	{
+	// Load all the PE/E32Image files
+	TInt nfiles=iObey->iNumberOfPeFiles;
+	iPeFiles=new TRomBuilderEntry* [nfiles];
+	if (!iPeFiles)
+		return Print(EError, "Out of memory.\n");
+
+	TInt r=TranslateFiles();
+	if (r!=KErrNone)
+		return r;
+	
+	ProcessDllData();
+
+	EnumerateVariants();
+
+	r=BuildDependenceGraph();
+	if (r!=KErrNone)
+		return r;
+
+	// Update the ROM image headers with SMP information.
+	SetSmpFlags();
+
+	r=ProcessDependencies();
+	if (r!=KErrNone)
+		return r;
+
+	char* addr = anAddr;
+	TRomExceptionSearchTable* exceptionSearchTable = 0;
+
+	if(gPagedRom)
+		{
+		gDepInfoFile = (char* )malloc(strlen((char *)iObey->iRomFileName) + 1);
+		strcpy(gDepInfoFile, (char *)iObey->iRomFileName);
+		iObey->SetArea().DefaultArea()->SortFilesForPagedRom();
+		// exception search table needs to go at start of ROM to make it not demand paged...
+		addr = ReserveRomExceptionSearchTable(addr,exceptionSearchTable);
+		}
+	else if(gGenDepGraph)
+		{
+			Print(EWarning, "Not dependence information in an unpaged ROM.");
+		}
+
+	addr=WriteDirectory(addr, aHeader);
+	// Aligned
+
+	TRACE(TSCRATCH,Print(EAlways,"Directory written\n"));
+
+	// Stick all the files in ROM
+
+	TReloc* relocationTable;
+	addr = AllocateRelocationTable(addr, relocationTable);
+	aHeader->iRelocInfo = relocationTable ? ActualToRomAddress(relocationTable) : 0;
+	// Aligned
+
+	TRACE(TSCRATCH,Print(EAlways,"Done AllocateRelocationTable\n"));
+
+	CalculateDataAddresses();
+	addr = LayoutRom(addr);
+
+	TRACE(TSCRATCH,Print(EAlways,"Done LayoutRom\n"));
+
+	FillInRelocationTable(relocationTable);
+
+	TRACE(TSCRATCH,Print(EAlways,"Done FillInRelocationTable\n"));
+
+	if(!exceptionSearchTable)
+		addr = ReserveRomExceptionSearchTable(addr,exceptionSearchTable);
+	ConstructRomExceptionSearchTable(exceptionSearchTable);
+
+	TRACE(TSCRATCH,Print(EAlways,"Done ConstructRomExceptionSearchTable\n"));
+
+	LinkKernelExtensions(iObey->iExtensions, iObey->iNumberOfExtensions);
+
+	TRACE(TSCRATCH,Print(EAlways,"Done LinkKernelExtensions\n"));
+
+	r=ResolveDllRefTables();
+	if (r!=KErrNone)
+		return r;
+	r=ResolveImports();
+	if (r!=KErrNone)
+		return r;
+	if (iObey->iCollapseMode>ECollapseNone)
+		{
+		r=CollapseImportThunks();
+		if (r!=KErrNone)
+			return r;
+		if (iObey->iCollapseMode>ECollapseImportThunksOnly)
+			{
+			r=CollapseBranches();
+			if (r!=KErrNone)
+				return r;
+			}
+		Print(ELog,"%d imports, %d branches, %d vtable entries fixed up\n",
+			  iImportsFixedUp,iBranchesFixedUp,iVtableEntriesFixedUp);
+		}
+
+	iSizeUsed=(TInt)addr-(TInt)iHeader;
+	Print(ELog, "\n%08x of %08x bytes used.\n", iSizeUsed, iSize-sizeof(TRomLoaderHeader));
+
+	// round the rom size in the header to a multiple of 1 Megabyte
+	TInt rounded = ((iSizeUsed+0xfffff)&0xfff00000);
+	if (rounded < iObey->iRomSize)
+		iObey->iRomSize = rounded;
+	iUncompressedSize = iSizeUsed;
+
+	anAddr = addr;
+
+	return KErrNone;
+	}
+
+
+void E32Rom::CreatePageIndex(char*& aAddr)
+	{
+	iHeader->iRomPageIndex = 0;
+	if(gPagedRom==0 || gEnableCompress==0)
+		return;
+
+	// Insert space for Rom Page Info table...
+	iHeader->iRomPageIndex = (TInt)aAddr-(TInt)iHeader;
+	TInt pageSize = iObey->iPageSize;
+	TInt numPages = iSize/pageSize+1;
+	TInt pageInfoSize = numPages*sizeof(SRomPageInfo);
+	
+	gPageIndexTableSize = pageInfoSize;		// For accumulate uncompressed un-paged size added Page Index Table
+		
+	Print(ELog, "Inserting %d bytes for RomPageInfo at ROM offset 0x%08x\n", pageInfoSize, iHeader->iRomPageIndex);
+	memset(aAddr,0,pageInfoSize);
+	iOverhead += pageInfoSize;
+	aAddr += pageInfoSize;
+	}
+
+TInt E32Rom::SetupPages()
+	{
+	iHeader->iPageableRomStart = 0;
+	iHeader->iPageableRomSize = 0;
+	iHeader->iDemandPagingConfig = gDemandPagingConfig;
+
+	if(!gPagedRom)
+		return KErrNone;
+
+	// Initialise the Rom Page Info for each page which indicates it is uncompressed...
+	TInt pageSize = iObey->iPageSize;
+
+	TInt pagedStartOffset = 0x7fffffff;
+	TRomBuilderEntry* e = iObey->SetArea().DefaultArea()->iFirstPagedCode;
+	if(e)
+		{
+		// we have paged code...
+		pagedStartOffset = e->RomEntry()->iAddressLin-iObey->iRomLinearBase;
+		pagedStartOffset = (pagedStartOffset+pageSize-1)&~(pageSize-1); // round up to next page;
+		iHeader->iPageableRomStart = pagedStartOffset;
+		TInt pageableSize = iSizeUsed-pagedStartOffset;
+		if(pageableSize>0)
+			iHeader->iPageableRomSize = pageableSize;
+		}
+	
+	return KErrNone;
+	}
+
+TInt E32Rom::CompressPages()
+	{
+	
+	if(!gPagedRom || !gEnableCompress)
+		return KErrNone;
+
+	// Initialise the Rom Page Info for each page which indicates it is uncompressed...
+	TInt pageSize = iObey->iPageSize;
+	TInt numPages = (iSizeUsed+pageSize-1)/pageSize;
+
+	TInt pagedStartOffset = iHeader->iPageableRomStart;
+
+	Print(EAlways, "\nCompressing pages...\n");
+	TInt inOffset = 0;
+    SRomPageInfo* pi = (SRomPageInfo*)((TInt)iHeader+iHeader->iRomPageIndex);
+	TInt currentIndex = 0;
+	while(inOffset < pagedStartOffset)
+		{
+		
+		TUint8 attrib = (TUint8)0;
+		SRomPageInfo info = {(TUint32)inOffset,(TUint16)pageSize,(TUint8)SRomPageInfo::EBytePair,(TUint8)attrib};
+		info.iDataSize = (TUint16) pageSize;
+		*pi++ = info;
+		inOffset += pageSize;
+		if((currentIndex & 255) == 255)
+			Print(EAlways, ".\n");
+		currentIndex++;
+		}
+	CompressPageWorker compressworker(this, pageSize, numPages, currentIndex);
+
+	boost::thread_group threads;
+	for(int i = 0; i < gThreadNum; i++)
+		{
+		threads.create_thread(compressworker);
+		}
+	threads.join_all();
+	if(compressworker.m_error < 0)
+	       return compressworker.m_error;
+	for(;currentIndex < numPages - 1; currentIndex++)
+		{
+		pi++;
+		SRomPageInfo* prev = pi - 1;
+		TUint8* dest = (TUint8*) iHeader + prev->iDataStart + prev->iDataSize;
+		TUint8* src = (TUint8*) iHeader + pi->iDataStart;
+		memcpy(dest, src, pi->iDataSize);
+		pi->iDataStart = prev->iDataStart + prev->iDataSize;
+		}
+	TInt relSize = pi->iDataStart + pi->iDataSize;
+
+	memset((TUint8*)iHeader + relSize, 0xff, iSizeUsed - relSize);
+	TInt compression = (iSizeUsed >= 1000) ? (relSize*10)/(iSizeUsed/1000) : (relSize*10000)/iSizeUsed;
+	Print(EAlways, "%d.%02d%%\n", compression/100, compression%100);
+	iSizeUsed = relSize;
+	return KErrNone;
+	}
+
+TInt E32Rom::CompressPage(SRomPageInfo& aPageInfo, TInt aOutOffset, CBytePair * aBPE)
+	{
+	TUint8* in = (TUint8*)iHeader+aPageInfo.iDataStart;
+	TInt inSize = aPageInfo.iDataSize;
+	TUint8* out = (TUint8*)iHeader+aOutOffset;
+	switch(aPageInfo.iCompressionType)
+		{
+	case SRomPageInfo::ENoCompression:
+		memcpy(out,in,inSize);
+		return inSize;
+
+	case SRomPageInfo::EBytePair:
+		{
+		TInt r = BytePairCompress(out, in, inSize, aBPE);
+		if(r!=KErrTooBig)
+			return r;
+		// data can't be compressed...
+		aPageInfo.iCompressionType = SRomPageInfo::ENoCompression;
+		memcpy(out,in,inSize);
+		return inSize;
+		}
+
+	default:
+		Print(EError, "Unsupported page compression type (%d)\n", aPageInfo.iCompressionType);
+		return KErrNotSupported;
+		}
+	}
+
+
+// Avoid "warning" about constant expression
+static void checksize(const char* aTypeName, int aSize, int aCorrectSize)
+	{
+	if (aSize != aCorrectSize)
+		Print(EError, "sizeof(%s) = %d, should be %d\n", aTypeName, aSize, aCorrectSize);
+	}
+
+TInt E32Rom::CreateExtension(MRomImage* aKernelRom) 
+	{
+
+	// sanity check
+	checksize("TExtensionRomHeader", sizeof(TExtensionRomHeader), 128);
+
+	char *addr=(char *)iHeader;
+	iExtensionRomHeader=(TExtensionRomHeader*)addr;
+	addr += sizeof(TExtensionRomHeader);
+	// Aligned
+
+	TRomHeader dummy;
+	TInt r=LoadContents(addr, &dummy);
+	if (r!=KErrNone)
+		{
+		Print(EError, "LoadContents failed - return code %d\n", r);
+		return r;
+		}
+	iExtensionRomHeader->iRomRootDirectoryList = dummy.iRomRootDirectoryList;
+
+	iLoaderHeader->SetUp(iObey);
+	FinaliseExtensionHeader(aKernelRom);
+	DisplayExtensionHeader();
+
+	return KErrNone;
+	}
+	
+TInt E32Rom::Create()
+	{
+
+	TVariantList::Setup(iObey);
+	char *addr=(char *)iHeader;
+	// Aligned
+
+	// Put the bootstrap in rom - it contains a hole at offset 0x80 where the 
+	// TRomHeader information will be placed later
+
+	gBootstrapSize = HFile::Read(iObey->iBootFileName, iHeader);
+	if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+		Print(ELog, "bootstrapSize: 0x%08x, (%d)\n", gBootstrapSize, gBootstrapSize);	
+	
+	if (gBootstrapSize==0)
+		return Print(EError, "Cannot open the bootstrap file '%s'.\n", iObey->iBootFileName);
+	gBootstrapSize=Align(gBootstrapSize);
+	addr+=gBootstrapSize;
+	iOverhead=gBootstrapSize;
+	// Aligned
+
+	CreatePageIndex(addr);
+
+	TInt r=LoadContents(addr, iHeader);
+	if (r!=KErrNone)
+		{
+		Print(EError, "LoadContents failed - return code %d\n", r);
+		return r;
+		}
+
+	r = SetupPages(); // initialize ROM paging info...
+	if(r!=KErrNone)
+		{
+		Print(EError, "Setup pages information failed - return code %d\n", r);
+		return r;
+		}
+	
+	r = CheckUnpagedMemSize(); // check for unpaged memory overflow
+	if(r!=KErrNone)
+	{
+		return r;
+	}
+	
+	r = CompressPages(); // setup ROM paging info...
+	if(r!=KErrNone)
+		{
+		Print(EError, "CompressPages failed - return code %d\n", r);
+		return r;
+		}
+
+	iLoaderHeader->SetUp(iObey);
+	ImpTRomHeader* header = (ImpTRomHeader *)iHeader;
+	header->SetUp(iObey);
+	header->iTotalSvDataSize=iTotalSvDataSize;
+	if (iObey->iMemModel==E_MM_Direct)
+		{
+		header->iUserDataAddress=iObey->iDataRunAddress;
+		header->iTotalUserDataSize=iNextDataChunkBase-iObey->iDataRunAddress;
+		}
+	else
+		{
+		header->iUserDataAddress=iObey->iDllDataTop;
+		header->iTotalUserDataSize=iObey->iDllDataTop-iNextDllDataAddr;
+		}
+	if (header->iRomSectionHeader)
+		FinaliseSectionHeader();	// sorts out the second section checksum
+
+	header->CheckSum(iObey->iCheckSum);	// finally, sort out the overall checksum
+
+	header->Display();
+
+	TUint testCheckSum = HMem::CheckSum((TUint *)iHeader, iHeader->iRomSize);
+	Print(ELog, "Rom 32bit words sum to   %08x\n", testCheckSum);
+	if (testCheckSum != iObey->iCheckSum)
+		return Print(EError, "Rom checksum is incorrect: %08x should be %08x\n",
+					testCheckSum, iObey->iCheckSum);
+
+	// 8bit checksum = sum of bytes
+	// odd/even checksum = checksum of the odd and even halfwords of the image
+
+	Print(ELog, "Rom 8bit checksum        %08x\n", HMem::CheckSum8((TUint8 *)iHeader, iHeader->iRomSize));
+	Print(ELog, "Rom 8bit odd checksum    %08x\n", HMem::CheckSumOdd8((TUint8 *)iHeader, iHeader->iRomSize));
+	Print(ELog, "Rom 8bit even checksum   %08x\n", HMem::CheckSumEven8((TUint8 *)iHeader, iHeader->iRomSize));
+
+	if (iHeader->iPrimaryFile)
+		{
+		if (iObey->iKernelModel==ESingleKernel)
+			{
+			Print(ELog,"\nPrimary details (Single Kernel):\n");
+			TRomEntry *r = (TRomEntry *)(iHeader->iPrimaryFile-iObey->iRomLinearBase+(char *)iHeader);
+			TRomImageHeader *hdr = (TRomImageHeader *)(r->iAddressLin-iObey->iRomLinearBase+(char *)iHeader);
+			Display(hdr);
+			Print(ELog,"\n");
+			}
+		else if (iObey->iKernelModel==EMultipleKernels)
+			{
+			Print(ELog,"\nPrimary details (Multiple Kernels):\n");
+			TRomEntry *r = (TRomEntry *)(iHeader->iPrimaryFile-iObey->iRomLinearBase+(char *)iHeader);
+			TInt n=1;
+			FOREVER
+					{
+					Print(ELog,"\nKernel %d:\n",n);
+					TRomImageHeader *hdr = (TRomImageHeader *)(r->iAddressLin-iObey->iRomLinearBase+(char *)iHeader);
+					Display(hdr);
+					Print(ELog,"\n");
+					if (!hdr->iNextExtension)
+						break;
+					r=(TRomEntry*)(hdr->iNextExtension-iObey->iRomLinearBase+(char*)iHeader);
+					n++;
+					}
+			}
+		}
+
+	return KErrNone;
+	}
+
+char *E32Rom::WriteDirectory(char *aAddr, TRomHeader* aHeader)
+//
+// Write the directory structure where appropriate
+//
+	{
+
+	TLinAddr dirptr=ActualToRomAddress(aAddr);
+	if (iObey->iSectionPosition==-1)
+		{
+		// Just the one rom.  Put the directory structure at aAddr
+		iDirectorySize=WriteHeadersToRom(aAddr);
+		aAddr+=Align(iDirectorySize);
+		}
+	else
+		{
+		// Put the directory structure in the second ROM, after the SectionHeader
+		// and the second section information for first section files
+		TInt size=0;
+		TInt i;
+		for (i=0; i<iObey->iNumberOfPeFiles; i++)
+			{
+			TRomBuilderEntry *file=iPeFiles[i];
+			if (file->iRomSectionNumber!=0)
+				break;
+			TInt size1, size2;
+			file->SizeInSections(size1,size2);
+			size+=size2;
+			}
+		dirptr=ActualToRomAddress(iSectionPtr)+size;
+		iDirectorySize=WriteHeadersToRom(RomToActualAddress(dirptr));
+		}
+	aHeader->iRomRootDirectoryList=dirptr;
+	return aAddr;
+	}
+
+void E32Rom::Display(TRomImageHeader *aHdr)
+//
+// Print info on a file
+//
+	{
+	TRACE(TAREA, Print(ELog, "+Display header %08x\n", aHdr));
+	Print(ELog, "Uids:                    %08x %08x %08x %08x\n", aHdr->iUid1, aHdr->iUid2, aHdr->iUid3, aHdr->iUidChecksum);
+	Print(ELog, "Entry point:             %08x\n", aHdr->iEntryPoint);
+	Print(ELog, "Code start addr:         %08x\n", aHdr->iCodeAddress);
+	Print(ELog, "Data start addr:         %08x\n", aHdr->iDataAddress);
+	Print(ELog, "DataBssLinearBase:       %08x\n", aHdr->iDataBssLinearBase);
+	Print(ELog, "Text size:               %08x\n", aHdr->iTextSize);
+	Print(ELog, "Code size:               %08x\n", aHdr->iCodeSize);
+	Print(ELog, "Data size:               %08x\n", aHdr->iDataSize);
+	Print(ELog, "BssSize:                 %08x\n", aHdr->iBssSize);
+	Print(ELog, "Total data size:         %08x\n", aHdr->iTotalDataSize);
+	Print(ELog, "Heap min:                %08x\n", aHdr->iHeapSizeMin);
+	Print(ELog, "Heap max:                %08x\n", aHdr->iHeapSizeMax);
+	Print(ELog, "Stack size:              %08x\n", aHdr->iStackSize);
+	Print(ELog, "Dll ref table:           %08x\n", aHdr->iDllRefTable);
+	Print(ELog, "Export directory:        %08x\n", aHdr->iExportDir);
+	Print(ELog, "Export dir count:        %08x\n", aHdr->iExportDirCount);
+	Print(ELog, "Hardware variant:        %08x\n", aHdr->iHardwareVariant);
+	Print(ELog, "Flags:                   %08x\n", aHdr->iFlags);
+	Print(ELog, "Secure ID:               %08x\n", aHdr->iS.iSecureId);
+	Print(ELog, "Vendor ID:               %08x\n", aHdr->iS.iVendorId);
+	Print(ELog, "Capability:              %08x %08x\n", aHdr->iS.iCaps[1], aHdr->iS.iCaps[0]);
+	Print(ELog, "Tools Version:           %d.%02d(%d)\n", aHdr->iToolsVersion.iMajor, aHdr->iToolsVersion.iMinor, aHdr->iToolsVersion.iBuild);
+	Print(ELog, "Module Version:          %d.%d\n", aHdr->iModuleVersion>>16, aHdr->iModuleVersion&0x0000ffffu);
+	Print(ELog, "Exception Descriptor:    %08x\n", aHdr->iExceptionDescriptor);
+	Print(ELog, "Priority:                %d\n", aHdr->iPriority);
+	}
+
+void E32Rom::DisplaySizes(TPrintType aWhere)
+	{
+
+	Print(aWhere, "Summary of file sizes in rom:\n");
+	Print(aWhere, "Overhead (bootstrap+gaps+sectioning)\t%d\n", iOverhead);
+	Print(aWhere, "Overhead (directory size)\t%d\n", iDirectorySize);
+	TRomBuilderEntry *file=iObey->FirstFile();
+	while (file)
+		{
+		file->DisplaySize(aWhere);
+		file=iObey->NextFile();
+		}
+	Print(aWhere, "\nTotal used\t%d\n", iSizeUsed);
+	Print(aWhere, "Free\t%d\n", iObey->iRomSize-iSizeUsed);
+
+	if (iObey->SetArea().Count() > 1)
+		{
+		Print(aWhere, "\nArea summary:\n");
+		for (NonDefaultAreasIterator it(iObey->SetArea());
+			 ! it.IsDone();
+			 it.GoToNext())
+			{
+			const Area& a = it.Current();
+			Print(aWhere, "%s\t used: %d bytes / free: %d bytes\n",
+				  a.Name(), a.UsedSize(), a.MaxSize()-a.UsedSize());
+			}
+		}
+	}
+
+TInt E32Rom::RequiredSize()
+//
+// Get the (approximate) required size of the Rom
+//
+	{
+
+	TInt sum=0;
+	TRomBuilderEntry *current=iObey->FirstFile();
+	while (current)
+		{
+		if (current->iResource || current->HCRDataFile())
+			sum+=Align(HFile::GetLength((TText*)current->iFileName));
+		else
+ 			sum+=Align(current->SizeInRom());
+		current=iObey->NextFile();
+		}
+	return sum+iOverhead+Align(iDirectorySize);
+	}
+
+TInt E32Rom::TranslateFiles()
+//
+// Load and translate all PE/E32 image files
+//
+	{
+
+	TInt i=0;
+	TInt total_errors = 0;
+	TRomBuilderEntry* current = 0;
+	EntryQueue imagesQueue;
+	for (current = iObey->FirstFile(); current; current = iObey->NextFile() )
+		{	
+		if ((!current->iResource) && (!current->HCRDataFile()))
+			{
+			iPeFiles[i++]=current;
+			imagesQueue.push(current);
+			}
+		}
+	LoadImageWorker loadworker(&imagesQueue, iObey->iMemModel);
+	boost::thread_group threads;
+	for(int i = 0; i < gThreadNum; i++)
+		{
+		threads.create_thread(loadworker);
+		}
+	threads.join_all();
+
+	total_errors = loadworker.m_errors;
+	if (total_errors)
+		return KErrGeneral;
+	for (current = iObey->FirstFile(); current; current = iObey->NextFile() )
+		{
+		if ((!current->iResource) && (!current->HCRDataFile()))
+			{
+			TInt err = CheckForVersionConflicts(current);
+			total_errors += err;
+			}
+		}
+	return total_errors ? KErrGeneral : KErrNone;
+	}
+
+const TText FileTypeFile[]=		"File     ";
+const TText FileTypePrimary[]=	"Primary  ";
+const TText FileTypeVariant[]=	"Variant  ";
+const TText FileTypeExtension[]="Extension";
+const TText FileTypeDevice[]=	"Device   ";
+
+void E32Rom::EnumerateVariants()
+	{
+	TInt vIndex;
+	TInt nFiles=iObey->iNumberOfExtensions+iObey->iNumberOfDevices+3;
+	iVariantFileLists=new COrderedFileList*[iObey->iNumberOfVariants];
+	for (vIndex=0; vIndex<iObey->iNumberOfVariants; vIndex++)
+		iVariantFileLists[vIndex]=COrderedFileList::New(nFiles);
+	for (vIndex=0; vIndex<iObey->iNumberOfVariants; vIndex++)
+		{
+		TRomBuilderEntry *variant=iObey->iVariants[vIndex];
+		THardwareVariant& v=variant->iHardwareVariant;
+		TInt i;
+		for (i=0; i<iObey->iNumberOfPrimaries; i++)
+			{
+			TRomBuilderEntry *primary=iObey->iPrimaries[i];
+			if (v<=primary->iHardwareVariant)
+				{
+				iVariantFileLists[vIndex]->Add(primary);
+				break;
+				}
+			}
+		iVariantFileLists[vIndex]->Add(variant);
+		for (i=0; i<iObey->iNumberOfExtensions; i++)
+			{
+			TRomBuilderEntry *ext=iObey->iExtensions[i];
+			if (v<=ext->iHardwareVariant)
+				{
+				iVariantFileLists[vIndex]->Add(ext);
+				}
+			}
+		for (i=0; i<iObey->iNumberOfDevices; i++)
+			{
+			TRomBuilderEntry *dev=iObey->iDevices[i];
+			if (v<=dev->iHardwareVariant)
+				{
+				iVariantFileLists[vIndex]->Add(dev);
+				}
+			}
+		}
+	TUint totalDataBss=0;
+	for (vIndex=0; vIndex<iObey->iNumberOfVariants; vIndex++)
+		{
+		TRomBuilderEntry *variant=iObey->iVariants[vIndex];
+		THardwareVariant& v=variant->iHardwareVariant;
+		COrderedFileList& files=*iVariantFileLists[vIndex];
+		TInt count=files.Count();
+		Print(ELog,"\nVariant %08x, %d Files:\n",v.ReturnVariant(),count); 
+		TInt i;
+		TUint dataOffset=0;
+		for (i=0; i<count; i++)
+			{
+			TRomBuilderEntry *pF=files[i];
+			TUint gap=0;
+			if (pF->iDataAlignment>0)
+				{
+				gap=(pF->iDataAlignment-dataOffset)%(pF->iDataAlignment);
+				dataOffset+=gap;
+				}
+			E32ImageHeader *pH=pF->iHdr;
+			if (pF->iDataBssOffset!=0xffffffff && pF->iDataBssOffset!=dataOffset)
+				Print(EError,"Conflicting DataBss addresses\n");
+			pF->iDataBssOffset=dataOffset;
+			TInt dataSize=AlignData(pH->iDataSize+pH->iBssSize);
+			const TText* pT=FileTypeFile;
+			if (pF->Primary())
+				pT=FileTypePrimary;
+			if (pF->Variant())
+				pT=FileTypeVariant;
+			if (pF->Extension())
+				pT=FileTypeExtension;
+			if (pF->Device())
+				pT=FileTypeDevice;
+			Print(ELog,"%s %12s[%08x] DataSize=%6x DataOffset=%6x",pT,pF->iName,pF->iHardwareVariant.ReturnVariant(),dataSize,dataOffset);
+			if (gap)
+				Print(ELog, " (gap %x for %x alignment)\n", gap, pF->iDataAlignment);
+			Print(ELog, "\n");
+			dataOffset+=dataSize;
+			}
+		if (dataOffset>totalDataBss)
+			totalDataBss=dataOffset;
+		}
+	Print(ELog,"\nTotal SvData size=%6x\n",totalDataBss);
+	iTotalSvDataSize=totalDataBss;
+	}
+
+TInt E32Rom::LoadDataToRom(TRomBuilderEntry *aFile, TAddressRange& aAddress, CBytePair* aBPE)
+//
+// Load a data file to rom
+//
+	{
+	const char* tn = "resource";
+	if (aFile->iNonXIP)
+		tn = (aFile->iCompression) ? "compressed executable" : "uncompressed executable";
+	Print(ELog,"Reading %s %s to rom linear address %08x\n", tn, aFile->iFileName, aAddress.iImageAddr);
+
+	TUint32 size=HFile::GetLength((TText*)aFile->iFileName);
+	if (size==0)
+		{
+		Print(EWarning, "File %s does not exist or is 0 bytes in length.\n",aFile->iFileName);
+		return size;
+		}
+
+	aFile->iHeaderRange=aAddress;
+	char* addr = (char*)aFile->iHeaderRange.iImagePtr;
+	const char* src = NULL;
+	#ifdef __TOOLS2__
+	ostringstream os;
+	#else
+	ostrstream os;
+	#endif
+	if (aFile->iNonXIP)
+		{
+		E32ImageFile f(aBPE);
+		TInt r = f.Open(aFile->iFileName);
+		// is it really a valid E32ImageFile?
+		if (r != KErrNone)
+			{
+			Print(EWarning, "File '%s' is not a valid executable.  Loading file as data.\n", aFile->iFileName);
+			aFile->iNonXIP = EFalse;
+			}
+		else
+			{
+			TUint compression = f.iHdr->CompressionType();
+			if (compression != aFile->iCompression || aFile->iPreferred)
+				{
+				if (compression == 0)
+					Print(ELog, "Compressing file %s\n", aFile->iFileName);
+				else if (aFile->iCompression == 0)
+					Print(ELog, "Decompressing file %s\n", aFile->iFileName);
+				f.iHdr->iCompressionType = aFile->iCompression;
+				if (aFile->iPreferred)
+					{
+					f.iHdr->iModuleVersion &= ~0xffffu;
+					f.iHdr->iModuleVersion |= 0x8000u;
+					}
+				f.UpdateHeaderCrc();
+				}
+			Print(ELog, "Compression Method:0x%08x/0x%08x \n", f.iHdr->CompressionType(), aFile->iCompression);
+			os << f;
+			#ifdef __TOOLS2__
+			size = (os.str()).length(); 
+			src = (os.str()).c_str();
+			#else
+			size = os.pcount();
+			src = os.str();
+			#endif
+			}
+		}
+	if (addr+size>iData+iSize)
+		{
+		Print(EError, "Can't fit '%s' in Rom.\n", aFile->iFileName);
+		Print(EError, "Rom overflowed by approximately 0x%x bytes.\n", RequiredSize()-iObey->iRomSize);
+		exit(667);
+		}
+	if (src)
+		memcpy(addr, src, size);
+	else
+		size = HFile::Read((TText*)aFile->iFileName, (TAny *)addr);
+	Print(ELog,"Size:                    %08x\n", size);
+
+	aFile->iHeaderRange.iSize=size;
+	aAddress.Extend(aFile->iHeaderRange.iSize);
+	return size;
+	}
+
+
+void E32Rom::CalculateDataAddresses()
+//
+//
+//
+	{
+
+	TInt i;
+	TUint32 maxkern = 0;
+	Print(ELog, "\nCalculating kernel limit.\n");
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		TRomBuilderEntry* e = iPeFiles[i];
+		if (e->Primary())
+			{
+			// this is a kernel
+			TUint32 stack = AlignToPage(e->iHdr->iStackSize);
+			TUint32 heap = AlignToPage(e->iHdr->iHeapSizeMax);
+			if (stack + heap > maxkern)
+				maxkern = stack + heap;
+			}
+		}
+	iObey->iKernelLimit = AlignToChunk(maxkern + iTotalSvDataSize) + iObey->iKernDataRunAddress;
+	if (iObey->iMemModel==E_MM_Direct)
+		iNextDataChunkBase=iObey->iDataRunAddress;
+	else
+		iNextDataChunkBase = iObey->iKernelLimit;
+	Print(ELog, "\nCalculating data addresses.\n");
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		TRACE(TAREA,Print(ELog,"CalculateDataAddresses %d %s\n",i,iPeFiles[i]->iFileName));
+		CalculateDataAddress(iPeFiles[i]);
+		}
+	TRACE(TIMPORT,Print(ELog,"CalculateDataAddresses complete\n"));
+
+	// On moving model, advance kernel limit past fixed process data areas
+	if (iObey->iMemModel==E_MM_Moving)
+		iObey->iKernelLimit = iNextDataChunkBase;
+	}
+
+void E32Rom::CalculateDataAddress(TRomBuilderEntry *aFile)
+//
+// Work out where the .data/.bss will be
+//
+	{
+	TUint32 dataBssSize=aFile->iRomNode->iRomFile->iTotalDataBss;
+	TUint32 dataRunAddr;
+	if (aFile->Primary())
+		{
+		dataRunAddr = iObey->iKernDataRunAddress;
+		CPU = aFile->iHdr->CpuIdentifier();
+		}
+	else
+		{
+		dataRunAddr = iObey->iDataRunAddress;
+		if (iObey->iMemModel!=E_MM_Multiple && iObey->iMemModel!=E_MM_Flexible && (aFile->iHdr->iFlags & KImageFixedAddressExe))	// propagate 'fixed' from PETRAN
+			{
+			dataRunAddr=0xffffffff;
+			}
+		}
+	if (aFile->iOverrideFlags&KOverrideAddress)
+		{
+		if ((iObey->iMemModel!=E_MM_Multiple && iObey->iMemModel!=E_MM_Flexible) || aFile->iRelocationAddress!=0xffffffff)
+			dataRunAddr=aFile->iRelocationAddress;
+		if (aFile->Extension() || aFile->Variant() || aFile->Device())
+			Print(EError, "reloc not permitted with extension/variant/device\n");
+		}
+	if (!aFile->IsDll() && !aFile->Primary() && (dataRunAddr==0xffffffff || iObey->iMemModel==E_MM_Direct))
+		{
+		dataRunAddr=iNextDataChunkBase;
+		TInt stackreserve=iObey->iDefaultStackReserve;
+		if (aFile->iOverrideFlags & KOverrideStackReserve)
+			stackreserve=aFile->iStackReserve;
+		TInt datsize=AlignToChunk(dataBssSize+stackreserve);
+		// Move target data address to next free chunk
+		iNextDataChunkBase+=datsize;
+		}
+	if (aFile->Extension() || aFile->Device() || aFile->Variant())
+		{
+		dataRunAddr=iObey->iKernDataRunAddress+aFile->iDataBssOffset;
+		}
+	else if (aFile->IsDll() && dataBssSize!=0 && aFile->iRomNode->iRomFile->iDataBssOffsetInExe<0)
+		{
+		iNextDllDataAddr = AllocVirtual(iNextDllDataAddr,dataBssSize);
+		dataRunAddr=iNextDllDataAddr;
+		}
+	if (iObey->iMemModel==E_MM_Moving && dataRunAddr==iObey->iDataRunAddress && aFile->Secondary())
+		{
+		Print(EWarning,"Secondary not fixed\n");
+		}
+
+	TRACE(TAREA, Print(ELog, "Data run address %08x\n", dataRunAddr));
+	aFile->iDataBssLinearBase=dataRunAddr;
+	}
+
+void E32Rom::LoadFileToRom(TRomBuilderEntry *aFile)
+//
+// Load an E32Image/PE file to rom
+//
+	{
+
+	char* addr = (char*)aFile->iHeaderRange.iImagePtr;
+	TRACE(TAREA, Print(ELog,"+LoadFileToRom addr %08x %08x %08x\n", addr,
+					   aFile->iHeaderRange.iImageAddr, aFile->iHeaderRange.iRunAddr));
+
+	if (addr+aFile->SizeInRom()>iData+iSize) // check this
+		{
+		Print(EError, "Can't fit '%s' in Rom.\n", aFile->iFileName);
+		Print(EError, "Rom overflowed by approximately 0x%x bytes.\n", RequiredSize()-iObey->iRomSize);
+		exit(666);
+		}
+
+	// check file will not overflow into next ROM
+	if (aFile->Primary())
+		{
+		if (!iPrevPrimaryAddress)
+			iHeader->iPrimaryFile=ActualToRomAddress(aFile->RomEntry());
+		else if (iObey->iKernelModel==EMultipleKernels)
+			{
+			((TRomImageHeader*)iPrevPrimaryAddress)->iNextExtension=ActualToRomAddress(aFile->RomEntry());
+			}
+		iPrevPrimaryAddress=addr;
+		TRACE(TAREA, Print(ELog, "iHeader->iPrimaryFile = %08x\n", iHeader->iPrimaryFile));
+		}
+
+	// Place the file in rom
+	if (aFile->Variant())
+		{
+		if (iPrevVariantAddress)
+			((TRomImageHeader*)iPrevVariantAddress)->iNextExtension=ActualToRomAddress(aFile->RomEntry());
+		else
+			iHeader->iVariantFile=ActualToRomAddress(aFile->RomEntry());
+		iPrevVariantAddress=addr;
+		}
+	if (aFile->IsDll() && aFile->iRomNode->iRomFile->iTotalDataBss!=0 && aFile->iRomNode->iRomFile->iDataBssOffsetInExe>=0)
+		{
+		TRomFile* f=aFile->iRomNode->iRomFile->iPDeps[0];	// attach process
+		aFile->iDataBssLinearBase = f->DataBssLinearBase() + aFile->iRomNode->iRomFile->iDataBssOffsetInExe;
+		}
+
+	aFile->LoadToRom();
+	}
+
+char *E32Rom::LayoutRom(char *romaddr)
+//
+// Layout the files from the obey file starting at romaddr in the image
+// dealing correctly with areas
+// Also deals with two section ROMs
+//
+	{
+
+	TAddressRange main;
+	TAddressRange* mainptr=&main;
+	SetImageAddr(main, romaddr);
+
+	TAddressRange second;
+	TAddressRange* secondptr=0;
+	if (iObey->iSectionStart != 0)
+		{
+		SetImageAddr(second,iSectionPtr);
+		secondptr = &second;
+		}
+
+	TInt fileCount=0;
+
+	//
+	// Process files in non default areas
+	//
+
+        CBytePair bpe(gFastCompress);
+	for (NonDefaultAreasIterator areaIt(iObey->SetArea());
+		 ! areaIt.IsDone();
+		 areaIt.GoToNext())
+		{
+		Area& currentArea = areaIt.Current();
+		currentArea.SetSrcBaseAddr(mainptr->iImageAddr);
+
+		mainptr->iRunAddr = currentArea.DestBaseAddr();
+
+		for (FilesInAreaIterator fileIt(currentArea);
+			 ! fileIt.IsDone();
+			 fileIt.GoToNext())
+			{
+			TRomBuilderEntry* currentFile = fileIt.Current();
+
+			LayoutFile(currentFile, *mainptr, secondptr, &bpe);
+		
+			TUint overflow;
+			if (! currentArea.ExtendSrcLimitAddr(mainptr->iImageAddr, overflow))
+				{
+				Print(EError, "Can't fit '%s' in area '%s'\n", currentFile->iFileName, currentArea.Name());
+				Print(EError, "Area overflowed by 0x%x bytes.\n", overflow);
+				exit(666);
+				}
+
+			++fileCount;
+			assert(iObey->iSectionPosition == -1 || fileCount < iObey->iSectionPosition);
+			}
+
+		TInt offset=(char*)mainptr->iImagePtr-romaddr;
+		mainptr->Extend(Align(offset)-offset);
+		} // for every non default area
+
+
+	//
+	// Process files in default area
+	//
+
+	mainptr->iRunAddr = mainptr->iImageAddr;
+
+	for (FilesInAreaIterator fileIt(*(iObey->SetArea().DefaultArea()));
+		 ! fileIt.IsDone();
+		 fileIt.GoToNext())
+		{
+		if (fileCount==iObey->iSectionPosition)
+			{
+			// skip rest of first section and pick up after the
+			// information already accumulated in the second section
+			NextRom(mainptr, secondptr);
+			mainptr = secondptr;
+			secondptr = 0;
+			}
+
+		LayoutFile(fileIt.Current(), *mainptr, secondptr, &bpe);
+
+		++fileCount;
+		}
+
+	// align to likely position of next file
+	TInt offset=(char*)mainptr->iImagePtr-romaddr;
+	offset = Align(offset)-offset;
+	mainptr->Extend(offset);
+	iOverhead +=offset;
+
+	return (char*)mainptr->iImagePtr;
+ 	}
+
+void E32Rom::LayoutFile(TRomBuilderEntry* current, TAddressRange& aMain, TAddressRange* aSecond, CBytePair * aBPE)
+//
+// Work out where to place a file in ROM and set up the 
+// appropriate TAddressRange information
+//
+	{
+	TInt alignment = iObey->iRomAlign;
+	if (current->iAlignment > alignment)
+		alignment = current->iAlignment;
+
+	if (alignment)
+		{
+		// Align this file on a boundary
+		TUint32 romaddr=aMain.iRunAddr;
+		TInt i=romaddr & (alignment-1);
+		TInt gap=0;
+		if (i!=0)
+			gap=alignment-i;
+		if (current->iAlignment)
+			Print(ELog, "\nAlign to %08x.  Skipped %d bytes\n", romaddr+gap, gap);
+		aMain.Extend(gap);
+		iOverhead += gap;
+		}
+
+	if (current->iCodeAlignment != 0)
+		{
+		TUint32 runaddr=aMain.iRunAddr + sizeof(TRomImageHeader);
+		TInt i=runaddr & (current->iCodeAlignment-1);
+		TInt gap=0;
+		if (i!=0)
+			gap=current->iCodeAlignment-i;
+		Print(ELog, "\nCode Align to %08x.  Skipped %d bytes\n", runaddr+gap, gap);
+		aMain.Extend(gap);
+		iOverhead += gap;
+		}
+
+	Print(ELog,"\n********************************************************************\n");
+
+	if (current->iPatched)
+		Print(ELog, "[Patched file]\n");
+
+	if (current->iResource)
+		{
+		TInt size=LoadDataToRom(current, aMain, aBPE);
+		if (aSecond != 0 && aMain.iImageAddr > iObey->iSectionStart)
+			return;		// first section has overflowed
+		current->FixupRomEntries(size);
+		return;
+		}
+	if(current->HCRDataFile()){	
+		TInt size=LoadDataToRom(current, aMain, aBPE);		
+		if (aSecond != 0 && aMain.iImageAddr > iObey->iSectionStart)
+			return;		// first section has overflowed
+		current->FixupRomEntries(size);
+		iHeader->iHcrFileAddress =  current->iHeaderRange.iImageAddr ;
+		TRACE(TAREA, Print(ELog, "iHeader->iHcrFileAddress = %08x\n", iHeader->iHcrFileAddress));		 
+		return ;
+	}
+	Print(ELog,"Processing file %s\n",current->iFileName);
+
+	if (current->Primary())
+		{
+		Print(ELog, "[Primary]\n");
+		}
+
+	if (current->Secondary())
+		{
+		iHeader->iSecondaryFile=ActualToRomAddress(current->RomEntry());
+		Print(ELog, "[Secondary]\n");
+		}
+
+	// Section 1 things
+	//
+	// TRomImageHeader, text, export directory, data
+
+	aMain.Append(current->iHeaderRange);
+	aMain.Append(current->iCodeSection);
+	aMain.Append(current->iDataSection);
+
+	// section 2 things
+	//
+	// dll ref table
+
+	if (aSecond != 0)
+		{
+		// two section ROM - split image between both sections
+		aSecond->Append(current->iExportDirSection);
+		aSecond->Append(current->iDllRefTableRange);
+		}
+	else
+		{
+		// default placement in first section
+		aMain.Append(current->iExportDirSection);
+		aMain.Append(current->iDllRefTableRange);
+		}
+
+	TInt section1size = aMain.iRunAddr-current->iCodeSection.iRunAddr;
+
+	if (aMain.iRunAddr == aMain.iImageAddr)
+		{
+		Print(ELog, "Load Address:            %08x\n", current->iHeaderRange.iImageAddr);
+		}
+	else
+		{
+		Print(ELog, "Rom Address:             %08x\n", current->iHeaderRange.iImageAddr);
+		Print(ELog, "Area Address:            %08x\n", current->iHeaderRange.iRunAddr);
+		}
+	Print(ELog,     "Size:                    %08x\n", section1size);
+
+	if (aSecond != 0 && aMain.iImageAddr > iObey->iSectionStart)
+		return;		// first section has overflowed
+
+	LoadFileToRom(current);
+	Display(current->iRomImageHeader);
+	Print(ELog,     "Dll ref table size:      %08x\n", current->iDllRefTableRange.iSize);
+	Print(ELog,     "Compression:             %08x\n", current->iCompression);
+	Print(ELog,     "\n");
+
+	current->FixupRomEntries(section1size);	
+	}
+
+static int CompareAddresses(const void * arg1, const void * arg2) 
+	{ 
+	return (* (TUint32 *)arg1) < (* (TUint32 *)arg2) ? -1: 1; 
+	}
+
+char *E32Rom::ReserveRomExceptionSearchTable(char *anAddr, TRomExceptionSearchTable*& exceptionSearchTable)
+	{
+	TRomExceptionSearchTable *pT = (TRomExceptionSearchTable *)anAddr;
+	exceptionSearchTable = pT;
+	if (iExtensionRomHeader)
+		{
+		iExtensionRomHeader->iRomExceptionSearchTable = ActualToRomAddress(anAddr);
+		}
+	else
+		{
+		iHeader->iRomExceptionSearchTable = ActualToRomAddress(anAddr);
+		}
+	TLinAddr * addr = &pT->iEntries[0];
+	int numEntries = 0;
+	int errors = 0;
+	// Count number of entries needed
+	for (int i = 0; i < iObey->iNumberOfPeFiles; i++)
+		{
+		TUint32 xd = iPeFiles[i]->iHdr->iExceptionDescriptor;
+		if ((xd & 1) && (xd != 0xffffffffu))
+			{
+			numEntries++;
+			}
+		else if (!iPeFiles[i]->iHdr->iExceptionDescriptor)
+			{
+#ifdef __REJECT_NON_EXCEPTION_AWARE_BINARIES__
+			Print(EError, "Executable not exception aware: %s\n", iPeFiles[i]->iName);
+			errors++;
+#else
+			Print(ELog, "Executable not exception aware: %s\n", iPeFiles[i]->iName);
+#endif
+			}
+		}
+	if (errors > 0) exit(666);
+	// NB we add one to numEntries to allow space for a fencepost value (see below for more)
+	int spaceNeeded = sizeof(pT->iNumEntries) + sizeof(pT->iEntries[0])*(numEntries+1);
+	int delta = (int)(addr+spaceNeeded) - (int)(iData+iSize);
+	// Check we've got enough room
+	if (delta > 0)
+		{
+		Print(EError, "Can't fit Rom Exception Search Table in Rom.\n");
+		Print(EError, "Rom overflowed by approximately 0x%x bytes.\n", delta);
+		exit(666);
+		}
+	pT->iNumEntries = numEntries;
+	return anAddr+spaceNeeded;
+	}
+	
+void E32Rom::ConstructRomExceptionSearchTable(TRomExceptionSearchTable* exceptionSearchTable)
+	{
+	TRomExceptionSearchTable *pT = exceptionSearchTable;
+	TLinAddr * addr = &pT->iEntries[0];
+	// Initialize the table
+	int numEntries = pT->iNumEntries;
+	TLinAddr fencepost = 0xffffffff;
+	if (numEntries)
+		{
+		TLinAddr fp = 0;
+		for (int j = 0; j < iObey->iNumberOfPeFiles; j++)
+			{
+			TUint32 xd = iPeFiles[j]->iHdr->iExceptionDescriptor;
+			if ((xd & 1) && (xd != 0xffffffff))
+				{
+				// mask out bottom bit set by ELFTRAN.
+				xd &= ~1;
+				*addr++ = iPeFiles[j]->iHdr->iCodeBase;
+				TLinAddr aEDAddr = iPeFiles[j]->iHdr->iCodeBase + xd; 
+				// Keep track of greatest code limit so we can use it as the fencepost value
+				TExceptionDescriptor * aEDp = (TExceptionDescriptor *)RomToActualAddress(aEDAddr);
+				TLinAddr codeLimit = aEDp->iROSegmentLimit;
+				if (codeLimit>fp) fp=codeLimit;
+				}
+			}
+		if (fp) fencepost=fp;
+		// now check they're in order (they should be).
+		int inOrder = 1;
+		for (int k=numEntries-1;inOrder && k; k--) 
+			{
+			inOrder = pT->iEntries[k]>pT->iEntries[k-1]?1:0;
+			}
+
+		if (!inOrder)
+			{
+			Print(ELog, "Sorting Rom Exception Table.\n");
+			qsort(&pT->iEntries[0],numEntries,sizeof(pT->iEntries[0]), CompareAddresses);
+			}
+		}
+	/*
+	  Add the fencepost value at the end of the table. This is used to optimize the comparison
+	  function passed to bsearch when retrieving values from the search table. It also allows a certain
+	  amount of error checking on lookup keys.
+	*/
+	*addr++ = fencepost;
+	}
+
+void TRomBuilderEntry::SizeInSections(TInt& aSize1, TInt& aSize2)
+//
+// Exact size of the upper & lower section information
+// lower = text + data
+// upper = export directory + dllref table
+//
+	{
+	aSize1  = iHeaderRange.iSize;
+	aSize1 += iCodeSection.iSize;			// text (including rdata)
+	aSize1 += iDataSection.iSize;			// static data
+
+	aSize2  = iExportDirSection.iSize;		// export directory
+	aSize2 += iDllRefTableRange.iSize;	// DLL ref table
+	}
+
+							
+void E32Rom::NextRom(TAddressRange* aFirst, TAddressRange* aSecond)
+//
+// Move on to the next Rom bank, taking the IATs with us
+//
+	{
+
+	Print(ELog,"\n####################################################################\n");
+	TInt gap=iObey->iSectionStart-aFirst->iImageAddr;
+	if (gap<0)
+		{
+		Print(EError, "First section overflowed by %08x bytes\n", -gap);
+		exit(669);
+		}
+	iOverhead+=gap+sizeof(TRomSectionHeader);
+	Print(ELog, "[Next rom section]\n");
+	Print(ELog, "Skipping %08x bytes\n", gap);
+	Print(ELog, "LinAddr:                 %08x\n", iObey->iSectionStart);
+	Print(ELog, "First section tables:    %08x\n", iObey->iSectionStart+sizeof(TRomSectionHeader));
+	TInt size=aSecond->iImageAddr-iObey->iSectionStart;
+	Print(ELog, "Tables size:             %08x\n", size-sizeof(TRomSectionHeader));
+	Print(ELog, "Rom Directory            %08x\n", iHeader->iRomRootDirectoryList);
+	Print(ELog, "Rom Directory size       %08x\n", iDirectorySize);
+
+	if (aSecond->iImageAddr != iHeader->iRomRootDirectoryList)
+		{
+		Print(EError, "Second section has overwritten the Rom directory\n");
+		exit(669);
+		}
+	aSecond->Extend(iDirectorySize);
+
+	Print(ELog, "\n");
+	}
+
+TInt E32Rom::ResolveDllRefTables()
+//
+//
+//
+	{
+
+	Print(ELog, "\nResolving Dll reference tables.\n");
+	TInt i;
+	TInt err = KErrNone;
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		TRACE(TIMPORT,Print(ELog,"ResolveDllRefTables %d\n",i));
+		TInt r=iPeFiles[i]->ResolveDllRefTable(*this);
+		if (r!=KErrNone)
+			err=r;
+		}
+	TRACE(TIMPORT,Print(ELog,"ResolveDllRefTables complete\n"));
+	return err;
+	}
+
+
+TInt E32Rom::BuildDependenceGraph()
+	{
+	Print(ELog, "\nBuilding dependence graph.\n");
+	TInt i;
+	TInt err = KErrNone;
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		TRACE(TIMPORT,Print(ELog,"BuildDep %d\n",i));
+		TRomBuilderEntry* e=iPeFiles[i];
+		TInt r=e->BuildDependenceGraph(*this);
+		if (r!=KErrNone)
+			err=r;
+		if (!e->IsDll())
+			{
+			if (e->iHdr->iDataSize!=0 || e->iHdr->iBssSize!=0)
+				e->iRomImageFlags|=(KRomImageFlagData|KRomImageFlagDataPresent);	// EXE with static data
+			}
+		else if ((e->iHdr->iDataSize!=0 || e->iHdr->iBssSize!=0) && !e->Variant() && !e->Extension())
+			{
+			// requires normal case DLL data initialisation
+			e->iRomImageFlags|=(KRomImageFlagData|KRomImageFlagDataInit|KRomImageFlagDataPresent);
+			}
+		}
+	TRACE(TIMPORT,Print(ELog,"BuildDep complete\n"));
+
+	if(!gPagedRom)
+		return err;
+
+	Print(ELog,"\n");
+
+	return err;
+	}
+
+#define MARK_BEEN_HERE	1
+#define MARK_KEEP		2
+#define	MARK_EXE		4
+#define MARK_CHECKED	8
+void E32Rom::UnmarkGraph(TInt aMark)
+	{
+	TRomNode* x = 0;
+	for (x=iObey->iRootDirectory->iNextExecutable; x; x=x->iNextExecutable)
+		x->iRomFile->iMark &= ~aMark;
+	}
+
+void E32Rom::FindMarked(TInt aMarkMask, TInt aMark, TRomFile**& aList)
+	{
+	UnmarkGraph(MARK_CHECKED);
+	TRomNode* x = 0;
+	aMarkMask |= MARK_CHECKED;
+	aMark &= ~MARK_CHECKED;
+	for (x=iObey->iRootDirectory->iNextExecutable; x; x=x->iNextExecutable)
+		{
+		TRomFile* e = x->iRomFile;
+		if ((e->iMark&aMarkMask)==aMark)
+			{
+			*aList++=e;
+			e->iMark |= MARK_CHECKED;
+			}
+		}
+	}
+
+TInt TRomFile::MarkDeps()
+	{
+	TInt n=0;
+	TInt i;
+	for (i=0; i<iNumDeps; ++i)
+		{
+		TRomFile* e=iDeps[i];
+		if (!(e->iMark & MARK_BEEN_HERE))
+			{
+			e->iMark|=MARK_BEEN_HERE;
+			++n;
+			n+=e->MarkDeps();
+			TUint32 flg = RomImageFlags();
+			TUint32 eflg = e->RomImageFlags();
+			if (eflg & KRomImageFlagDataPresent)
+				iRbEntry->iRomImageFlags |= KRomImageFlagDataPresent;
+			TBool e_is_dll = eflg & KImageDll;
+			if ((flg & KImageDll) && e_is_dll && (eflg & KRomImageFlagDataInit))
+				iRbEntry->iRomImageFlags |= KRomImageFlagDataInit;
+			if (!e_is_dll)
+				e->iMark|=MARK_EXE;
+			if (eflg&KRomImageFlagData)
+				e->iMark|=MARK_KEEP;
+			}
+		}
+	return n;
+	}
+
+TInt TRomFile::FindRouteTo(TRomFile* aDest, TRomFile** aStack, TInt aIndex)
+	{
+	TInt i;
+	for (i=0; i<iNumDeps; ++i)
+		{
+		TRomFile* e=iDeps[i];
+		if (e == aDest)
+			return aIndex;
+		if (!(e->iMark & MARK_BEEN_HERE))
+			{
+			e->iMark|=MARK_BEEN_HERE;
+			aStack[aIndex] = e;
+			TInt r = e->FindRouteTo(aDest, aStack, aIndex+1);
+			if (r >= 0)
+				return r;
+			}
+		}
+	return KErrNotFound;
+	}
+
+void E32Rom::ListRouteTo(TRomFile* aStart, TRomFile* aDest, TInt aNDeps)
+	{
+	TRomNode* rootdir = iObey->iRootDirectory;
+	TRomFile** stack = new TRomFile*[aNDeps];
+	UnmarkGraph();
+	TInt depth = aStart->FindRouteTo(aDest, stack, 0);
+	assert(depth >= 0);
+	Print(EAlways, "\t--->%s\n", (const char*)TModuleName(*aDest, rootdir));
+	while(--depth >= 0)
+		Print(EAlways, "\tvia %s\n", (const char*)TModuleName(*stack[depth], rootdir));
+	delete[] stack;
+	}
+
+TInt E32Rom::ProcessDependencies()
+	{
+	TInt i;
+	TInt errors = 0;
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		TRomBuilderEntry* e=iPeFiles[i];
+		TRomNode* rn = e->iRomNode;
+		TRomFile* rf = rn->iRomFile;
+		UnmarkGraph();
+		TInt n=rf->MarkDeps();
+		rf->iNumPDeps=n;
+		if (n)
+			{
+			rf->iPDeps=new TRomFile* [n];
+			if (!rf->iPDeps)
+				return KErrNoMemory;
+			TRomFile** l=rf->iPDeps;
+			FindMarked(MARK_EXE, MARK_EXE, l);
+			TInt nx=l-rf->iPDeps;
+			if (!e->IsDll() && (nx>1 || nx==1 && l[-1]!=rf))
+				{
+				Print(EError,"EXE %s links to the following other EXEs:\n", e->iFileName);
+				TInt j;
+				for (j=0; j<nx; ++j)
+					{
+					if (rf->iPDeps[j] != rf)
+						ListRouteTo(rf, rf->iPDeps[j], n);
+					}
+				++errors;
+				continue;
+				}
+			else if (nx>1)
+				{
+				Print(EError,"DLL %s links to more than one EXE:\n",e->iFileName);
+				TInt j;
+				for (j=0; j<nx; ++j)
+					ListRouteTo(rf, rf->iPDeps[j], n);
+				++errors;
+				continue;
+				}
+			if (nx)
+				e->iRomImageFlags|=KRomImageFlagExeInTree;
+			FindMarked(MARK_KEEP|MARK_EXE, MARK_KEEP, l);
+			rf->iNumPDeps=l-rf->iPDeps;
+			if (rf->iNumPDeps)
+				{
+				e->iDllRefTableRange.iSize=(rf->iNumPDeps-1)*sizeof(TRomImageHeader*)+sizeof(TDllRefTable);
+				if (e->IsDll() && rf->iTotalDataBss)
+					{
+					TRomFile* f=rf->iPDeps[0];	// first dependency, EXE if there is one
+					TUint fflg = f->RomImageFlags();
+					TBool f_is_dll = fflg & KImageDll;
+					if (!f_is_dll)
+						{
+						// DLL with data/bss depends on EXE
+						if ((fflg & KRomImageFlagFixedAddressExe) || iObey->iMemModel==E_MM_Direct)
+							{
+							// assign the DLL data address in the EXE bss section
+							rf->iDataBssOffsetInExe=f->iTotalDataBss;
+							f->iTotalDataBss+=rf->iTotalDataBss;
+							}
+						}
+					else if (iObey->iMemModel==E_MM_Direct)
+						{
+						Print(EError, "DLL with data/bss must have attach process specified\n");
+						return KErrGeneral;
+						}
+					}
+				}
+			else
+				{
+				delete[] rf->iPDeps;
+				rf->iPDeps=NULL;
+				}
+			}
+		if (!rf->iNumPDeps)
+			e->iDllRefTableRange.iSize=0;
+		}
+	if (iObey->iMemModel == E_MM_Moving)
+		{
+		// On moving model only, we must verify that no fixed process links to a
+		// DLL with data/bss which is attached to a fixed process.
+		// On multiple model there is no restriction.
+		// On direct model all DLLs with data/bss must specify an attach process
+		// and the error will show up as one EXE depending on another.
+		for (i=0; i<iObey->iNumberOfPeFiles; i++)
+			{
+			TRomBuilderEntry* e=iPeFiles[i];
+			TRomNode* rn = e->iRomNode;
+			TRomFile* rf = rn->iRomFile;
+			TUint rif = rf->RomImageFlags();
+			if (e->IsDll() || e->Primary() || !(rif & KRomImageFlagFixedAddressExe))
+				continue;	// only need to check fixed address user mode EXEs
+			TInt n = rf->iNumPDeps;
+			TInt j;
+			for (j=0; j<n; ++j)
+				{
+				TRomFile* f = rf->iPDeps[j];
+				TUint fflg = f->RomImageFlags();
+				if ((fflg & KImageDll) && (f->iDataBssOffsetInExe < 0))
+					{
+					// fixed user EXE links to DLL with data/bss and no attach process
+					Print(EError,"Fixed EXE %s links to DLL with data/bss and no attach process:\n", e->iFileName);
+					ListRouteTo(rf, rf->iPDeps[j], n);
+					++errors;
+					}
+				}
+			}
+		}
+	if (errors)
+		return KErrGeneral;
+
+	STRACE(TIMPORT, 
+		{
+		for (i=0; i<iObey->iNumberOfPeFiles; i++)
+			{
+			TRomBuilderEntry* e=iPeFiles[i];
+			TRomNode* rn = e->iRomNode;
+			TRomFile* rf = rn->iRomFile;
+			Print(ELog,"File %s: PN=%d\n",e->iFileName,rf->iNumPDeps);
+			TInt j;
+			for (j=0; j<rf->iNumPDeps; ++j)
+				{
+				TRomFile* f=rf->iPDeps[j];
+				Print(ELog,"\t%s\n", (const char*)TModuleName(*f, iObey->iRootDirectory));
+				}
+			}
+		})
+	return KErrNone;
+	}
+
+void E32Rom::SetSmpFlags()
+    {
+	if (gLogLevel & LOG_LEVEL_SMP_INFO)
+		{
+		Print(ELog,"\nComputing SMP properties. The following components are SMP-unsafe:\n");
+		}
+
+	bool is_all_safe = 1;
+
+	for (int i = 0; i < iObey->iNumberOfPeFiles; i++)
+		{
+		TRomBuilderEntry* e = iPeFiles[i];
+
+        if ( e->iRomNode->iRomFile->ComputeSmpSafe(e) )
+			{
+			e->iRomImageFlags |= KRomImageSMPSafe;
+			}
+		else
+			{
+			is_all_safe = 0;
+			e->iRomImageFlags &= ~KRomImageSMPSafe;
+			}
+		}
+
+	if ( (gLogLevel & LOG_LEVEL_SMP_INFO) && is_all_safe)
+		{
+		Print(ELog,"There are no unsafe components.");
+		}
+    }
+
+TInt E32Rom::ResolveImports()
+//
+// Fix the import address table for each of the files in rom
+//	
+	{
+
+	Print(ELog, "Resolving Imports.\n");
+	TInt i;
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		TInt r=iPeFiles[i]->FixupImports(*this);
+		if (r!=KErrNone)
+			return r;
+		}
+	return KErrNone;
+	}
+
+char *E32Rom::RomToActualAddress(TUint aPtr)
+	{
+	return (char *)(aPtr-iObey->iRomLinearBase+(TUint)iHeader);
+	}
+
+TUint E32Rom::ActualToRomAddress(TAny *aPtr)
+	{
+	return ((TUint)aPtr)-(TUint32)iHeader+iObey->iRomLinearBase;
+	}
+
+void E32Rom::SetImageAddr(TAddressRange& aRange, TAny* aPtr, TUint32 aRunOffset)
+	{
+	aRange.iImagePtr=aPtr;
+	aRange.iImageAddr=ActualToRomAddress(aPtr);
+	aRange.iRunAddr=aRange.iImageAddr+aRunOffset;
+	}
+
+void E32Rom::SetImageAddr(TAddressRange& aRange, TUint aAddr, TUint32 aRunOffset)
+	{
+	aRange.iImagePtr=RomToActualAddress(aAddr);
+	aRange.iImageAddr=aAddr;
+	aRange.iRunAddr=aAddr+aRunOffset;
+	}
+
+TRomNode* E32Rom::FindImageFileByName(const TDllFindInfo& aInfo, TBool aPrintDiag, TBool& aFallBack)
+//
+// return the file with the name aName
+//
+	{
+	return iObey->iRootDirectory->FindImageFileByName(aInfo, aPrintDiag, aFallBack);
+	}
+
+TInt E32Rom::CheckForVersionConflicts(const TRomBuilderEntry* a)
+	{
+	return iObey->iRootDirectory->CheckForVersionConflicts(a);
+	}
+
+TRomNode* E32Rom::CopyDirectory(TRomNode*& aLastExecutable)
+	{
+	return iObey->iRootDirectory->CopyDirectory(aLastExecutable, 0);
+	}
+
+TInt E32Rom::CollapseImportThunks()
+//
+// Collapse 3-word import thunks into a single branch
+//	
+	{
+
+	Print(ELog, "\nCollapsing Import Thunks.\n");
+	TInt i;
+	for (i=0; i<iObey->iNumberOfPeFiles; i++)
+		{
+		if (iPeFiles[i]->iHdr->iImportOffset)
+			{
+			TInt r=CollapseImportThunks(iPeFiles[i]);
+			if (r!=KErrNone)
+				return r;
+			}
+		}
+	return KErrNone;
+	}
+
+TInt E32Rom::WriteImages(TInt aHeaderType)
+	{
+	if (aHeaderType < 0)
+		aHeaderType = 1;
+	ofstream romFile((const char *)iObey->iRomFileName,ios::binary);
+	if (!romFile)
+		return Print(EError,"Cannot open ROM file %s for output\n",iObey->iRomFileName);
+	Write(romFile, aHeaderType);
+	romFile.close();
+
+	// Write out the odd/even 16-bits of the images
+
+	char sname[256];
+	if (iObey->iRomOddFileName)
+		{
+		strcpy(sname, (const char*)iObey->iRomOddFileName);
+		if (strcmp(sname, "*")==0)
+			{
+			// use romname with ".odd" appended.
+			sprintf(sname,"%s.odd",(const char *)iObey->iRomFileName);
+			}
+		ofstream oFile(sname,ios::binary);
+		if (!oFile)
+			return Print(EError,"Cannot open file %s for output\n",sname);
+		Print(EAlways, "Writing odd half words to file %s\n",sname);
+		WriteOdd(oFile);
+		oFile.close();
+		}
+	if (iObey->iRomEvenFileName)
+		{
+		strcpy(sname, (const char*)iObey->iRomEvenFileName);
+		if (strcmp(sname, "*")==0)
+			{
+			// use romname with ".even" appended.
+			sprintf(sname,"%s.even",(const char *)iObey->iRomFileName);
+			}
+		ofstream oFile(sname,ios::binary);
+		if (!oFile)
+			return Print(EError,"Cannot open file %s for output\n",sname);
+		Print(EAlways, "Writing even half words to file %s\n",sname);
+		WriteEven(oFile);
+		oFile.close();
+		}
+
+	// Write out the ROM in the SREC or S19 format
+
+	if (iObey->iSRecordFileName)
+		{
+		strcpy(sname, (const char*)iObey->iSRecordFileName);
+		if (strcmp(sname, "*")==0)
+			{
+			// use romname with ".srec" appended.
+			sprintf(sname,"%s.srec",(const char *)iObey->iRomFileName);
+			}
+		ofstream sFile(sname,ios::binary);
+		if (!romFile)
+			return Print(EError,"Cannot open file %s for output\n",sname);
+		Print(EAlways, "Writing S record format to file %s\n",sname);
+		WriteSRecord(sFile);
+		sFile.close();
+		}
+	return KErrNone;
+	}
+
+void E32Rom::WriteOdd(ofstream &os)
+	{
+	char *ptr=(char *)iHeader+2;
+	TInt i;
+	for (i=2; i<iObey->iRomSize; i+=4, ptr+=4)
+		os.write(ptr, 2);
+	}
+
+void E32Rom::WriteEven(ofstream &os)
+	{
+	char *ptr=(char *)iHeader;
+	TInt i;
+	for (i=0; i<iObey->iRomSize; i+=4, ptr+=4)
+		os.write(ptr, 2);
+	}
+
+void E32Rom::SetCompressionInfo(TUint aCompressionType, TUint aCompressedSize, TUint aUncompressedSize)
+	{
+
+	if (iExtensionRomHeader)
+		{
+		iExtensionRomHeader->iCompressionType=aCompressionType;
+		iExtensionRomHeader->iCompressedSize=aCompressedSize;
+		iExtensionRomHeader->iUncompressedSize=aUncompressedSize;
+		}
+	else
+		{
+		iHeader->iCompressionType=aCompressionType;
+		iHeader->iCompressedSize=aCompressedSize;
+		iHeader->iUncompressedSize=aUncompressedSize;
+		}
+	}
+
+void E32Rom::Write(ofstream &os, TInt aHeaderType)
+//
+// Output a rom image
+//
+	{
+
+	const char *compressed=gEnableCompress ? " compressed" : " uncompressed"; 
+
+	switch (aHeaderType)
+		{
+	case 0:
+		Print(EAlways, "\nWriting%s Rom image without",compressed);
+		break;
+	case 1:
+	default:
+		Print(EAlways, "\nWriting%sRom image with repro",compressed);
+		os.write(iData, sizeof(TRomLoaderHeader));
+		break;
+	case 2:
+		Print(EAlways, "\nWriting%s Rom image with PE-COFF",compressed);
+			{
+			unsigned char coffhead[0x58] = {0};  // zero all the elements
+
+			// fill in the constant bits
+			// this is supposed to be simple, remember
+			coffhead[1] = 0x0a;
+			coffhead[2] = 0x01;
+			coffhead[0x10] = 0x1c;
+			coffhead[0x12] = 0x0f;
+			coffhead[0x13] = 0xa1;
+			coffhead[0x14] = 0x0b;
+			coffhead[0x15] = 0x01;
+			coffhead[0x26] = 0x40;
+			coffhead[0x2a] = 0x40;
+			coffhead[0x30] = 0x2e;
+			coffhead[0x31] = 0x74;
+			coffhead[0x32] = 0x65;
+			coffhead[0x33] = 0x78;
+			coffhead[0x34] = 0x74;
+			coffhead[0x3a] = 0x40;
+			coffhead[0x3e] = 0x40;
+			coffhead[0x44] = 0x58;
+			coffhead[0x54] = 0x20;
+
+			// now fill in the text segment size
+			*(TUint32 *) (&coffhead[0x18]) = ALIGN4K(iSizeUsed);
+			*(TUint32 *) (&coffhead[0x40]) = ALIGN4K(iSizeUsed);
+
+			os.write(reinterpret_cast<char *>(coffhead), sizeof(coffhead));
+			}
+		break;
+		}
+	Print(EAlways, " header to file %s\n", iObey->iRomFileName);
+	
+	iHeader->iUnpagedCompressedSize   = 0;
+	iHeader->iUnpagedUncompressedSize = iHeader->iPageableRomStart;
+	iHeader->iCompressedUnpagedStart =  gBootstrapSize + gPageIndexTableSize;	// AttilaV calculate uncompressed un-paged size 
+	
+	if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+		{
+		Print(ELog, "iUnpagedCompressedSize  :0x%08x (%d)\n",     iHeader->iUnpagedCompressedSize);
+		Print(ELog, "iUnpagedUncompressedSize:0x%08x (%d)\n\n",   iHeader->iUnpagedUncompressedSize);
+		
+		Print(ELog, "iExtensionRomHeader     :%d\n",     iExtensionRomHeader);
+		Print(ELog, "iCompressionType        :0x%08x\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressionType : iHeader->iCompressionType ));	
+		Print(ELog, "iCompressedSize         :0x%08x (%d)\n",     (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize  : iHeader->iCompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize  : iHeader->iCompressedSize ));
+		Print(ELog, "iUncompressedSize       :0x%08x (%d)\n\n",   (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ));
+	
+		Print(ELog, "iPageableRomStart       :0x%08x (%d)\n",   iHeader->iPageableRomStart, iHeader->iPageableRomStart );
+		Print(ELog, "iPageableRomSize        :0x%08x (%d)\n",   iHeader->iPageableRomSize, iHeader->iPageableRomSize  );
+		Print(ELog, "iRomPageIndex           :0x%08x (%d)\n",   iHeader->iRomPageIndex, iHeader->iRomPageIndex );
+	
+		Print(ELog, "iSizeUsed               :0x%08x (%d)\n",   iSizeUsed, iSizeUsed );
+		Print(ELog, "Linear base address     :0x%08x\n",iHeader->iRomBase); 
+		Print(ELog, "Size:                    0x%08x\n",iHeader->iRomSize);
+		}
+
+	if ( gPagedRom && gCompressUnpaged)
+		{
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			Print(ELog, "Write out compressed un-paged and paged sections\n\n");
+		ImpTRomHeader* header = (ImpTRomHeader *)iHeader;
+		
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			{
+			Print(ELog, "Header:\n");
+			header->Display();
+			}
+		
+		streampos headerpos=os.tellp();
+		
+		// Write out uncompressed un-paged part (bootstrap + Page Index Table)
+		os.write((char *)(iHeader), iHeader->iCompressedUnpagedStart);
+		
+		// write out the compressed unpaged part
+		int srcsize=iHeader->iPageableRomStart - iHeader->iCompressedUnpagedStart;		
+		
+		int rawimagelen=DeflateCompressCheck(((char *)iHeader)+iHeader->iCompressedUnpagedStart,srcsize,os);
+		iHeader->iUnpagedCompressedSize = rawimagelen;
+		iHeader->iUnpagedUncompressedSize = srcsize ;
+		
+		// align to 4kbyte boundary if neccessary
+		TUint32 distanceFrom4kBoundary = ((~(iHeader->iCompressedUnpagedStart + rawimagelen /*+ sizeof(TRomLoaderHeader)*/ )) & 0xfff) + 1;
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			Print(ELog, "distanceFrom4kBoundary  :0x%08x (%d)\n", distanceFrom4kBoundary, distanceFrom4kBoundary);
+		char filer[0x1000];
+		memset( filer, 0, 0x1000);
+		os.write((char *)filer, distanceFrom4kBoundary);
+		
+		
+		// write out the paged part
+		os.write((char *)iHeader + iHeader->iPageableRomStart, ALIGN4K(iSizeUsed - iHeader->iPageableRomStart));
+		
+		// update size and compression information of paged-part
+		SetCompressionInfo(KUidCompressionDeflate, ALIGN4K(iSizeUsed), ALIGN4K(iUncompressedSize));
+		
+		// Calculate starting index of the Pageable Rom Start
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			{
+			Print(ELog, "iPageableRomStart				: %d (0x%08x)\n", iHeader->iPageableRomStart, iHeader->iPageableRomStart);
+			Print(ELog, "iCompressedUnpagedStart			: %d (0x%08x)\n", iHeader->iCompressedUnpagedStart, iHeader->iCompressedUnpagedStart);
+			Print(ELog, "rawimagelen						: %d (0x%08x)\n", rawimagelen, rawimagelen);
+			}
+		
+		TInt displacement = iHeader->iCompressedUnpagedStart + rawimagelen + distanceFrom4kBoundary; 
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			Print(ELog, "new iPageableRomStart			: %d (0x%08x)\n", (iHeader->iCompressedUnpagedStart + rawimagelen + distanceFrom4kBoundary), (iHeader->iCompressedUnpagedStart + rawimagelen + distanceFrom4kBoundary));
+		displacement = iHeader->iPageableRomStart-displacement;
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			Print(ELog, "displacement					: %d (0x%08x)\n", displacement, displacement);
+		
+		SRomPageInfo* pi = (SRomPageInfo*)((TInt)iHeader+iHeader->iRomPageIndex);
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			Print(ELog, "First Pageable page info[0x%08x]:(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi, pi->iDataStart, pi->iDataSize, pi->iDataSize);
+		
+		TInt startPageableIndex = (iHeader->iPageableRomStart) / (iObey->iPageSize);
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			{
+			Print(ELog, "iObey->iPageSize				: %d (0x%08x)\n", iObey->iPageSize, iObey->iPageSize);
+			Print(ELog, "startPageableIndex				: %d (0x%08x)\n", startPageableIndex, startPageableIndex);
+			}
+		pi += startPageableIndex;
+		
+		
+		while ( 0 != pi->iDataStart)
+			{
+				if (H.iVerbose) Print(ELog, "\t\tinfo[0x%08x]:(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi, pi->iDataStart, pi->iDataSize, pi->iDataSize);		
+				
+				pi->iDataStart -= displacement;
+				
+				if (H.iVerbose) Print(ELog, "\t\tinfo[0x%08x]:(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi, pi->iDataStart, pi->iDataSize, pi->iDataSize);		
+				
+				++pi;
+			}
+		
+		
+		
+		// Rewrite the header with updated info
+		#ifdef __TOOLS2__
+		os.seekp(headerpos); 
+		#else
+		os.seekp(headerpos,ios::beg);
+		#endif
+		
+		// Rewrite uncompressed un-paged part (bootstrap + Page Index Table)
+		os.write((char *)(iHeader), iHeader->iCompressedUnpagedStart);
+		
+		
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			{
+			Print(ELog, "iUnpagedCompressedSize  :0x%08x (%d)\n",     iHeader->iUnpagedCompressedSize, iHeader->iUnpagedCompressedSize);
+			Print(ELog, "iUnpagedUncompressedSize:0x%08x (%d)\n\n",   iHeader->iUnpagedUncompressedSize, iHeader->iUnpagedUncompressedSize);
+		
+			Print(ELog, "iCompressionType        :0x%08x\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressionType : iHeader->iCompressionType ));	
+			Print(ELog, "iCompressedSize         :0x%08x (%d)\n",     (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize  : iHeader->iCompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize  : iHeader->iCompressedSize ));
+			Print(ELog, "iUncompressedSize       :0x%08x (%d)\n\n",   (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ));
+		
+			Print(ELog, "iPageableRomStart       :0x%08x (%d)\n",   iHeader->iPageableRomStart, iHeader->iPageableRomStart );
+			Print(ELog, "iPageableRomSize        :0x%08x (%d)\n",   iHeader->iPageableRomSize, iHeader->iPageableRomSize  );
+			Print(ELog, "iRomPageIndex           :0x%08x (%d)\n",   iHeader->iRomPageIndex, iHeader->iRomPageIndex );
+			Print(ELog, "\t\tinfo(iDataStart:0x%08x, iDataSize:0x%08x (%d))\n\n", pi->iDataStart, pi->iDataSize, pi->iDataSize);
+		
+			Print(ELog, "Linear base address:     %08x\n",iHeader->iRomBase); 
+			Print(ELog, "Size:                    %08x\n",iHeader->iRomSize);
+			}
+		
+		return;
+		}
+
+	if (!gEnableCompress || gPagedRom || !gCompressUnpaged)
+		{
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			Print(ELog, "Writeout uncompressed un-paged and paged sections2\n");
+		SetCompressionInfo(KFormatNotCompressed, ALIGN4K(iSizeUsed), ALIGN4K(iUncompressedSize));
+		iHeader->iUnpagedCompressedSize = ALIGN4K(iSizeUsed);
+		iHeader->iUnpagedUncompressedSize = ALIGN4K(iUncompressedSize);
+		
+		os.write((char *)iHeader, ALIGN4K(iSizeUsed));
+		
+		if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+			{
+			Print(ELog, "iUnpagedCompressedSize  :0x%08x (%d)\n",     iHeader->iUnpagedCompressedSize);
+			Print(ELog, "iUnpagedUncompressedSize:0x%08x (%d)\n\n",   iHeader->iUnpagedUncompressedSize);
+		
+			Print(ELog, "iCompressionType        :0x%08x\n", (iExtensionRomHeader ? iExtensionRomHeader->iCompressionType : iHeader->iCompressionType ));	
+			Print(ELog, "iCompressedSize         :0x%08x (%d)\n",     (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize  : iHeader->iCompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iCompressedSize  : iHeader->iCompressedSize ));
+			Print(ELog, "iUncompressedSize       :0x%08x (%d)\n\n",   (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ), (iExtensionRomHeader ? iExtensionRomHeader->iUncompressedSize: iHeader->iUncompressedSize ));
+		
+			Print(ELog, "iPageableRomStart       :0x%08x (%d)\n",   iHeader->iPageableRomStart, iHeader->iPageableRomStart );
+			Print(ELog, "iPageableRomSize        :0x%08x (%d)\n",   iHeader->iPageableRomSize, iHeader->iPageableRomSize  );
+			Print(ELog, "iRomPageIndex           :0x%08x (%d)\n",   iHeader->iRomPageIndex, iHeader->iRomPageIndex );
+			}
+		
+		return;
+		}
+
+	// compressed image without paging section
+	streampos headerpos=os.tellp();
+	int headersize=iExtensionRomHeader ? sizeof(TExtensionRomHeader) : sizeof(TRomHeader);
+
+	os.write(reinterpret_cast<char*>(iHeader), headersize); // write a dummy header
+	// compress the rest of the image
+	int srcsize=iSizeUsed - headersize;
+	int rawimagelen=DeflateCompressCheck(((char *)iHeader)+headersize,srcsize,os);
+	// write the compression info into the header
+	SetCompressionInfo(KUidCompressionDeflate, rawimagelen, iUncompressedSize); // doesn't need to be 4K aligned
+	iHeader->iCompressedUnpagedStart = headersize; 
+	iHeader->iUnpagedCompressedSize = rawimagelen;
+	iHeader->iUnpagedUncompressedSize = srcsize;
+		
+	#ifdef __TOOLS2__
+	os.seekp(headerpos); 
+	#else
+	os.seekp(headerpos,ios::beg);
+	#endif
+	os.write(reinterpret_cast<char*>(iHeader), headersize);	// write header again with (compressed) size info
+	
+	if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
+		Print(ELog, "\tiSizeUsed:%d, iUncompressedSize:%d, headersize:%d, srcsize:%d, rawimagelen:%d \n",iSizeUsed, iUncompressedSize, headersize, srcsize, rawimagelen);
+	}
+
+TInt E32Rom::Compare(char *anImage, TInt aHeaderType)
+	{
+	if (aHeaderType < 0)
+		aHeaderType = 1;
+	ifstream file(anImage, ios::binary);
+	if (!file)
+		return Print(EError, "Cannot open Rom image '%s' for verification\n", anImage);
+	Print(ELog, "\nVerifying ROM against image in %s\n", anImage);
+	switch (aHeaderType)
+		{
+	case 0:
+		break;
+	case 1:
+	default:
+		Print(ELog, "Skipping repro header\n");
+		file.seekg(sizeof(TRomLoaderHeader));
+		break;
+	case 2:
+		Print(ELog, "Skipping coff header\n");
+		file.seekg(0x58);
+		break;
+		}
+	TInt length=ALIGN4K(iSizeUsed);
+	if (iObey->iSectionStart != 0)
+		{
+		length = iObey->iSectionStart-iObey->iRomLinearBase;
+		Print(ELog, "Verifying first section (%08x bytes)... ", length);
+		}
+
+	TRomHeader compareHeader;
+	file.read((char *)&compareHeader, sizeof(TRomHeader));
+	// Arrange different settings for TRomHeader and
+	// TRomSectionHeader in the obey file
+	// For now just copy across the things that'll change
+	compareHeader.iVersion=iHeader->iVersion;
+	compareHeader.iTime=iHeader->iTime;
+	compareHeader.iTimeHi=(TUint32)(iHeader->iTime >> 32);
+	compareHeader.iCheckSum=iHeader->iCheckSum;
+	compareHeader.iLanguage=iHeader->iLanguage;
+
+	if (memcmp(&compareHeader, iHeader, sizeof(TRomHeader))!=0)
+		return Print(EError, "Verify failed.\nRom headers are different\n");
+
+	// Now compare the rest of the image (or first section)
+
+	TUint *ptr=(TUint *)(iHeader+1);
+	TInt i;
+	for (i=sizeof(TRomHeader); i<length; i+=4)
+		{
+		TUint a;
+		file.read((char *)&a, sizeof(TUint));
+		if (file.eof())
+			return Print(EError, "Verify failed.\nDifferent Rom sizes\n");
+		if (a!=*ptr)
+			return Print(EError, "Verify failed.\nContents differ at Rom address %08x\n", i+iObey->iRomLinearBase);
+		ptr++;
+		}
+	file.close();
+	Print(EAlways, "Verify OK\n");
+	return KErrNone;
+	}
+
+
+char* E32Rom::AllocateRelocationTable(char* aAddr, TReloc*& aRelocTable)
+	{
+	if(iObey->SetArea().Count() > 1)
+		{
+		aRelocTable = reinterpret_cast<TReloc*>(aAddr);
+
+		// Allocate one entry per non default area + 1 sentinel
+		// (Count() returns number of non default areas + 1 (the
+		// default area))
+		TInt size = iObey->SetArea().Count() * sizeof(TReloc);	
+		aAddr += Align(size);
+		}
+	else
+		{
+		aRelocTable = 0;
+		}
+
+	return aAddr;
+	}
+
+
+void E32Rom::FillInRelocationTable(TReloc* aRelocTable)
+	{
+	TReloc* p = aRelocTable;
+	TInt wastedBytes = 0;
+
+	for (NonDefaultAreasIterator areaIt(iObey->SetArea());
+		 ! areaIt.IsDone();
+		 areaIt.GoToNext())
+		{
+		Area& currentArea = areaIt.Current();
+
+		if (currentArea.UsedSize() > 0)
+			{
+			p->iLength = currentArea.UsedSize();
+			p->iSrc = currentArea.SrcBaseAddr();
+			p->iDest = currentArea.DestBaseAddr();
+			++p;
+			}
+		else
+			{
+			wastedBytes += sizeof(TReloc);
+			}
+		}
+
+	if (aRelocTable != 0)
+		{
+		// Last entry acts as a sentinel
+		memset(p, 0, sizeof(*p));
+		}
+
+	if (wastedBytes > 0)
+		{
+ 		Print(EWarning, "Some areas are declared but not used\n");
+ 		Print(EWarning, "%d bytes wasted in relocation table\n", wastedBytes);
+		}
+	}
+
+
+/**
+ Link together the kernel extensions.
+
+ Must be called only after space has been allocated in the ROM image
+ for the kernel extension.
+ */
+
+void E32Rom::LinkKernelExtensions(TRomBuilderEntry* aExtArray[], TInt aExtCount)
+	{
+	/**
+	 * The kernel extensions should never be linked together as part of extension ROMs.
+	 */
+	if (!iExtensionRomHeader)
+		{
+		TLinAddr* pLastNextExtAddr = &(iHeader->iExtensionFile);
+
+		for (TInt i=0; i<aExtCount; ++i)
+			{
+			TRomBuilderEntry* curExt = aExtArray[i];
+			*pLastNextExtAddr = ActualToRomAddress(curExt->RomEntry());
+			pLastNextExtAddr = &(curExt->iRomImageHeader->iNextExtension);
+			}
+	
+		*pLastNextExtAddr = 0;
+		}
+	}
+
+void E32Rom::ProcessDllData()
+	{
+		DllDataEntry *entry = iObey->GetFirstDllDataEntry();
+		TRomBuilderEntry	*romEntry;
+		TLinAddr* aExportTbl;
+		void	*aLocation;
+		TUint	aDataAddr;
+		while(entry){
+			// A Dll data may be patched either via the ordinal number (as in ABIv2), or via
+			// the address of the data field (as in ABIv1).
+			romEntry = entry->iRomNode->iRomFile->iRbEntry;
+			if((TInt)entry->iOrdinal != -1) { 
+				
+				// const data symbol may belong in the Code section. Get the address of the data field via the 
+				// export table. If the address lies within the Code or data section limits, 
+				// get the corresponding location and update it.While considering the Data section limits don't 
+				// include the Bss section, as it doesn't exist as yet in the image.
+				if(entry->iOrdinal < 1 || entry->iOrdinal > (TUint32)romEntry->iOrigHdr->iExportDirCount)
+				{
+					Print(EWarning, "Invalid ordinal %d specified for DLL %s\n", entry->iOrdinal, romEntry->iName);
+					entry = entry->NextDllDataEntry();
+					continue;
+				}
+				aExportTbl = (TLinAddr*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iExportDirOffset);
+				aDataAddr = (TInt32)(aExportTbl[entry->iOrdinal - 1] + entry->iOffset);
+				
+				if( (aDataAddr >= romEntry->iOrigHdr->iCodeBase) && 
+					(aDataAddr <= (TUint)(romEntry->iOrigHdr->iCodeBase + \
+										romEntry->iOrigHdr->iCodeSize)) )
+				{
+					char *aCodeSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iCodeOffset);
+					aLocation = (void*)(aCodeSeg + (aDataAddr - romEntry->iOrigHdr->iCodeBase));
+					memcpy(aLocation, &(entry->iNewValue), entry->iSize);
+				}
+				else if( (aDataAddr >= romEntry->iOrigHdr->iDataBase) && 
+					(aDataAddr <= (TUint)(romEntry->iOrigHdr->iDataBase + \
+										romEntry->iOrigHdr->iDataSize )) )
+				{
+					char *aDataSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iDataOffset);
+					aLocation = (void*)(aDataSeg + (aDataAddr - romEntry->iOrigHdr->iDataBase));
+					memcpy(aLocation, &(entry->iNewValue), entry->iSize);
+				}
+				else
+				{
+					Print(EWarning, "Patchdata failed as address pointed by ordinal %d of DLL %s doesn't lie within Code or Data section limits\n", entry->iOrdinal, romEntry->iName);
+				}
+				
+			}
+			else if((TInt)entry->iDataAddress != -1) { 
+				// const data symbol may belong in the Code section. If the address lies within the Code
+				// or data section limits, get the corresponding location and update it.While considering 
+				// the Data section limits don't include the Bss section, as it doesn't exist as yet in the image.
+				aDataAddr = (TUint)(entry->iDataAddress + entry->iOffset);
+				if( (aDataAddr >= romEntry->iOrigHdr->iCodeBase) && 
+					(aDataAddr <= (TUint)(romEntry->iOrigHdr->iCodeBase + \
+											romEntry->iOrigHdr->iCodeSize )) )
+				{
+					char *aCodeSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iCodeOffset);
+					aLocation = (void*)(aCodeSeg + (aDataAddr - romEntry->iOrigHdr->iCodeBase));
+					memcpy(aLocation, &(entry->iNewValue), entry->iSize);
+				}
+				else if( (aDataAddr   >= romEntry->iOrigHdr->iDataBase) && 
+					(aDataAddr <= (TUint)(romEntry->iOrigHdr->iDataBase + \
+											romEntry->iOrigHdr->iDataSize )) )
+				{
+					char *aDataSeg = (char*)((char*)romEntry->iOrigHdr + romEntry->iOrigHdr->iDataOffset);
+					aLocation = (void*)(aDataSeg + (aDataAddr - romEntry->iOrigHdr->iDataBase));
+					memcpy(aLocation, &(entry->iNewValue), entry->iSize);
+				}
+				else
+				{
+					Print(EWarning, "Patchdata failed as address 0x%x specified for DLL %s doesn't lie within Code or Data section limits\n", entry->iOrdinal, romEntry->iName);
+				}
+			}
+			else {
+			}
+			entry = entry->NextDllDataEntry();
+		}
+	}
+
+TInt E32Rom::CheckUnpagedMemSize()
+	{
+
+	if (H.iVerbose && gPagedRom)
+		{
+		Print(EDiagnostic, "iMaxUnpagedMemSize 0x%08x (%d)\n", iObey->iMaxUnpagedMemSize, iObey->iMaxUnpagedMemSize);
+		}
+		
+	// Only check if the iMaxUnpagedMemSize is set
+	if (iObey->iMaxUnpagedMemSize <= 0) return KErrNone;
+	
+	// Only for paged rom
+	if (!gPagedRom) 
+		{
+		Print(EWarning, "The unpaged size overflow check is skipped.\n");
+		return KErrNone;
+		}
+	
+	if (iHeader->iPageableRomStart > 0)
+		{
+		if (iHeader->iPageableRomStart > iObey->iMaxUnpagedMemSize) 
+			{
+			Print(EError, "Unpaged memory size overflow: require 0x%08x (%d) bytes while the maximum size is 0x%08x (%d) bytes\n",
+				iHeader->iPageableRomStart, 
+				iHeader->iPageableRomStart, 
+				iObey->iMaxUnpagedMemSize, 
+				iObey->iMaxUnpagedMemSize);
+			
+			return KErrNoMemory;
+			}
+		}
+	else
+		{
+		Print(EWarning, "The size of unpaged memory is not available. The unpaged memory overflow checking is skipped.\n");
+		}
+		
+	return KErrNone;
+	}
+
+TRomNode* E32Rom::RootDirectory() 
+{ 
+	return iObey->iRootDirectory; 
+}
+
+TText* E32Rom::RomFileName()
+{ 
+	return iObey->iRomFileName; 
+}
+
+TUint32 E32Rom::RomBase()
+{
+	return iHeader->iRomBase;
+}
+
+TUint32 E32Rom::RomSize()
+{
+	return iHeader->iRomSize;
+}
+
+TVersion E32Rom::Version()
+{
+	return iHeader->iVersion;
+}
+
+TInt64 E32Rom::Time()
+{
+	return iHeader->iTime;
+}
+
+TUint32 E32Rom::CheckSum()
+{
+	return iHeader->iCheckSum;
+}
+
+TUint32 E32Rom::DataRunAddress()
+{
+	return iObey->iDataRunAddress;
+}
+
+TUint32 E32Rom::RomAlign()
+{
+	return iObey->iRomAlign;
+}