userlibandfileserver/fileserver/sfile/sf_lepoc.cpp
branchRCL_3
changeset 21 e7d2d738d3c2
parent 0 a41df078684a
child 39 2bb754abd467
--- a/userlibandfileserver/fileserver/sfile/sf_lepoc.cpp	Fri Mar 12 15:50:11 2010 +0200
+++ b/userlibandfileserver/fileserver/sfile/sf_lepoc.cpp	Mon Mar 15 12:45:50 2010 +0200
@@ -202,14 +202,33 @@
 #ifdef _DEBUG
 	__IF_DEBUG(Printf("processed reloc table (size=%d,pageCount=%d)", iCodeRelocTableSize, pageCount));
 
-	// dump the import fixup table if loader tracing enabled
-	const TUint16* table16 = (const TUint16*)table;
-	const TInt halfWordsInTable = iCodeRelocTableSize / 2;
-	for(i = 0; i < halfWordsInTable; i += 4)
+	// Dump the processed reloc table if loader tracing enabled. The dump is in
+	// two parts; first, the page indexes (1 word per page), then the entries
+	// describing the items to be relocated on each of these pages, formatted
+	// with up to 8 entries per line but starting a new line for each page.
+	// Each of these entries has the relocation type in the first nibble, and
+	// the offset within the page in the remaining 3 nibbles.
+	const TUint32* table32 = (const TUint32*)table;
+	for (i = 0; i <= pageCount; ++i)
+		__IF_DEBUG(Printf("%04x: %08x", i*4, table32[i]));
+
+	for (i = 0; i < pageCount; ++i)
 		{
-		__IF_DEBUG(Printf(
-			"reloc %04x: %04x %04x %04x %04x",
-			i * 2, table16[i+0], table16[i+1], table16[i+2], table16[i+3]));
+		TUint start = table32[i];
+		TInt nbytes = table32[i+1] - start;
+		while (nbytes)
+			{
+			TBuf8<0x100> buf;
+			buf.Format(_L8("%04x:"), start);
+
+			const TUint16* p = (const TUint16*)(table+start);
+			TInt n = nbytes <= 16 ? nbytes : 16;
+			for (nbytes -= n, start += n; n > 0; n -= 2)
+				buf.AppendFormat(_L8(" %04x"), *p++);
+
+			buf.AppendFormat(_L8("\r\n"));
+			__IF_DEBUG(RawPrint(buf));
+			}
 		}
 #endif
 	return KErrNone;
@@ -268,6 +287,18 @@
 		}
 	}
 
+// A version that will work in user or supervisor mode
+void MyPrintf(const char* aFmt, ...)
+	{
+	VA_LIST list;
+	VA_START(list, aFmt);
+	TPtrC8 fmt((const TText8*)aFmt);
+	TBuf8<0x100> buf;
+	buf.AppendFormatList(fmt, list);
+	buf.AppendFormat(_L8("\r\n"));
+	RDebug::RawPrint(buf);
+	VA_END(list);
+	}
 
 /**
 Arguments for svRelocateSection.
@@ -340,29 +371,80 @@
 
 /**
 Fix up the export directory
-Only performed on PE images.  ELF image's exports are marked
-as relocatable and therefore relocated by svRelocateSection when the 
-text section is relocated up
+Only performed on PE images.  ELF image's exports are marked as relocatable
+and therefore relocated by svRelocateSection along with the text section
 */
 TInt svRelocateExports(TAny* aPtr)
 	{
-	E32Image* pI=(E32Image*)aPtr;
-	TUint32* destExport=(TUint32*)pI->iExportDirLoad;
-	TInt i=pI->iExportDirCount;
-	TUint32 codeBase=pI->iCodeRunAddress;
-	while (i-->0)
-		*destExport+++=codeBase;
+	E32Image& exporter = *(E32Image*)aPtr;
+
+	// Dump everything potentially useful that we know about the exporter ...
+	__LDRTRACE(MyPrintf("RelocateExports: paged? %d, iRomImageHeader@%08x, iHeader@%08x",
+						exporter.iUseCodePaging, exporter.iRomImageHeader, exporter.iHeader));
+	__LDRTRACE(MyPrintf("  iCodeLoadAddress %08x, iCodeRunAddress %08x, iCodeSize %x iTextSize %x",
+						exporter.iCodeLoadAddress, exporter.iCodeRunAddress,
+						exporter.iCodeSize, exporter.iTextSize))
+	__LDRTRACE(MyPrintf("  iDataLoadAddress %08x, iDataRunAddress %08x, iDataSize %x iBssSize %x iTotalDataSize %x",
+						exporter.iDataLoadAddress, exporter.iDataRunAddress,
+						exporter.iDataSize, exporter.iBssSize, exporter.iTotalDataSize));
+	__LDRTRACE(MyPrintf("  iCodeDelta, %x iDataDelta %x, iExportDirEntryDelta %x",
+						exporter.iCodeDelta, exporter.iDataDelta, exporter.iExportDirEntryDelta));
+
+	// It turns out that very little of the exporter info is useful! For
+	// example, the required code and data deltas are NOT those provided
+	// by the exporter, nor are the load addresses relevant ... :(
+	//
+	// In the case of a PE-derived image, the entries in the export table
+	// are expressed in terms of offsets into the image file, rather than
+	// locations in memory. Each therefore needs to be relocated by the
+	// difference between its file offset and its run address.
+	//
+	// It is assumed that the code segment appears before the data segment
+	// in the file; therefore, export table entries with values between 0
+	// and (exporter.iCodeSize) refer to the text segment, while higher
+	// values represent references to data addresses. Since the run addresses
+	// of code and data segments may be different, each type of export must
+	// be relocated with respect to the correct section.
+	//
+	// The following express the start and finish of each section in terms of
+	// file offsets and then derive the required adjustments to the entries
+	// in the export table ...
+	TUint32 codeStart = 0;							// compiler whinges if this is 'const' :(
+	const TUint32 codeFinish = codeStart + exporter.iCodeSize;
+	const TUint32 dataStart = codeFinish;
+	const TUint32 dataFinish = dataStart + exporter.iTotalDataSize;
+	const TUint32 codeDelta = exporter.iCodeRunAddress - codeStart;
+	const TUint32 dataDelta = exporter.iDataRunAddress - dataStart;
+
+	TUint32* destExport = (TUint32*)exporter.iExportDirLoad;
+	for (TInt i = exporter.iExportDirCount; --i >= 0; )
+		{
+		TUint32 relocAddr = *destExport;
+		TUint32 newValue;
+		if (relocAddr >= codeStart && relocAddr < codeFinish)
+			newValue = relocAddr + codeDelta;		// points to text/rdata section
+		else if (relocAddr >= dataStart && relocAddr < dataFinish)
+			newValue = relocAddr + dataDelta;		// points to data/bss section
+		else
+			newValue = relocAddr;					// unknown - just leave it alone
+		*destExport++ = newValue;
+
+		__LDRTRACE(MyPrintf("RelocateExports: export %d %08x => %08x %c",
+							exporter.iExportDirCount-i, relocAddr, newValue,
+							(relocAddr >= codeStart && relocAddr < codeFinish) ? 'C' :
+							(relocAddr >= dataStart && relocAddr < dataFinish) ? 'D' : 'X'));
+		}
+
 	return 0;
 	}
 
 
 struct SFixupImportAddressesInfo
 	{
-	TUint32* iIat;
-	TUint32* iExportDir;
-	TUint32 iExportDirEntryDelta;
-	TInt iNumImports;
-	E32Image* iExporter;
+	TUint32* iIat;					// Next part of IAT to be fixed up
+	E32Image* iExporter;			// Module from which we're importing
+	TInt iNumImports;				// Number of imports from this exporter
+
 	/**
 	For demand paging, this points to the buffer which is populated
 	so each page can be fixed up as it is loaded in.
@@ -378,52 +460,104 @@
 Fix up the import address table, used for 'PE derived' executables.
 @param aPtr Pointer to function arguments (SFixupImportAddressesInfo structure).
 			SFixupImportAddressesInfo::iIat is updated by this function.
+
+For a given importer, this function will be called once for each image from which
+objects are imported, and each time it will update the relevant portion of the
+importer's IAT, until all imports from all exporters have been processed.
 */
 TInt svFixupImportAddresses(TAny* aPtr)
 	{
 	SFixupImportAddressesInfo& info = *(SFixupImportAddressesInfo*)aPtr;
-
-	TUint32 maxOrdinal = (TUint32)info.iExporter->iExportDirCount;
-	TUint32 absentOrdinal = (TUint32)info.iExporter->iFileEntryPoint;
-
-	TUint32* exp_dir = info.iExportDir - KOrdinalBase; // address of 0th ordinal
-	TUint32 exp_delta = info.iExportDirEntryDelta;
+	E32Image& exporter = *info.iExporter;
+
+#ifdef _DEBUG
+	__LDRTRACE(MyPrintf(">svFixupImportAddresses %d imports, code@%08x, fixup@%08x exporter@%08x",
+						info.iNumImports, info.iCodeLoadAddress, info.iFixup64, info.iExporter));
+
+	// Dump everything potentially useful that we know about the exporter ...
+	__LDRTRACE(MyPrintf("%S: paged? %d, iRomImageHeader@%08x, iHeader@%08x",
+						&exporter.iFileName, exporter.iUseCodePaging,
+						exporter.iRomImageHeader, exporter.iHeader));
+	__LDRTRACE(MyPrintf("iCodeLoadAddress %08x, iCodeRunAddress %08x, iCodeSize %x iTextSize %x",
+						exporter.iCodeLoadAddress, exporter.iCodeRunAddress,
+						exporter.iCodeSize, exporter.iTextSize))
+	__LDRTRACE(MyPrintf("iDataLoadAddress %08x, iDataRunAddress %08x, iDataSize %x iBssSize %x iTotalDataSize %x",
+						exporter.iDataLoadAddress, exporter.iDataRunAddress,
+						exporter.iDataSize, exporter.iBssSize, exporter.iTotalDataSize));
+	__LDRTRACE(MyPrintf("iCodeDelta, %x iDataDelta %x, iExportDirEntryDelta %x",
+						exporter.iCodeDelta, exporter.iDataDelta, exporter.iExportDirEntryDelta));
+
+	if (exporter.iRomImageHeader)
+		{
+		const TRomImageHeader& rh = *exporter.iRomImageHeader;
+		__LDRTRACE(MyPrintf("ROM: iCodeAddress %08x, iCodeSize %x, iTextSize %x",
+							rh.iCodeAddress, rh.iCodeSize, rh.iTextSize));
+		__LDRTRACE(MyPrintf("ROM: iDataAddress %08x, iDataSize %x, iBssSize %x",
+							rh.iDataAddress, rh.iDataSize, rh.iBssSize));
+		__LDRTRACE(MyPrintf("ROM: iDataBssLinearBase %08x, iTotalDataSize %x",
+							rh.iDataBssLinearBase, rh.iTotalDataSize));
+		}
+
+	if (exporter.iHeader)
+		{
+		const E32ImageHeader& ih = *exporter.iHeader;
+		__LDRTRACE(MyPrintf("HEAD: iCodeBase %08x, iCodeSize %x, iTextSize %x",
+							ih.iCodeBase, ih.iCodeSize, ih.iTextSize));
+		__LDRTRACE(MyPrintf("HEAD: iDataBase %08x, iDataSize %x, iBssSize %x",
+							ih.iDataBase, ih.iDataSize, ih.iBssSize));
+		}
+#endif // _DEBUG
+
+	// 'exportDir' points to the address of the 0th ordinal (symbol name data);
+	// ordinary exports start from ordinal 1
+	const TUint32* const exportDir = (TUint32*)exporter.iExportDirLoad - KOrdinalBase;
+	const TUint32 maxOrdinal = (TUint32)exporter.iExportDirCount;
+	const TUint32 absentOrdinal = (TUint32)exporter.iFileEntryPoint;
 
 	TUint32* iat = info.iIat;
-	TUint32* iatE = iat+info.iNumImports;
-	for(; iat<iatE; ++iat)
+	TUint32* const iatEnd = iat + info.iNumImports;
+	for (; iat < iatEnd; ++iat)
 		{
-		TUint32 imp = *iat;
-		if(imp>maxOrdinal)
+		// Each IAT slot contains the ordinal number of the export to be imported from
+		// the exporter. We use that index to locate the address of the export itself.
+		TUint32 ordinal = *iat;
+		if (ordinal > maxOrdinal)
 			return KErrNotSupported;
 
-		TUint32 writeValue;
-		if(imp==0 && !(info.iExporter->iAttr&ECodeSegAttNmdExpData))
-			{
-			// attempt to import ordinal zero (symbol name data) from an executable
-			// which doesn't export this information, use NULL for imported value in this case...
-			writeValue = NULL;
-			}
-		else
+		// If the import number is 0 (symbol name data), and the exporter doesn't provide
+		// this, we don't regard it as an error; we just skip this block, leaving the
+		// address set to 0. For all other valid cases, we index the export directory to
+		// find the exported object's address (which has already been relocated) ...
+		TUint32 newValue = 0;
+		if (ordinal > 0 || (exporter.iAttr & ECodeSegAttNmdExpData))
 			{
-			// get imported value from exporter...
-			TUint32 exp_addr = exp_dir[imp];
-			if(exp_addr==0 || exp_addr==absentOrdinal)
+			TUint32 expAddr = exportDir[ordinal];
+			if (expAddr == 0 || expAddr == absentOrdinal)
 				return KErrNotSupported;
-			writeValue = exp_addr + exp_delta;
+			// The new value is just the address of the export, no adjustment needed
+			newValue = expAddr;
 			}
 
-		// if not code paging then directly fix up the import...
-		if (info.iFixup64 == 0)
-			*iat = writeValue;
+		__LDRTRACE(MyPrintf("svFixupImportAddresses: import[%d]@%08x is export[%d] == %08x",
+							iat - info.iIat, iat, ordinal, newValue));
+
+		// In non-paged code, we can simply replace the ordinals in the IAT with the
+		// object addresses to which they refer once and for all. However, in a code
+		// paging system, the IAT may be thrown away and later reloaded from the code
+		// image; therefore, we need to save the updates in the buffer pointed to by
+		// 'iFixup64' so that they can be reapplied each time the code page(s)
+		// containing (parts of the) IAT are reloaded. The fixup entries are in the
+		// form of 64-bit words, with the 32-bit address-to-be-fixed-up in the upper
+		// half and the value-to-be-stored-there in the lower half -- the multiple
+		// casts are needed to stop some compilers whinging about converting a
+		// pointer to a 64-bit integral type :(
+		if (!info.iFixup64)
+			*iat = newValue;
 		else
-		// ...otherwise defer until the page is fixed up
-			{
-			TUint64 iat64 = reinterpret_cast<TUint64>(iat);
-			*info.iFixup64++ = (iat64 << 32) | writeValue;
-			}
+			*info.iFixup64++ = ((TUint64)(TUintPtr)iat << 32) | newValue;
 		}
 
+	// Finally, update 'info.iIat' to show which imports have been processed
 	info.iIat = iat;
 	return KErrNone;
 	}
@@ -436,50 +570,155 @@
 TInt svElfDerivedFixupImportAddresses(TAny* aPtr)
 	{
 	SFixupImportAddressesInfo& info = *(SFixupImportAddressesInfo*)aPtr;
-	TUint32 maxOrdinal = (TUint32)info.iExporter->iExportDirCount;
-	TUint32 absentOrdinal = (TUint32)info.iExporter->iFileEntryPoint;
-
-	TUint32* exp_dir = info.iExportDir - KOrdinalBase; // address of 0th ordinal
-	TUint32 exp_delta = info.iExportDirEntryDelta;
-	TUint32 code = info.iCodeLoadAddress;
+	E32Image& exporter = *info.iExporter;
+
+#ifdef _DEBUG
+	__LDRTRACE(MyPrintf(">svElfDerivedFixupImportAddresses %d imports, code@%08x, fixup@%08x exporter@%08x",
+						info.iNumImports, info.iCodeLoadAddress, info.iFixup64, info.iExporter));
+
+	// Dump everything potentially useful that we know about the exporter ...
+	__LDRTRACE(MyPrintf("%S: paged? %d, iRomImageHeader@%08x, iHeader@%08x",
+						&exporter.iFileName, exporter.iUseCodePaging,
+						exporter.iRomImageHeader, exporter.iHeader));
+	__LDRTRACE(MyPrintf("iCodeLoadAddress %08x, iCodeRunAddress %08x, iCodeSize %x iTextSize %x",
+						exporter.iCodeLoadAddress, exporter.iCodeRunAddress,
+						exporter.iCodeSize, exporter.iTextSize))
+	__LDRTRACE(MyPrintf("iDataLoadAddress %08x, iDataRunAddress %08x, iDataSize %x iBssSize %x iTotalDataSize %x",
+						exporter.iDataLoadAddress, exporter.iDataRunAddress,
+						exporter.iDataSize, exporter.iBssSize, exporter.iTotalDataSize));
+	__LDRTRACE(MyPrintf("iCodeDelta, %x iDataDelta %x, iExportDirEntryDelta %x",
+						exporter.iCodeDelta, exporter.iDataDelta, exporter.iExportDirEntryDelta));
+
+	if (exporter.iRomImageHeader)
+		{
+		const TRomImageHeader& rh = *exporter.iRomImageHeader;
+		__LDRTRACE(MyPrintf("ROM: iCodeAddress %08x, iCodeSize %x, iTextSize %x",
+							rh.iCodeAddress, rh.iCodeSize, rh.iTextSize));
+		__LDRTRACE(MyPrintf("ROM: iDataAddress %08x, iDataSize %x, iBssSize %x",
+							rh.iDataAddress, rh.iDataSize, rh.iBssSize));
+		__LDRTRACE(MyPrintf("ROM: iDataBssLinearBase %08x, iTotalDataSize %x",
+							rh.iDataBssLinearBase, rh.iTotalDataSize));
+		}
+
+	if (exporter.iHeader)
+		{
+		const E32ImageHeader& ih = *exporter.iHeader;
+		__LDRTRACE(MyPrintf("HEAD: iCodeBase %08x, iCodeSize %x, iTextSize %x",
+							ih.iCodeBase, ih.iCodeSize, ih.iTextSize));
+		__LDRTRACE(MyPrintf("HEAD: iDataBase %08x, iDataSize %x, iBssSize %x",
+							ih.iDataBase, ih.iDataSize, ih.iBssSize));
+		}
+#endif // _DEBUG
+
+	// Here we calculate the bounds of each section of the exporter, as
+	// code and data exports may have to be offset by different amounts.
+	// Unfortunately, the required information seems to be in several
+	// different places, depending on whether the code is ROM or RAM, etc
+	TUint32 codeStart = exporter.iCodeRunAddress;
+	TUint32 codeEnd = codeStart + exporter.iCodeSize;
+	TUint32 dataStart = exporter.iDataRunAddress;
+	TUint32 dataEnd = dataStart + exporter.iTotalDataSize;
+
+	if (exporter.iRomImageHeader)
+		{
+		const TRomImageHeader& rh = *exporter.iRomImageHeader;
+		codeStart = rh.iCodeAddress;
+		codeEnd = codeStart + rh.iCodeSize;
+		dataStart = rh.iDataBssLinearBase;
+		dataEnd = dataStart + rh.iTotalDataSize;
+		}
+
+	if (exporter.iHeader)
+		{
+		const E32ImageHeader& ih = *exporter.iHeader;
+		codeStart = ih.iCodeBase;
+		codeEnd = codeStart + ih.iCodeSize;
+		dataStart = ih.iDataBase;
+		dataEnd = dataStart + ih.iDataSize + ih.iBssSize;
+		}
+
+	// 'exportDir' points to the address of the 0th ordinal (symbol name data);
+	// ordinary exports start from ordinal 1
+	const TUint32* const exportDir = (TUint32*)exporter.iExportDirLoad - KOrdinalBase;
+	const TUint32 maxOrdinal = (TUint32)exporter.iExportDirCount;
+	const TUint32 absentOrdinal = (TUint32)exporter.iFileEntryPoint;
+
+	const TUint32 codeDelta = exporter.iCodeDelta;
+	const TUint32 dataDelta = exporter.iDataDelta;
+	const TUint32 dirDelta = exporter.iExportDirEntryDelta;
+	TUint8* const codeBase = (TUint8*)info.iCodeLoadAddress;
 
 	TUint32* iol = info.iImportOffsetList;
-	TUint32* iolE = iol+info.iNumImports;
-	for(; iol<iolE; ++iol)
+	TUint32* const iolEnd = iol + info.iNumImports;
+	for(; iol < iolEnd; ++iol)
 		{
-		TUint32* impPtr = (TUint32*)(code+*iol);
-		TUint32 impd = *impPtr;
-		TUint32 imp = impd & 0xffff;
-		TUint32 offset = impd >> 16;
-		if(imp>maxOrdinal)
+		// Whereas the PE format's IAT contains ordinals to be imported, the ELF IOL
+		// (Import Offset List) is a list of offsets (within the importer's code) of
+		// the locations that contain references to imported objects.
+		//
+		// At the start of this process, each such location contains a composite value,
+		// of which the low 16 bits indicate the ordinal to be imported from the
+		// exporter's directory, and the upper 16 provide an optional adjustment to
+		// be added to the imported value.
+		//
+		// This composite value has to be replaced by the actual address of the
+		// object being imported (plus the adjustment factor, if any).
+		TUint32 codeOffset = *iol;
+		TUint32* codePtr = (TUint32*)(codeBase+codeOffset);
+		TUint32 importInfo = *codePtr;
+		TUint32 ordinal = importInfo & 0xffff;
+		TUint32 adjustment = importInfo >> 16;
+		if(ordinal > maxOrdinal)
 			return KErrNotSupported;
 
-		TUint32 writeValue;
-		if(imp==0 && !(info.iExporter->iAttr&ECodeSegAttNmdExpData))
+		// If the import number is 0 (symbol name data), and the exporter doesn't provide
+		// this, we don't regard it as an error; we just skip this block, leaving the
+		// address set to 0. For all other valid cases, we index the export directory to find
+		// the exported object's address (which may OR MAY NOT have already been relocated)
+		TUint32 expAddr = 0;
+		TUint32 newValue = 0;
+		if (ordinal > 0 || (exporter.iAttr & ECodeSegAttNmdExpData))
 			{
-			// attempt to import ordinal zero (symbol name data) from an executable
-			// which doesn't export this information, use NULL for imported value in this case...
-			writeValue = NULL;
+			expAddr = exportDir[ordinal];
+			if(expAddr == 0 || expAddr == absentOrdinal)
+				return KErrNotSupported;
+
+			// If the exporter does not use code paging, then the entries in the export
+			// table will already have been relocated along with its text section. In
+			// the paged case, however, the relocation will have been deferred until the
+			// relevant pages are (re)loaded; therefore, we have to deduce here whether
+			// each export is code or data so that we can apply the correct delta ...
+			TUint32 sectionDelta;
+			if (!exporter.iUseCodePaging)
+				sectionDelta = dirDelta;
+			else if (expAddr >= codeStart && expAddr < codeEnd)
+				sectionDelta = codeDelta;			// points to text/rdata section
+			else if (expAddr >= dataStart && expAddr < dataEnd)
+				sectionDelta = dataDelta;			// points to data/bss section
+			else
+				sectionDelta = dirDelta;			// unknown - assume nonpaged?
+			newValue = expAddr + sectionDelta + adjustment;
 			}
+
+		__LDRTRACE(MyPrintf("svElfDerivedFixupImportAddresses: import[%d] (%08x:%08x) is export[%d] %08x+%08x => %08x",
+							iol - info.iImportOffsetList, codePtr, importInfo, ordinal, expAddr, adjustment, newValue));
+
+		// In non-paged code, we can simply replace the ordinals in the IAT with the
+		// object addresses to which they refer once and for all. However, in a code
+		// paging system, the IAT may be thrown away and later reloaded from the code
+		// image; therefore, we need to save the updates in the buffer pointed to by
+		// 'iFixup64' so that they can be reapplied each time the code page(s)
+		// containing (parts of the) IAT are reloaded. The fixup entries are in the
+		// form of 64-bit words, with the 32-bit address-to-be-fixed-up in the upper
+		// half and the value-to-be-stored-there in the lower half -- the multiple
+		// casts are needed to stop some compilers whinging about converting a
+		// pointer to a 64-bit integral type :(
+		if (!info.iFixup64)
+			*codePtr = newValue;
 		else
-			{
-			// get imported value from exporter...
-			TUint32 exp_addr = exp_dir[imp];
-			if(exp_addr==0 || exp_addr==absentOrdinal)
-				return KErrNotSupported;
-			writeValue = exp_addr + exp_delta + offset;
-			}
-
-		// if not code paging then directly fix up the import...
-		if (info.iFixup64 == 0)
-			*impPtr = writeValue;
-		// ...otherwise defer until the page is fixed up
-		else
-			{
-			TUint64 impPtr64 = reinterpret_cast<TUint64>(impPtr);
-			*info.iFixup64++ = (impPtr64 << 32) | writeValue;
-			}
+			*info.iFixup64++ = ((TUint64)(TUintPtr)codePtr << 32) | newValue;
 		}
+
 	return KErrNone;
 	}
 
@@ -2834,8 +3073,9 @@
 			//	on "new" dlls
 			if (e->iDepCount && !e->iAlreadyLoaded && e->iIsDll)
 				{
-				__IF_DEBUG(Printf("****Go recursive****"));
+				__IF_DEBUG(Printf("****Going recursive****"));
 				r = e->LoadDlls(aArray);
+				__IF_DEBUG(Printf("****Returned from recursion****"));
 				if (r!=KErrNone)
 					{
 					return r;
@@ -2956,8 +3196,6 @@
 			r = exp->ReadExportDirLoad();
 			if (r != KErrNone)
 				return r;
-			info.iExportDir = (TUint32*)exp->iExportDirLoad;
-			info.iExportDirEntryDelta = exp->iExportDirEntryDelta;
 			info.iNumImports = block->iNumberOfImports;
 			info.iExporter = exp;
 
@@ -2976,10 +3214,14 @@
 			if (impfmt == KImageImpFmt_ELF)
 				{
 				info.iImportOffsetList = (TUint32*)(block+1);
+				__IF_DEBUG(Printf("Import format ELF (%08x); info@%08x", impfmt, &info));
 				r = ExecuteInSupervisorMode(&svElfDerivedFixupImportAddresses, &info);
 				}
 			else
+				{
+				__IF_DEBUG(Printf("Import format PE (%08x); info@%08x", impfmt, &info));
 				r = ExecuteInSupervisorMode(&svFixupImportAddresses, &info);
+				}
 
 			if (r != KErrNone)
 				{
@@ -3058,7 +3300,18 @@
 */
 TInt E32Image::BuildImportFixupTable()
 	{
-	__IF_DEBUG(Printf(">BuildImportFixupTable,0x%08x,%d", iFixups, iFixupCount));
+	__IF_DEBUG(Printf(">BuildImportFixupTable,%d@%08x,%08x", iFixupCount, iFixups, iCodeLoadAddress));
+
+#ifdef _DEBUG
+	// Dump the incoming fixup table if loader tracing enabled. Each item is an
+	// (address, value) pair, where the address and the value are 32 bits each.
+	TInt i;
+	for (i = 0; i < iFixupCount; ++i)
+		{
+		TUint64 x = iFixups[i];
+		__IF_DEBUG(Printf("%04x: %08x %08x", i*sizeof(TUint64), I64HIGH(x), I64LOW(x)));
+		}
+#endif	// DEBUG
 
 	// sort the array in address order, to organize by page
 	RArray<TUint64> fixup64ToSort(sizeof(TUint64), iFixups, iFixupCount);
@@ -3070,7 +3323,7 @@
 	// to the word at offset XXX.  (See PREQ1110 Design Sketch v1.0 S3.1.1.2.3.2.)
 
 	TUint32 pageCount = SizeToPageCount(iCodeSize);
-	iImportFixupTableSize = (pageCount+1) * sizeof(TUint32) + iFixupCount * 3 * sizeof(TUint16);
+	iImportFixupTableSize = (pageCount+1)*sizeof(TUint32) + 3*iFixupCount*sizeof(TUint16);
 	iImportFixupTable = (TUint32*) User::Alloc(iImportFixupTableSize);
 	__IF_DEBUG(Printf("iImportFixupTable=0x%08x", iImportFixupTable));
 	if (iImportFixupTable == 0)
@@ -3121,18 +3374,20 @@
 	while (++lastPage <= pageCount)
 		iImportFixupTable[lastPage] = iImportFixupTableSize;
 
-	__IF_DEBUG(Printf("processed table (size=%d,pageCount=%d)", iImportFixupTableSize, pageCount));
-
 #ifdef _DEBUG
-	// dump the import fixup table if loader tracing enabled
+	__IF_DEBUG(Printf("processed fixup table (size=%d,pageCount=%d)", iImportFixupTableSize, pageCount));
+
+	// Dump the processed fixup table if loader tracing enabled. The dump is in two
+	// parts; first, the page indexes (1 word per page), then the entries describing
+	// the items to be relocated, each of which is a 16-bit offset-within-page and a
+	// 32-bit value to be stored there.
+	for (i = 0; i <= (TInt)pageCount; ++i)
+		__IF_DEBUG(Printf("%04x: %08x", i*4, iImportFixupTable[i]));
+
 	const TUint16* table16 = (const TUint16*)iImportFixupTable;
 	const TInt halfWordsInTable = iImportFixupTableSize / 2;
-	for (TInt i = 0; i < halfWordsInTable; i += 4)
-		{
-		__IF_DEBUG(Printf(
-			"%04x: %04x %04x %04x %04x",
-			i * 2, table16[i+0], table16[i+1], table16[i+2], table16[i+3]));
-		}
+	for (i *= 2; i < halfWordsInTable; i += 3)
+		__IF_DEBUG(Printf("%04x: %04x %04x%04x", i*2, table16[i+0], table16[i+2], table16[i+1]));
 #endif
 
 	User::Free(iFixups);