symbian-qemu-0.9.1-12/python-2.6.1/Mac/Modules/cg/CFMLateImport.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2 	File:		CFMLateImport.c
       
     3 
       
     4 	Contains:	Implementation of CFM late import library.
       
     5 
       
     6 	Written by:	Quinn
       
     7 
       
     8 	Copyright:	Copyright © 1999 by Apple Computer, Inc., all rights reserved.
       
     9 
       
    10 				You may incorporate this Apple sample source code into your program(s) without
       
    11 				restriction. This Apple sample source code has been provided "AS IS" and the
       
    12 				responsibility for its operation is yours. You are not permitted to redistribute
       
    13 				this Apple sample source code as "Apple sample source code" after having made
       
    14 				changes. If you're going to re-distribute the source, we require that you make
       
    15 				it clear in the source that the code was descended from Apple sample source
       
    16 				code, but that you've made changes.
       
    17 
       
    18 	Change History (most recent first):
       
    19 
       
    20         <13>     24/9/01    Quinn   Fixes to compile with C++ activated.
       
    21         <12>     21/9/01    Quinn   [2710489] Fix typo in the comments for FragmentLookup.
       
    22         <11>     21/9/01    Quinn   Changes for CWPro7 Mach-O build.
       
    23         <10>     19/9/01    Quinn   Corrected implementation of kPEFRelocSmBySection. Added
       
    24                                     implementations of kPEFRelocSetPosition and kPEFRelocLgByImport
       
    25                                     (from code contributed by Eric Grant, Ned Holbrook, and Steve
       
    26                                     Kalkwarf), although I can't test them yet.
       
    27          <9>     19/9/01    Quinn   We now handle unpacked data sections, courtesy of some code from
       
    28                                     Ned Holbrook.
       
    29          <8>     19/9/01    Quinn   Minor fixes for the previous checkin. Updated some comments and
       
    30                                     killed some dead code.
       
    31          <7>     19/9/01    Quinn   Simplified API and implementation after a suggestion by Eric
       
    32                                     Grant. You no longer have to CFM export a dummy function; you
       
    33                                     can just pass in the address of your fragment's init routine.
       
    34          <6>     15/2/01    Quinn   Modify compile-time warnings to complain if you try to build
       
    35                                     this module into a Mach-O binary.
       
    36          <5>      5/2/01    Quinn   Removed redundant assignment in CFMLateImportCore.
       
    37          <4>    30/11/00    Quinn   Added comment about future of data symbols in CF.
       
    38          <3>    16/11/00    Quinn   Allow symbol finding via a callback and use that to implement
       
    39                                     CFBundle support.
       
    40          <2>    18/10/99    Quinn   Renamed CFMLateImport to CFMLateImportLibrary to allow for
       
    41                                     possible future API expansion.
       
    42          <1>     15/6/99    Quinn   First checked in.
       
    43 */
       
    44 
       
    45 // To Do List:
       
    46 //
       
    47 // o get rid of dependence on ANSI "string.h", but how?
       
    48 //
       
    49 // Done:
       
    50 //
       
    51 // Ã investigate alternative APIs, like an external lookup routine
       
    52 //   renamed CFMLateImport to CFMLateImportLibrary to allow for
       
    53 //   future expansion of the APIs for things like CFMLateImportSymbol
       
    54 // Ã test with non-zero fragment offset in the file
       
    55 // Ã test more with MPW fragments
       
    56 // Ã test data imports
       
    57 
       
    58 /////////////////////////////////////////////////////////////////
       
    59 
       
    60 // MoreIsBetter Setup
       
    61 
       
    62 //#include "MoreSetup.h"
       
    63 #define MoreAssert(x) (true)
       
    64 #define MoreAssertQ(x)
       
    65 
       
    66 // Mac OS Interfaces
       
    67 
       
    68 #if ! MORE_FRAMEWORK_INCLUDES
       
    69 	#include <CodeFragments.h>
       
    70 	#include <PEFBinaryFormat.h>
       
    71 #endif
       
    72 
       
    73 // Standard C Interfaces
       
    74 
       
    75 #include <string.h>
       
    76 
       
    77 // MIB Prototypes
       
    78 
       
    79 //#include "MoreInterfaceLib.h"
       
    80 #define MoreBlockZero BlockZero
       
    81 
       
    82 // Our Prototypes
       
    83 
       
    84 #include "CFMLateImport.h"
       
    85 
       
    86 /////////////////////////////////////////////////////////////////
       
    87 
       
    88 #if TARGET_RT_MAC_MACHO
       
    89 	#error CFMLateImport is not suitable for use in a Mach-O project.
       
    90 #elif !TARGET_RT_MAC_CFM || !TARGET_CPU_PPC
       
    91 	#error CFMLateImport has not been qualified for 68K or CFM-68K use.
       
    92 #endif
       
    93 
       
    94 /////////////////////////////////////////////////////////////////
       
    95 #pragma mark ----- Utility Routines -----
       
    96 
       
    97 static OSStatus FSReadAtOffset(SInt16 refNum, SInt32 offset, SInt32 count, void *buffer)
       
    98 	// A convenient wrapper around PBRead which has two advantages
       
    99 	// over FSRead.  First, it takes count as a value parameter.
       
   100 	// Second, it reads from an arbitrary offset into the file,
       
   101 	// which avoids a bunch of SetFPos calls.
       
   102 	//
       
   103 	// I guess this should go into "MoreFiles.h", but I'm not sure
       
   104 	// how we're going to integrate such a concept into MIB yet.
       
   105 {
       
   106 	ParamBlockRec pb;
       
   107 	
       
   108 	pb.ioParam.ioRefNum     = refNum;
       
   109 	pb.ioParam.ioBuffer     = (Ptr) buffer;
       
   110 	pb.ioParam.ioReqCount   = count;
       
   111 	pb.ioParam.ioPosMode    = fsFromStart;
       
   112 	pb.ioParam.ioPosOffset  = offset;
       
   113 	
       
   114 	return PBReadSync(&pb);
       
   115 }
       
   116 
       
   117 /////////////////////////////////////////////////////////////////
       
   118 #pragma mark ----- Late Import Engine -----
       
   119 
       
   120 // This structure represents the core data structure of the late import
       
   121 // engine.  It basically holds information about the fragment we're going
       
   122 // to fix up.  It starts off with the first three fields, which are
       
   123 // provided by the client.  Then, as we procede through the operation,
       
   124 // we fill out more fields.
       
   125 
       
   126 struct FragToFixInfo {
       
   127 	CFragSystem7DiskFlatLocator	locator;				// How to find the fragment's container.
       
   128 	CFragConnectionID 			connID;					// CFM connection to the fragment.
       
   129 	CFragInitFunction 			initRoutine;			// The CFM init routine for the fragment.
       
   130 	PEFContainerHeader 			containerHeader;		// The CFM header, read in from the container.
       
   131 	PEFSectionHeader			*sectionHeaders;		// The CFM section headers.  A pointer block containing an array of containerHeader.sectionCount elements.
       
   132 	PEFLoaderInfoHeader			*loaderSection;			// The entire CFM loader section in a pointer block.
       
   133 	SInt16						fileRef;				// A read-only path to the CFM container.  We keep this here because one that one routine needs to read from the container.
       
   134 	void 						*section0Base;			// The base address of section 0, which we go through hoops to calculate.
       
   135 	void 						*section1Base;			// The base address of section 1, which we go through hoops to calculate.
       
   136 	Boolean						disposeSectionPointers;	// See below.
       
   137 };
       
   138 typedef struct FragToFixInfo FragToFixInfo;
       
   139 
       
   140 // The disposeSectionPointers Boolean is designed for future cool VM
       
   141 // support.  If VM is on, the entire code fragment is file mapped into
       
   142 // high memory, including the data we're forced to allocate the
       
   143 // sectionHeaders and loaderSection memory blocks to maintain.  If
       
   144 // we could find the address of the entire file mapped container,
       
   145 // we could access the information directly from there and thus
       
   146 // we wouldn't need to allocate (or dispose of) the memory blocks
       
   147 // for sectionHeaders and loaderSection.
       
   148 //
       
   149 // I haven't implemented this yet because a) I'm not sure how to do
       
   150 // it with documented APIs, and b) I couldn't be bothered, but
       
   151 // disposeSectionPointers remains as vestigial support for the concept.
       
   152 
       
   153 static OSStatus ReadContainerBasics(FragToFixInfo *fragToFix)
       
   154 	// Reads some basic information from the container of the
       
   155 	// fragment to fix and stores it in various fields of
       
   156 	// fragToFix.  This includes:
       
   157 	//
       
   158 	// o containerHeader -- The contain header itself.
       
   159 	// o sectionHeaders  -- The array of section headers (in a newly allocated pointer block).
       
   160 	// o loaderSection   -- The entire loader section (in a newly allocated pointer block).
       
   161 	//
       
   162 	// Also sets disposeSectionPointers to indicate whether
       
   163 	// the last two pointers should be disposed of.
       
   164 	//
       
   165 	// Finally, it leaves the container file open for later
       
   166 	// folks who want to read data from it.
       
   167 {
       
   168 	OSStatus 	err;
       
   169 	UInt16 		sectionIndex;
       
   170 	Boolean 	found;
       
   171 
       
   172 	MoreAssertQ(fragToFix != nil);
       
   173 	MoreAssertQ(fragToFix->locator.fileSpec != nil);
       
   174 	MoreAssertQ(fragToFix->connID != nil);
       
   175 	MoreAssertQ(fragToFix->loaderSection == nil);
       
   176 	MoreAssertQ(fragToFix->sectionHeaders == nil);
       
   177 	MoreAssertQ(fragToFix->fileRef == 0);
       
   178 	
       
   179 	fragToFix->disposeSectionPointers = true;
       
   180 	
       
   181 	// Open up the file, read the container head, then read in
       
   182 	// all the section headers, then go looking through the
       
   183 	// section headers for the loader section (PEF defines
       
   184 	// that there can be only one).
       
   185 	
       
   186 	err = FSpOpenDF(fragToFix->locator.fileSpec, fsRdPerm, &fragToFix->fileRef);
       
   187 	if (err == noErr) {
       
   188 		err = FSReadAtOffset(fragToFix->fileRef,
       
   189 								fragToFix->locator.offset,
       
   190 								sizeof(fragToFix->containerHeader),
       
   191 								&fragToFix->containerHeader);
       
   192 		if (err == noErr) {
       
   193 			if (   fragToFix->containerHeader.tag1 != kPEFTag1
       
   194 				|| fragToFix->containerHeader.tag2 != kPEFTag2
       
   195 				|| fragToFix->containerHeader.architecture != kCompiledCFragArch
       
   196 				|| fragToFix->containerHeader.formatVersion != kPEFVersion) {
       
   197 				err = cfragFragmentFormatErr;
       
   198 			}
       
   199 		}
       
   200 		if (err == noErr) {
       
   201 			fragToFix->sectionHeaders = (PEFSectionHeader *) NewPtr(fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader));
       
   202 			err = MemError();
       
   203 		}
       
   204 		if (err == noErr) {
       
   205 			err = FSReadAtOffset(fragToFix->fileRef,
       
   206 									fragToFix->locator.offset + sizeof(fragToFix->containerHeader),
       
   207 									fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader), 
       
   208 									fragToFix->sectionHeaders);
       
   209 		}
       
   210 		if (err == noErr) {
       
   211 			sectionIndex = 0;
       
   212 			found = false;
       
   213 			while ( sectionIndex < fragToFix->containerHeader.sectionCount && ! found ) {
       
   214 				found = (fragToFix->sectionHeaders[sectionIndex].sectionKind == kPEFLoaderSection);
       
   215 				if ( ! found ) {
       
   216 					sectionIndex += 1;
       
   217 				}
       
   218 			}
       
   219 		}
       
   220 		if (err == noErr && ! found) {
       
   221 			err = cfragNoSectionErr;
       
   222 		}
       
   223 		
       
   224 		// Now read allocate a pointer block and read the loader section into it.
       
   225 		
       
   226 		if (err == noErr) {
       
   227 			fragToFix->loaderSection = (PEFLoaderInfoHeader *) NewPtr(fragToFix->sectionHeaders[sectionIndex].containerLength);
       
   228 			err = MemError();
       
   229 		}
       
   230 		if (err == noErr) {
       
   231 			err = FSReadAtOffset(fragToFix->fileRef, 
       
   232 									fragToFix->locator.offset + fragToFix->sectionHeaders[sectionIndex].containerOffset,
       
   233 									fragToFix->sectionHeaders[sectionIndex].containerLength, 
       
   234 									fragToFix->loaderSection);
       
   235 		}				
       
   236 	}
       
   237 	
       
   238 	// No clean up.  The client must init fragToFix to zeros and then
       
   239 	// clean up regardless of whether we return an error.
       
   240 		
       
   241 	return err;
       
   242 }
       
   243 
       
   244 static UInt32 DecodeVCountValue(const UInt8 *start, UInt32 *outCount)
       
   245 	// Given a pointer to the start of a variable length PEF value, 
       
   246 	// work out the value (in *outCount).  Returns the number of bytes 
       
   247 	// consumed by the value.
       
   248 {
       
   249 	UInt8 *			bytePtr;
       
   250 	UInt8			byte;
       
   251 	UInt32			count;
       
   252 	
       
   253 	bytePtr = (UInt8 *)start;
       
   254 	
       
   255 	// Code taken from "PEFBinaryFormat.h".
       
   256 	count = 0;
       
   257 	do {
       
   258 		byte = *bytePtr++;
       
   259 		count = (count << kPEFPkDataVCountShift) | (byte & kPEFPkDataVCountMask);
       
   260 	} while ((byte & kPEFPkDataVCountEndMask) != 0);
       
   261 	
       
   262 	*outCount = count;
       
   263 	return bytePtr - start;
       
   264 }
       
   265 
       
   266 static UInt32 DecodeInstrCountValue(const UInt8 *inOpStart, UInt32 *outCount)
       
   267 	// Given a pointer to the start of an opcode (inOpStart), work out the 
       
   268 	// count argument for that opcode (*outCount).  Returns the number of 
       
   269 	// bytes consumed by the opcode and count combination.
       
   270 {
       
   271 	MoreAssertQ(inOpStart != nil);
       
   272 	MoreAssertQ(outCount  != nil);
       
   273 	
       
   274 	if (PEFPkDataCount5(*inOpStart) != 0)
       
   275 	{
       
   276 		// Simple case, count encoded in opcode.
       
   277 		*outCount = PEFPkDataCount5(*inOpStart);
       
   278 		return 1;
       
   279 	}
       
   280 	else
       
   281 	{
       
   282 		// Variable-length case.
       
   283 		return 1 + DecodeVCountValue(inOpStart + 1, outCount);
       
   284 	}
       
   285 }
       
   286 
       
   287 static OSStatus UnpackPEFDataSection(const UInt8 * const packedData,   UInt32 packedSize,
       
   288 								           UInt8 * const unpackedData, UInt32 unpackedSize)
       
   289 {
       
   290 	OSErr			err;
       
   291 	UInt32			offset;
       
   292 	UInt8			opCode;
       
   293 	UInt8 *			unpackCursor;
       
   294 	
       
   295 	MoreAssertQ(packedData != nil);
       
   296 	MoreAssertQ(unpackedData != nil);
       
   297 	MoreAssertQ(unpackedSize >= packedSize);
       
   298 
       
   299 	// The following asserts assume that the client allocated the memory with NewPtr, 
       
   300 	// which may not always be true.  However, the asserts' value in preventing accidental 
       
   301 	// memory block overruns outweighs the possible maintenance effort.
       
   302 	
       
   303 	MoreAssertQ( packedSize   == GetPtrSize( (Ptr) packedData  ) );
       
   304 	MoreAssertQ( unpackedSize == GetPtrSize( (Ptr) unpackedData) );
       
   305 	
       
   306 	err          = noErr;
       
   307 	offset       = 0;
       
   308 	unpackCursor = unpackedData;
       
   309 	while (offset < packedSize) {
       
   310 		MoreAssertQ(unpackCursor < &unpackedData[unpackedSize]);
       
   311 		
       
   312 		opCode = packedData[offset];
       
   313 		
       
   314 		switch (PEFPkDataOpcode(opCode)) {
       
   315 			case kPEFPkDataZero:
       
   316 				{
       
   317 					UInt32	count;
       
   318 					
       
   319 					offset += DecodeInstrCountValue(&packedData[offset], &count);
       
   320 					
       
   321 					MoreBlockZero(unpackCursor, count);
       
   322 					unpackCursor += count;
       
   323 				}
       
   324 				break;
       
   325 			
       
   326 			case kPEFPkDataBlock:
       
   327 				{
       
   328 					UInt32	blockSize;
       
   329 					
       
   330 					offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
       
   331 					
       
   332 					BlockMoveData(&packedData[offset], unpackCursor, blockSize);
       
   333 					unpackCursor += blockSize;
       
   334 					offset += blockSize;
       
   335 				}
       
   336 				break;
       
   337 			
       
   338 			case kPEFPkDataRepeat:
       
   339 				{
       
   340 					UInt32	blockSize;
       
   341 					UInt32	repeatCount;
       
   342 					UInt32  loopCounter;
       
   343 					
       
   344 					offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
       
   345 					offset += DecodeVCountValue(&packedData[offset], &repeatCount);
       
   346 					repeatCount += 1;	// stored value is (repeatCount - 1)
       
   347 					
       
   348 					for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
       
   349 						BlockMoveData(&packedData[offset], unpackCursor, blockSize);
       
   350 						unpackCursor += blockSize;
       
   351 					}
       
   352 					offset += blockSize;
       
   353 				}
       
   354 				break;
       
   355 			
       
   356 			case kPEFPkDataRepeatBlock:
       
   357 				{
       
   358 					UInt32	commonSize;
       
   359 					UInt32	customSize;
       
   360 					UInt32	repeatCount;
       
   361 					const UInt8 *commonData;
       
   362 					const UInt8 *customData;
       
   363 					UInt32 loopCounter;
       
   364 					
       
   365 					offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
       
   366 					offset += DecodeVCountValue(&packedData[offset], &customSize);
       
   367 					offset += DecodeVCountValue(&packedData[offset], &repeatCount);
       
   368 					
       
   369 					commonData = &packedData[offset];
       
   370 					customData = &packedData[offset + commonSize];
       
   371 					
       
   372 					for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
       
   373 						BlockMoveData(commonData, unpackCursor, commonSize);
       
   374 						unpackCursor += commonSize;
       
   375 						BlockMoveData(customData, unpackCursor, customSize);
       
   376 						unpackCursor += customSize;
       
   377 						customData += customSize;
       
   378 					}
       
   379 					BlockMoveData(commonData, unpackCursor, commonSize);
       
   380 					unpackCursor += commonSize;
       
   381 					offset += (repeatCount * (commonSize + customSize)) + commonSize;
       
   382 				}
       
   383 				break;
       
   384 			
       
   385 			case kPEFPkDataRepeatZero:
       
   386 				{
       
   387 					UInt32	commonSize;
       
   388 					UInt32	customSize;
       
   389 					UInt32	repeatCount;
       
   390 					const UInt8 *customData;
       
   391 					UInt32 loopCounter;
       
   392 					
       
   393 					offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
       
   394 					offset += DecodeVCountValue(&packedData[offset], &customSize);
       
   395 					offset += DecodeVCountValue(&packedData[offset], &repeatCount);
       
   396 					
       
   397 					customData = &packedData[offset];
       
   398 					
       
   399 					for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
       
   400 						MoreBlockZero(unpackCursor, commonSize);
       
   401 						unpackCursor += commonSize;
       
   402 						BlockMoveData(customData, unpackCursor, customSize);
       
   403 						unpackCursor += customSize;
       
   404 						customData += customSize;
       
   405 					}
       
   406 					MoreBlockZero(unpackCursor, commonSize);
       
   407 					unpackCursor += commonSize;
       
   408 					offset += repeatCount * customSize;
       
   409 				}
       
   410 				break;
       
   411 			
       
   412 			default:
       
   413 				#if MORE_DEBUG
       
   414 					DebugStr("\pUnpackPEFDataSection: Unexpected data opcode");
       
   415 				#endif
       
   416 				err = cfragFragmentCorruptErr;
       
   417 				goto leaveNow;
       
   418 				break;
       
   419 		}
       
   420 	}
       
   421 	
       
   422 leaveNow:
       
   423 	return err;
       
   424 }
       
   425 
       
   426 /*	SetupSectionBaseAddresses Rationale
       
   427 	-----------------------------------
       
   428 	
       
   429 	OK, here's where things get weird.  In order to run the relocation
       
   430 	engine, I need to be able to find the base address of an instantiated
       
   431 	section of the fragment we're fixing up given only its section number.
       
   432 	This isn't hard for CFM to do because it's the one that instantiated the
       
   433 	sections in the first place.  It's surprisingly difficult to do if
       
   434 	you're not CFM.  [And you don't have access to the private CFM APis for 
       
   435 	doing it.]
       
   436 	
       
   437 	[Alan Lillich is going to kill me when he reads this!  I should point out
       
   438 	 that TVector's don't have to contain two words, they can be longer,
       
   439 	 and that the second word isn't necessarily a TOC pointer, it's
       
   440 	 just that the calling conventions require that it be put in the
       
   441 	 TOC register when the code is called.
       
   442 	 
       
   443 	 Furthermore, the code section isn't always section 0, and the data
       
   444 	 section isn't always section 1, and there can be zero to many sections
       
   445 	 of each type.
       
   446 	 
       
   447 	 But these niceties are besides the point: I'm doing something tricky 
       
   448 	 because I don't have a nice API for getting section base addresses.  
       
   449 	 If I had a nice API for doing that, none of this code would exist.
       
   450 	]
       
   451 
       
   452 	The technique is very sneaky (thanks to Eric Grant).  The fragment to 
       
   453 	fix necessarily has a CFM init routine (because it needs that routine 
       
   454 	in order to capture the fragment location and connection ID).  Thus the 
       
   455 	fragment to fix must have a TVector in its data section.  TVectors are 
       
   456 	interesting because they're made up of two words.  The first is a pointer 
       
   457 	to the code that implements the routine; the second is a pointer to the TOC
       
   458 	for the fragment that's exporting the TVector.  How TVectors are
       
   459 	created is interesting too.  On disk, a TVector consists of two words,
       
   460 	the first being the offset from the start of the code section to the
       
   461 	routine, the second being the offset from the start of the data section
       
   462 	to the TOC base.  When CFM prepares a TVector, it applies the following
       
   463 	transform:
       
   464 	
       
   465 		tvector.codePtr = tvector.codeOffset + base of code section
       
   466 		tvector.tocPtr  = tvector.tocOffset  + base of data section
       
   467 		
       
   468 	Now, you can reverse these questions to make them:
       
   469 	
       
   470 		base of code section = tvector.codePtr - tvector.codeOffset
       
   471 		base of data section = tvector.dataPtr - tvector.dataOffset
       
   472 	
       
   473 	So if you can find the relocated contents of the TVector and
       
   474 	find the original offsets that made up the TVector, you can then
       
   475 	calculate the base address of both the code and data sections.
       
   476 	
       
   477 	Finding the relocated contents of the TVector is easy; I simply 
       
   478 	require the client to pass in a pointer to its init routine. 
       
   479 	A routine pointer is a TVector pointer, so you can just cast it 
       
   480 	and extract the pair of words.
       
   481 
       
   482 	Finding the original offsets is a trickier.  My technique is to
       
   483 	look up the init routine in the fragment's loader info header.  This
       
   484 	yields the section number and offset where the init routine's unrelocated 
       
   485 	TVector exists.  Once I have that, I can just read the unrelocated TVector
       
   486 	out of the file and extract the offsets.
       
   487 */
       
   488 
       
   489 struct TVector {
       
   490 	void *codePtr;
       
   491 	void *tocPtr;
       
   492 };
       
   493 typedef struct TVector TVector;
       
   494 
       
   495 static OSStatus SetupSectionBaseAddresses(FragToFixInfo *fragToFix)
       
   496 	// This routine initialises the section0Base and section1Base
       
   497 	// base fields of fragToFix to the base addresses of the
       
   498 	// instantiated fragment represented by the other fields
       
   499 	// of fragToFix.  The process works in three states:
       
   500 	//
       
   501 	// 1. 	Find the contents of the relocated TVector of the 
       
   502 	//      fragment's initialisation routine, provided to us by 
       
   503 	//      the caller.
       
   504 	//
       
   505 	// 2.	Find the contents of the non-relocated TVector by 
       
   506 	//      looking it up in the PEF loader info header and then 
       
   507 	//      using that to read the TVector contents from disk.
       
   508 	//      This yields the offsets from the section bases for 
       
   509 	//      the init routine.
       
   510 	//
       
   511 	// 3.	Subtract 2 from 3.
       
   512 {
       
   513 	OSStatus 			err;
       
   514 	TVector *			relocatedExport;
       
   515 	SInt32				initSection;
       
   516 	UInt32				initOffset;
       
   517 	PEFSectionHeader *	initSectionHeader;
       
   518 	Ptr					packedDataSection;
       
   519 	Ptr					unpackedDataSection;
       
   520 	TVector 			originalOffsets;
       
   521 
       
   522 	packedDataSection   = nil;
       
   523 	unpackedDataSection = nil;
       
   524 	
       
   525 	// Step 1.
       
   526 
       
   527 	// First find the init routine's TVector, which gives us the relocated 
       
   528 	// offsets of the init routine into the data and code sections.
       
   529 
       
   530 	relocatedExport = (TVector *) fragToFix->initRoutine;
       
   531 		
       
   532 	// Step 2.
       
   533 	
       
   534 	// Now find the init routine's TVector's offsets in the data section on 
       
   535 	// disk.  This gives us the raw offsets from the data and code section 
       
   536 	// of the beginning of the init routine.
       
   537 	
       
   538 	err = noErr;
       
   539 	initSection = fragToFix->loaderSection->initSection;
       
   540 	initOffset  = fragToFix->loaderSection->initOffset;
       
   541 	if (initSection == -1) {
       
   542 		err = cfragFragmentUsageErr;
       
   543 	}
       
   544 	if (err == noErr) {
       
   545 		MoreAssertQ( initSection >= 0 );		// Negative indexes are pseudo-sections which are just not allowed!
       
   546 		MoreAssertQ( initSection < fragToFix->containerHeader.sectionCount );
       
   547 
       
   548 		initSectionHeader = &fragToFix->sectionHeaders[initSection];
       
   549 		
       
   550 		// If the data section is packed, unpack it to a temporary buffer and then get the 
       
   551 		// original offsets from that buffer.  If the data section is unpacked, just read 
       
   552 		// the original offsets directly off the disk.
       
   553 		
       
   554 		if ( initSectionHeader->sectionKind == kPEFPackedDataSection ) {
       
   555 
       
   556 			// Allocate space for packed and unpacked copies of the section.
       
   557 			
       
   558 			packedDataSection = NewPtr(initSectionHeader->containerLength);
       
   559 			err = MemError();
       
   560 
       
   561 			if (err == noErr) {
       
   562 				unpackedDataSection = NewPtr(initSectionHeader->unpackedLength);
       
   563 				err = MemError();
       
   564 			}
       
   565 
       
   566 			// Read the contents of the packed section.
       
   567 			
       
   568 			if (err == noErr) {
       
   569 				err = FSReadAtOffset(	fragToFix->fileRef,
       
   570 										fragToFix->locator.offset
       
   571 										+ initSectionHeader->containerOffset,
       
   572 										initSectionHeader->containerLength,
       
   573 										packedDataSection);
       
   574 			}
       
   575 			
       
   576 			// Unpack the data into the unpacked section.
       
   577 			
       
   578 			if (err == noErr) {
       
   579 				err = UnpackPEFDataSection( (UInt8 *) packedDataSection,   initSectionHeader->containerLength,
       
   580 								            (UInt8 *) unpackedDataSection, initSectionHeader->unpackedLength);
       
   581 			}
       
   582 			
       
   583 			// Extract the init routine's TVector from the unpacked section.
       
   584 			
       
   585 			if (err == noErr) {
       
   586 				BlockMoveData(unpackedDataSection + initOffset, &originalOffsets, sizeof(TVector));
       
   587 			}
       
   588 			
       
   589 		} else {
       
   590 			MoreAssertQ(fragToFix->sectionHeaders[initSection].sectionKind == kPEFUnpackedDataSection);
       
   591 			err = FSReadAtOffset(fragToFix->fileRef, 
       
   592 									fragToFix->locator.offset
       
   593 									+ fragToFix->sectionHeaders[initSection].containerOffset
       
   594 									+ initOffset,
       
   595 									sizeof(TVector), 
       
   596 									&originalOffsets);
       
   597 		}
       
   598 	}
       
   599 
       
   600 	// Step 3.
       
   601 		
       
   602 	// Do the maths to subtract the unrelocated offsets from the current address 
       
   603 	// to get the base address.
       
   604 	
       
   605 	if (err == noErr) {
       
   606 		fragToFix->section0Base = ((char *) relocatedExport->codePtr) - (UInt32) originalOffsets.codePtr;
       
   607 		fragToFix->section1Base = ((char *) relocatedExport->tocPtr)  - (UInt32) originalOffsets.tocPtr;
       
   608 	}
       
   609 	
       
   610 	// Clean up.
       
   611 	
       
   612 	if (packedDataSection != nil) {
       
   613 		DisposePtr(packedDataSection);
       
   614 		MoreAssertQ( MemError() == noErr );
       
   615 	}
       
   616 	if (unpackedDataSection != nil) {
       
   617 		DisposePtr(unpackedDataSection);
       
   618 		MoreAssertQ( MemError() == noErr );
       
   619 	}
       
   620 	return err;
       
   621 }
       
   622 
       
   623 static void *GetSectionBaseAddress(const FragToFixInfo *fragToFix, UInt16 sectionIndex)
       
   624 	// This routine returns the base of the instantiated section
       
   625 	// whose index is sectionIndex.  This routine is the evil twin
       
   626 	// of SetupSectionBaseAddresses.  It simply returns the values
       
   627 	// for section 0 and 1 that we derived in SetupSectionBaseAddresses.
       
   628 	// In a real implementation, this routine would call CFM API
       
   629 	// to get this information, and SetupSectionBaseAddresses would
       
   630 	// not exist, but CFM does not export the necessary APIs to
       
   631 	// third parties.
       
   632 {
       
   633 	void *result;
       
   634 	
       
   635 	MoreAssertQ(fragToFix != nil);
       
   636 	MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
       
   637 	
       
   638 	switch (sectionIndex) {
       
   639 		case 0:
       
   640 			result = fragToFix->section0Base;
       
   641 			break;
       
   642 		case 1:
       
   643 			result = fragToFix->section1Base;
       
   644 			break;
       
   645 		default:
       
   646 			result = nil;
       
   647 			break;
       
   648 	}
       
   649 	return result;
       
   650 }
       
   651 
       
   652 
       
   653 static OSStatus FindImportLibrary(PEFLoaderInfoHeader *loaderSection, const char *libraryName, PEFImportedLibrary **importLibrary)
       
   654 	// This routine finds the import library description (PEFImportedLibrary)
       
   655 	// for the import library libraryName in the PEF loader section.
       
   656 	// It sets *importLibrary to the address of the description.
       
   657 {
       
   658 	OSStatus 			err;
       
   659 	UInt32 				librariesRemaining;
       
   660 	PEFImportedLibrary 	*thisImportLibrary;
       
   661 	Boolean 			found;
       
   662 	
       
   663 	MoreAssertQ(loaderSection != nil);
       
   664 	MoreAssertQ(libraryName != nil);
       
   665 	MoreAssertQ(importLibrary != nil);
       
   666 	
       
   667 	// Loop through each import library looking for a matching name.
       
   668 	
       
   669 	// Initialise thisImportLibrary to point to the byte after the
       
   670 	// end of the loader section's header.
       
   671 	
       
   672 	thisImportLibrary = (PEFImportedLibrary *) (loaderSection + 1);
       
   673 	librariesRemaining = loaderSection->importedLibraryCount;
       
   674 	found = false;
       
   675 	while ( librariesRemaining > 0 && ! found ) {
       
   676 		// PEF defines that import library names will have
       
   677 		// a null terminator, so we can just use strcmp.
       
   678 		found = (strcmp( libraryName,
       
   679 						((char *)loaderSection)
       
   680 						+ loaderSection->loaderStringsOffset 
       
   681 						+ thisImportLibrary->nameOffset) == 0);
       
   682 		// *** Remove ANSI strcmp eventually.
       
   683 		if ( ! found ) {
       
   684 			thisImportLibrary += 1;
       
   685 			librariesRemaining -= 1;
       
   686 		}
       
   687 	}
       
   688 	
       
   689 	if (found) {
       
   690 		*importLibrary = thisImportLibrary;
       
   691 		err = noErr;
       
   692 	} else {
       
   693 		*importLibrary = nil;
       
   694 		err = cfragNoLibraryErr;
       
   695 	}
       
   696 	return err;
       
   697 }
       
   698 
       
   699 static OSStatus LookupSymbol(CFMLateImportLookupProc lookup, void *refCon,
       
   700 							PEFLoaderInfoHeader *loaderSection,
       
   701 							UInt32 symbolIndex,
       
   702 							UInt32 *symbolValue)
       
   703 	// This routine is used to look up a symbol during relocation.
       
   704 	// "lookup" is a client callback and refCon is its argument.
       
   705 	// Typically refCon is the CFM connection to the library that is
       
   706 	// substituting for the weak linked library.  loaderSection
       
   707 	// is a pointer to the loader section of the fragment to fix up.
       
   708 	// symbolIndex is the index of the imported symbol in the loader section.
       
   709 	// The routine sets the word pointed to by symbolValue to the
       
   710 	// value of the symbol.
       
   711 	//
       
   712 	// The routine works by using symbolIndex to index into the imported
       
   713 	// symbol table to find the offset of the symbol's name in the string
       
   714 	// table.  It then looks up the symbol by calling the client's "lookup"
       
   715 	// function and passes the resulting symbol address back in symbolValue.
       
   716 {
       
   717 	OSStatus 			err;
       
   718 	UInt32 				*importSymbolTable;
       
   719 	UInt32 				symbolStringOffset;
       
   720 	Boolean 			symbolIsWeak;
       
   721 	CFragSymbolClass 	symbolClass;
       
   722 	char 				*symbolStringAddress;
       
   723 	Str255 				symbolString;
       
   724 	
       
   725 	MoreAssertQ(lookup != nil);
       
   726 	MoreAssertQ(loaderSection != nil);
       
   727 	MoreAssertQ(symbolIndex < loaderSection->totalImportedSymbolCount);
       
   728 	MoreAssertQ(symbolValue != nil);
       
   729 	
       
   730 	// Find the base of the imported symbol table.
       
   731 	
       
   732 	importSymbolTable = (UInt32 *)(((char *)(loaderSection + 1)) + (loaderSection->importedLibraryCount * sizeof(PEFImportedLibrary)));
       
   733 	
       
   734 	// Grab the appropriate entry out of the table and
       
   735 	// extract the information from that entry.
       
   736 	
       
   737 	symbolStringOffset = importSymbolTable[symbolIndex];
       
   738 	symbolClass = PEFImportedSymbolClass(symbolStringOffset);
       
   739 	symbolIsWeak = ((symbolClass & kPEFWeakImportSymMask) != 0);
       
   740 	symbolClass = symbolClass & ~kPEFWeakImportSymMask;
       
   741 	symbolStringOffset = PEFImportedSymbolNameOffset(symbolStringOffset);
       
   742 	
       
   743 	// Find the string for the symbol in the strings table and
       
   744 	// extract it from the table into a Pascal string on the stack.
       
   745 	
       
   746 	symbolStringAddress = ((char *)loaderSection) + loaderSection->loaderStringsOffset + symbolStringOffset;
       
   747 	symbolString[0] = strlen(symbolStringAddress);		// *** remove ANSI strlen
       
   748 	BlockMoveData(symbolStringAddress, &symbolString[1], symbolString[0]);
       
   749 	
       
   750 	// Look up the symbol in substitute library.  If it fails, return
       
   751 	// a 0 value and check whether the error is fatal (a strong linked
       
   752 	// symbol) or benign (a weak linked symbol).
       
   753 	
       
   754 	err = lookup(symbolString, symbolClass, (void **) symbolValue, refCon);
       
   755 	if (err != noErr) {
       
   756 		*symbolValue = 0;
       
   757 		if (symbolIsWeak) {
       
   758 			err = noErr;
       
   759 		}
       
   760 	}
       
   761 	return err;
       
   762 }
       
   763 
       
   764 // The EngineState structure encapsulates all of the persistent state
       
   765 // of the CFM relocation engine virtual machine.  I originally defined
       
   766 // this structure so I could pass the state around between routines
       
   767 // that implement various virtual opcodes, however I later worked
       
   768 // out that the relocation was sufficiently simple that I could put it
       
   769 // in in one routine.  Still, I left the state in this structure in
       
   770 // case I ever need to reverse that decision.  It's also a convenient
       
   771 // instructional design.
       
   772 
       
   773 struct EngineState {
       
   774 	UInt32 currentReloc;		// Index of current relocation opcodes
       
   775 	UInt32 terminatingReloc;	// Index of relocation opcodes which terminates relocation
       
   776 	UInt32 *sectionBase;		// Start of the section
       
   777 	UInt32 *relocAddress;		// Address within the section where the relocations are to be performed
       
   778 	UInt32 importIndex;			// Symbol index, which is used to access an imported symbol's address
       
   779 	void  *sectionC;			// Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses
       
   780 	void  *sectionD;			// Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses
       
   781 };
       
   782 typedef struct EngineState EngineState;
       
   783 
       
   784 // Note:
       
   785 // If I ever have to support the repeat opcodes, I'll probably
       
   786 // have to add a repeat counter to EngineState.
       
   787 
       
   788 static OSStatus InitEngineState(const FragToFixInfo *fragToFix,
       
   789 								UInt16 relocHeaderIndex,
       
   790 								EngineState *state)
       
   791 	// This routine initialises the engine state suitably for
       
   792 	// running the relocation opcodes for the section whose
       
   793 	// index is relocHeaderIndex.  relocHeaderIndex is not a
       
   794 	// a section number.  See the comment where it's used below
       
   795 	// for details.  The routine basically fills out all the fields
       
   796 	// in the EngineState structure as described by
       
   797 	// "Mac OS Runtime Architectures".
       
   798 {
       
   799 	OSStatus err;
       
   800 	PEFLoaderRelocationHeader *relocHeader;
       
   801 	
       
   802 	MoreAssertQ(fragToFix != nil);
       
   803 	MoreAssertQ(state != nil);
       
   804 
       
   805 	// This bit is tricky.  relocHeaderIndex is an index into the relocation
       
   806 	// header table, starting at relocSectionCount (which is in the loader
       
   807 	// section header) for the first relocated section and decrementing
       
   808 	// down to 1 for the last relocated section.  I find the relocation
       
   809 	// header by using relocHeaderIndex as a index backwards from the
       
   810 	// start of the relocation opcodes (ie relocInstrOffset).  If you
       
   811 	// look at the diagram of the layout of the container in
       
   812 	// "PEFBinaryFormat.h", you'll see that the relocation opcodes
       
   813 	// immediately follow the relocation headers.
       
   814 	//
       
   815 	// I did this because the alternative (starting at the loader
       
   816 	// header and stepping past the import library table and the
       
   817 	// import symbol table) was a pain.
       
   818 
       
   819 	relocHeader = (PEFLoaderRelocationHeader *) (((char *) fragToFix->loaderSection) + fragToFix->loaderSection->relocInstrOffset - relocHeaderIndex * sizeof(PEFLoaderRelocationHeader));
       
   820 	
       
   821 	MoreAssertQ(relocHeader->reservedA == 0);		// PEF spec says it must be; we check to try to catch bugs in calculation of relocHeader
       
   822 	
       
   823 	state->currentReloc = relocHeader->firstRelocOffset;
       
   824 	state->terminatingReloc = relocHeader->firstRelocOffset + relocHeader->relocCount;
       
   825 	state->sectionBase = (UInt32 *) GetSectionBaseAddress(fragToFix, relocHeader->sectionIndex);
       
   826 	state->relocAddress = state->sectionBase;
       
   827 	state->importIndex = 0;
       
   828 
       
   829 	// From "Mac OS Runtime Architectures":
       
   830 	//
       
   831 	// The sectionC and sectionD variables actually contain the
       
   832 	// memory address of an instantiated section minus the
       
   833 	// default address for that section. The default address for a
       
   834 	// section is contained in the defaultAddress field of the
       
   835 	// section header. However, in almost all cases the default
       
   836 	// address should be 0, so the simplified definition suffices.
       
   837 	// 
       
   838 	// In the debug version, we drop into MacsBug if this weird case
       
   839 	// ever executes because it's more likely we made a mistake than
       
   840 	// we encountered a section with a default address.
       
   841 
       
   842 	state->sectionC = GetSectionBaseAddress(fragToFix, 0);
       
   843 	if (state->sectionC != nil) {
       
   844 		#if MORE_DEBUG
       
   845 			if (fragToFix->sectionHeaders[0].defaultAddress != 0) {
       
   846 				DebugStr("\pInitEngineState: Executing weird case.");
       
   847 			}
       
   848 		#endif
       
   849 		(char *) state->sectionC -= fragToFix->sectionHeaders[0].defaultAddress;
       
   850 	}
       
   851 	state->sectionD = GetSectionBaseAddress(fragToFix, 1);
       
   852 	if (state->sectionD != nil) {
       
   853 		#if MORE_DEBUG
       
   854 			if (fragToFix->sectionHeaders[1].defaultAddress != 0) {
       
   855 				DebugStr("\pInitEngineState: Executing weird case.");
       
   856 			}
       
   857 		#endif
       
   858 		(char *) state->sectionD -= fragToFix->sectionHeaders[1].defaultAddress;
       
   859 	}
       
   860 
       
   861 	err = noErr;
       
   862 	if (state->relocAddress == nil) {
       
   863 		err = cfragFragmentUsageErr;
       
   864 	}
       
   865 	return err;
       
   866 }
       
   867 
       
   868 // kPEFRelocBasicOpcodes is a table that maps the top 7 bits of the opcode
       
   869 // to a fundamental action.  It's contents are defined for me in "PEFBinaryFormat.h",
       
   870 // which is really convenient.
       
   871 
       
   872 static UInt8 kPEFRelocBasicOpcodes[kPEFRelocBasicOpcodeRange] = { PEFMaskedBasicOpcodes };
       
   873 
       
   874 static OSStatus RunRelocationEngine(const FragToFixInfo *fragToFix, 
       
   875 										PEFImportedLibrary  *importLibrary, 
       
   876 										CFMLateImportLookupProc lookup, void *refCon)
       
   877 	// This is where the rubber really hits the.  Given a fully
       
   878 	// populated fragToFix structure, the import library description
       
   879 	// of the weak imported library we're resolving, and a connection
       
   880 	// to the library we're going to substitute it, re-execute the
       
   881 	// relocation instructions (CFM has already executed them once)
       
   882 	// but only *do* instructions (ie store the change to the data section)
       
   883 	// that CFM skipped because the weak symbols were missing.
       
   884 {
       
   885 	OSStatus 	err;
       
   886 	EngineState	state;
       
   887 	UInt16 		sectionsLeftToRelocate;
       
   888 	UInt32 		totalRelocs;
       
   889 	UInt16		*relocInstrTable;
       
   890 	UInt16 		opCode;
       
   891 	
       
   892 	MoreAssertQ(fragToFix != nil);
       
   893 	MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
       
   894 	MoreAssertQ(fragToFix->sectionHeaders != nil);
       
   895 	MoreAssertQ(fragToFix->loaderSection != nil);
       
   896 	MoreAssertQ(fragToFix->section0Base != nil);	// Technically, having a nil for these two is not a problem, ...
       
   897 	MoreAssertQ(fragToFix->section1Base != nil);	// but in practise it a wildly deviant case and we should know about it.
       
   898 	MoreAssertQ(importLibrary != nil);
       
   899 	MoreAssertQ(lookup != nil);
       
   900 
       
   901 	// Before entering the loop, work out some information in advance.
       
   902 
       
   903 	// totalRelocs is only used for debugging, to make sure our
       
   904 	// relocation PC (state.currentReloc) doesn't run wild.
       
   905 	
       
   906 	totalRelocs = (fragToFix->loaderSection->loaderStringsOffset - fragToFix->loaderSection->relocInstrOffset) / sizeof(UInt16);
       
   907 	
       
   908 	// relocInstrTable is the base address of the table of relocation
       
   909 	// instructions in the fragment to fix.
       
   910 	
       
   911 	relocInstrTable = (UInt16 *)((char *) fragToFix->loaderSection + fragToFix->loaderSection->relocInstrOffset);
       
   912 	
       
   913 	// sectionsLeftToRelocate is the loop counter for the outer loop.
       
   914 	
       
   915 	MoreAssertQ(fragToFix->loaderSection->relocSectionCount <= 0x0FFFF);
       
   916 	sectionsLeftToRelocate = fragToFix->loaderSection->relocSectionCount;
       
   917 
       
   918 	// Now let's run the relocation engine.  We run it once per
       
   919 	// section in the table.  Each time around, we init the engine
       
   920 	// and then loop again, this time executing individual opcodes.
       
   921 	// The opcode loop terminates when the relocation PC
       
   922 	// (state.currentReloc) hits the final opcode (state.terminatingReloc).
       
   923 	
       
   924 	// Note:
       
   925 	// One design decision I made was to totally re-init the engine state
       
   926 	// for each section.  The CFM spec is unclear as to whether you're supposed
       
   927 	// to totally re-init the engine state, or just re-init the section-specific
       
   928 	// state (ie currentReloc, terminatingReloc, and relocAddress).  I hope this
       
   929 	// is correct, but it's hard to test without having a fragment with multiple
       
   930 	// relocated sections, which is difficult to create.
       
   931 	
       
   932 	// How do I decide which opcodes should be effective (ie make changes to
       
   933 	// the section being relocated) and which opcodes should just be executed
       
   934 	// for their side effects (ie updated state.relocAddress or state.importIndex)?
       
   935 	// The answer is both simple and subtle.  Opcodes whose actions are dependent
       
   936 	// on a symbol that was in the weak linked library are effective, those that
       
   937 	// an independent of those symbols are not.  The only opcodes that use
       
   938 	// symbolic values are kPEFRelocImportRun and kPEFRelocSmByImport, and
       
   939 	// these are only if the symbol is in the weak linked library.
       
   940 	// All other cases are executed for their side effects only.
       
   941 	//
       
   942 	// How do I determine if a symbol is in the weak linked library?
       
   943 	// Well I know the symbol's index and I know the lower bound and count
       
   944 	// of the symbols in the weak linked library, so I just do a simple
       
   945 	// bounds test, ie 
       
   946 	//
       
   947 	//   firstImportedSymbol <= importIndex < firstImportedSymbol + importedSymbolCount
       
   948 
       
   949 	// From this code, it's relatively easy to see which relocation opcodes
       
   950 	// aren't implemented.  If you ever encounter one, you'll find yourself
       
   951 	// in MacsBug with a message telling you which opcode was found.  The
       
   952 	// two big groups of opcodes I skipped were the large format opcodes
       
   953 	// and the repeating opcodes.  I skipped them because:
       
   954 	//
       
   955 	// a) I haven't got a way to generate them in a PEF container that I can 
       
   956 	//    test against. Without that, there's no way I could be assured that
       
   957 	//    the code worked.
       
   958 	//
       
   959 	// b) I'm lazy.
       
   960 
       
   961 	err = noErr;
       
   962 	while ( sectionsLeftToRelocate > 0 ) {
       
   963 		err = InitEngineState(fragToFix, sectionsLeftToRelocate, &state);
       
   964 		if (err != noErr) {
       
   965 			goto leaveNow;
       
   966 		}
       
   967 		
       
   968 		while ( state.currentReloc != state.terminatingReloc ) {
       
   969 			
       
   970 			MoreAssertQ( state.currentReloc < totalRelocs );
       
   971 
       
   972 			opCode = relocInstrTable[state.currentReloc];
       
   973 			switch ( PEFRelocBasicOpcode(opCode) ) {
       
   974 				case kPEFRelocBySectDWithSkip:
       
   975 					{
       
   976 						UInt16 skipCount;
       
   977 						UInt16 relocCount;
       
   978 						
       
   979 						skipCount = ((opCode >> 6) & 0x00FF);
       
   980 						relocCount = (opCode & 0x003F);
       
   981 						state.relocAddress += skipCount;
       
   982 						state.relocAddress += relocCount;
       
   983 					}
       
   984 					break;
       
   985 				case kPEFRelocBySectC:
       
   986 				case kPEFRelocBySectD:
       
   987 					{
       
   988 						UInt16 runLength;
       
   989 
       
   990 						runLength = (opCode & 0x01FF) + 1;
       
   991 						state.relocAddress += runLength;
       
   992 					}
       
   993 					break;
       
   994 				case kPEFRelocTVector12:
       
   995 					{
       
   996 						UInt16 runLength;
       
   997 
       
   998 						runLength = (opCode & 0x01FF) + 1;
       
   999 						state.relocAddress += (runLength * 3);
       
  1000 					}
       
  1001 					break;
       
  1002 				case kPEFRelocTVector8:
       
  1003 				case kPEFRelocVTable8:
       
  1004 					{
       
  1005 						UInt16 runLength;
       
  1006 
       
  1007 						runLength = (opCode & 0x01FF) + 1;
       
  1008 						state.relocAddress += (runLength * 2);
       
  1009 					}
       
  1010 					break;
       
  1011 				case kPEFRelocImportRun:
       
  1012 					{
       
  1013 						UInt32 symbolValue;
       
  1014 						UInt16 runLength;
       
  1015 						
       
  1016 						runLength = (opCode & 0x01FF) + 1;
       
  1017 						while (runLength > 0) {
       
  1018 							if ( state.importIndex >= importLibrary->firstImportedSymbol && state.importIndex < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
       
  1019 								err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, state.importIndex, &symbolValue);
       
  1020 								if (err != noErr) {
       
  1021 									goto leaveNow;
       
  1022 								}
       
  1023 								*(state.relocAddress) += symbolValue;
       
  1024 							}
       
  1025 							state.importIndex += 1;
       
  1026 							state.relocAddress += 1;
       
  1027 							runLength -= 1;
       
  1028 						}
       
  1029 					}
       
  1030 					break;
       
  1031 				case kPEFRelocSmByImport:
       
  1032 					{
       
  1033 						UInt32 symbolValue;
       
  1034 						UInt32 index;
       
  1035 
       
  1036 						index = (opCode & 0x01FF);
       
  1037 						if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
       
  1038 							err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue);
       
  1039 							if (err != noErr) {
       
  1040 								goto leaveNow;
       
  1041 							}
       
  1042 							*(state.relocAddress) += symbolValue;
       
  1043 						}
       
  1044 						state.importIndex = index + 1;
       
  1045 						state.relocAddress += 1;
       
  1046 					}
       
  1047 					break;
       
  1048 				case kPEFRelocSmSetSectC:
       
  1049 					{
       
  1050 						UInt32 index;
       
  1051 
       
  1052 						index = (opCode & 0x01FF);
       
  1053 						state.sectionC = GetSectionBaseAddress(fragToFix, index);
       
  1054 						MoreAssertQ(state.sectionC != nil);
       
  1055 					}
       
  1056 					break;
       
  1057 				case kPEFRelocSmSetSectD:
       
  1058 					{
       
  1059 						UInt32 index;
       
  1060 
       
  1061 						index = (opCode & 0x01FF);
       
  1062 						state.sectionD = GetSectionBaseAddress(fragToFix, index);
       
  1063 						MoreAssertQ(state.sectionD != nil);
       
  1064 					}
       
  1065 					break;
       
  1066 				case kPEFRelocSmBySection:
       
  1067 					state.relocAddress += 1;
       
  1068 					break;
       
  1069 				case kPEFRelocIncrPosition:
       
  1070 					{
       
  1071 						UInt16 offset;
       
  1072 						
       
  1073 						offset = (opCode & 0x0FFF) + 1;
       
  1074 						((char *) state.relocAddress) += offset;
       
  1075 					}
       
  1076 					break;
       
  1077 				case kPEFRelocSmRepeat:
       
  1078 					#if MORE_DEBUG
       
  1079 						DebugStr("\pRunRelocationEngine: kPEFRelocSmRepeat not yet implemented");
       
  1080 					#endif
       
  1081 					err = unimpErr;
       
  1082 					goto leaveNow;
       
  1083 					break;
       
  1084 				case kPEFRelocSetPosition:
       
  1085 					{
       
  1086 						UInt32 offset;
       
  1087 
       
  1088 						// Lot's of folks have tried various interpretations of the description of 
       
  1089 						// this opCode in "Mac OS Runtime Architectures" (which states "This instruction 
       
  1090 						// sets relocAddress to the address of the section offset offset."  *smile*).
       
  1091 						// I eventually dug into the CFM source code to find my interpretation, which 
       
  1092 						// I believe is correct.  The key point is tht the offset is relative to 
       
  1093 						// the start of the section for which these relocations are being performed.
       
  1094 						
       
  1095 						// Skip to next reloc word, which is the second chunk of the offset.
       
  1096 						
       
  1097 						state.currentReloc += 1;
       
  1098 						
       
  1099 						// Extract offset based on the most significant 10 bits in opCode and 
       
  1100 						// the next significant 16 bits in the next reloc word.
       
  1101 						
       
  1102 						offset = PEFRelocSetPosFullOffset(opCode, relocInstrTable[state.currentReloc]);
       
  1103 
       
  1104 						state.relocAddress = (UInt32 *) ( ((char *) state.sectionBase) + offset);
       
  1105 					}
       
  1106 					break;
       
  1107 				case kPEFRelocLgByImport:
       
  1108 					{
       
  1109 						UInt32 symbolValue;
       
  1110 						UInt32 index;
       
  1111 
       
  1112 						// Get the 26 bit symbol index from the current and next reloc words.
       
  1113 						
       
  1114 						state.currentReloc += 1;
       
  1115 						index = PEFRelocLgByImportFullIndex(opCode, relocInstrTable[state.currentReloc]);
       
  1116 						
       
  1117 						if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
       
  1118 							err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue);
       
  1119 							if (err != noErr) {
       
  1120 								goto leaveNow;
       
  1121 							}
       
  1122 							*(state.relocAddress) += symbolValue;
       
  1123 						}
       
  1124 						state.importIndex = index + 1;
       
  1125 						state.relocAddress += 1;
       
  1126 					}
       
  1127 					break;
       
  1128 				case kPEFRelocLgRepeat:
       
  1129 					#if MORE_DEBUG
       
  1130 						DebugStr("\pRunRelocationEngine: kPEFRelocLgRepeat not yet implemented");
       
  1131 					#endif
       
  1132 					err = unimpErr;
       
  1133 					goto leaveNow;
       
  1134 					break;
       
  1135 				case kPEFRelocLgSetOrBySection:
       
  1136 					#if MORE_DEBUG
       
  1137 						DebugStr("\pRunRelocationEngine: kPEFRelocLgSetOrBySection not yet implemented");
       
  1138 					#endif
       
  1139 					err = unimpErr;
       
  1140 					goto leaveNow;
       
  1141 					break;
       
  1142 				case kPEFRelocUndefinedOpcode:
       
  1143 					err = cfragFragmentCorruptErr;
       
  1144 					goto leaveNow;
       
  1145 					break;
       
  1146 				default:
       
  1147 					MoreAssertQ(false);
       
  1148 					err = cfragFragmentCorruptErr;
       
  1149 					goto leaveNow;
       
  1150 					break;
       
  1151 			}
       
  1152 			state.currentReloc += 1;
       
  1153 		}
       
  1154 		
       
  1155 		sectionsLeftToRelocate -= 1;
       
  1156 	}
       
  1157 
       
  1158 leaveNow:
       
  1159 	return err;
       
  1160 }
       
  1161 
       
  1162 extern pascal OSStatus CFMLateImportCore(const CFragSystem7DiskFlatLocator *fragToFixLocator,
       
  1163 										CFragConnectionID fragToFixConnID,
       
  1164 										CFragInitFunction fragToFixInitRoutine,
       
  1165 										ConstStr255Param weakLinkedLibraryName,
       
  1166 										CFMLateImportLookupProc lookup,
       
  1167 										void *refCon)
       
  1168 	// See comments in interface part.
       
  1169 {
       
  1170 	OSStatus err;
       
  1171 	OSStatus junk;
       
  1172 	FragToFixInfo fragToFix;
       
  1173 	PEFImportedLibrary *importLibrary;
       
  1174 	char weakLinkedLibraryNameCString[256];
       
  1175 
       
  1176 	MoreAssertQ(fragToFixLocator != nil);	
       
  1177 	MoreAssertQ(fragToFixConnID != nil);
       
  1178 	MoreAssertQ(fragToFixInitRoutine != nil);
       
  1179 	MoreAssertQ(weakLinkedLibraryName != nil);	
       
  1180 	MoreAssertQ(lookup != nil);	
       
  1181 	
       
  1182 	// Fill out the bits of fragToFix which are passed in
       
  1183 	// by the client.
       
  1184 	
       
  1185 	MoreBlockZero(&fragToFix, sizeof(fragToFix));
       
  1186 	fragToFix.locator = *fragToFixLocator;
       
  1187 	fragToFix.connID  = fragToFixConnID;
       
  1188 	fragToFix.initRoutine = fragToFixInitRoutine;
       
  1189 	
       
  1190 	// Make a C string from weakLinkedLibraryName.
       
  1191 	
       
  1192 	BlockMoveData(weakLinkedLibraryName + 1, weakLinkedLibraryNameCString, weakLinkedLibraryName[0]);
       
  1193 	weakLinkedLibraryNameCString[weakLinkedLibraryName[0]] = 0;
       
  1194 
       
  1195 	// Get the basic information from the fragment.
       
  1196 	// Fills out the containerHeader, sectionHeaders, loaderSection and fileRef fields
       
  1197 	// of fragToFix.
       
  1198 	
       
  1199 	err = ReadContainerBasics(&fragToFix);
       
  1200 
       
  1201 	// Set up the base address fields in fragToFix (ie section0Base and section1Base)
       
  1202 	// by looking up our init routine (fragToFix.initRoutine) and subtracting
       
  1203 	// away the section offsets (which we get from the disk copy of the section)
       
  1204 	// to derive the bases of the sections themselves.
       
  1205 	
       
  1206 	if (err == noErr) {
       
  1207 		err = SetupSectionBaseAddresses(&fragToFix);
       
  1208 	}
       
  1209 	
       
  1210 	// Look inside the loader section for the import library description
       
  1211 	// of weakLinkedLibraryName.  We need this to know the range of symbol
       
  1212 	// indexes we're going to fix up.
       
  1213 	
       
  1214 	if (err == noErr) {
       
  1215 		err = FindImportLibrary(fragToFix.loaderSection, weakLinkedLibraryNameCString, &importLibrary);
       
  1216 	}
       
  1217 	
       
  1218 	// Do a quick check to ensure that the library was actually imported weak.
       
  1219 	// If it wasn't, it doesn't make much sense to resolve its weak imports
       
  1220 	// later on.  Resolving them again is likely to be bad.
       
  1221 	
       
  1222 	if (err == noErr) {
       
  1223 		if ((importLibrary->options & kPEFWeakImportLibMask) == 0) {
       
  1224 			err = cfragFragmentUsageErr;
       
  1225 		}
       
  1226 	}
       
  1227 	
       
  1228 	// Now run the main relocation engine.
       
  1229 	
       
  1230 	if (err == noErr) {
       
  1231 		err = RunRelocationEngine(&fragToFix, importLibrary, lookup, refCon);
       
  1232 	}
       
  1233 	
       
  1234 	// Clean up.
       
  1235 	
       
  1236 	if (fragToFix.disposeSectionPointers) {
       
  1237 		if (fragToFix.fileRef != 0) {
       
  1238 			junk = FSClose(fragToFix.fileRef);
       
  1239 			MoreAssertQ(junk == noErr);
       
  1240 		}
       
  1241 		if (fragToFix.loaderSection != nil) {
       
  1242 			DisposePtr( (Ptr) fragToFix.loaderSection);
       
  1243 			MoreAssertQ(MemError() == noErr);
       
  1244 		}
       
  1245 		if (fragToFix.sectionHeaders != nil) {
       
  1246 			DisposePtr( (Ptr) fragToFix.sectionHeaders);
       
  1247 			MoreAssertQ(MemError() == noErr);
       
  1248 		}
       
  1249 	}
       
  1250 	return err;
       
  1251 }
       
  1252 
       
  1253 static pascal OSStatus FragmentLookup(ConstStr255Param symName, CFragSymbolClass symClass,
       
  1254 									void **symAddr, void *refCon)
       
  1255 	// This is the CFMLateImportLookupProc callback used when 
       
  1256 	// late importing from a CFM shared library.
       
  1257 {
       
  1258 	OSStatus err;
       
  1259 	CFragConnectionID connIDToImport;
       
  1260 	CFragSymbolClass  foundSymClass;
       
  1261 	
       
  1262 	MoreAssertQ(symName != nil);
       
  1263 	MoreAssertQ(symAddr != nil);
       
  1264 	MoreAssertQ(refCon  != nil);
       
  1265 	
       
  1266 	connIDToImport = (CFragConnectionID) refCon;
       
  1267 	
       
  1268 	// Shame there's no way to validate that connIDToImport is valid.
       
  1269 
       
  1270 	err = FindSymbol(connIDToImport, symName, (Ptr *) symAddr, &foundSymClass);
       
  1271 	if (err == noErr) {
       
  1272 		// If the symbol isn't of the right class, we act like we didn't 
       
  1273 		// find it, but also assert in the debug build because weird things 
       
  1274 		// are afoot.
       
  1275 		if (foundSymClass != symClass) {
       
  1276 			MoreAssertQ(false);
       
  1277 			*symAddr = nil;
       
  1278 			err = cfragNoSymbolErr;
       
  1279 		}
       
  1280 	}
       
  1281 	return err;
       
  1282 }
       
  1283 
       
  1284 extern pascal OSStatus CFMLateImportLibrary(const CFragSystem7DiskFlatLocator *fragToFixLocator,
       
  1285 										CFragConnectionID fragToFixConnID,
       
  1286 										CFragInitFunction fragToFixInitRoutine,
       
  1287 										ConstStr255Param weakLinkedLibraryName,
       
  1288 										CFragConnectionID connIDToImport)
       
  1289 	// See comments in interface part.
       
  1290 {
       
  1291 	MoreAssertQ(connIDToImport != nil);
       
  1292 	return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
       
  1293 										weakLinkedLibraryName, FragmentLookup, connIDToImport);
       
  1294 }
       
  1295 
       
  1296 static pascal OSStatus BundleLookup(ConstStr255Param symName, CFragSymbolClass symClass,
       
  1297 									void **symAddr, void *refCon)
       
  1298 	// This is the CFMLateImportLookupProc callback used when 
       
  1299 	// late importing from a CFBundle.
       
  1300 {
       
  1301 	OSStatus 	err;
       
  1302 	CFBundleRef bundleToImport;
       
  1303 	CFStringRef symNameStr;
       
  1304 	
       
  1305 	MoreAssertQ(symName != nil);
       
  1306 	MoreAssertQ(symAddr != nil);
       
  1307 	MoreAssertQ(refCon  != nil);
       
  1308 	
       
  1309 	symNameStr = nil;
       
  1310 	
       
  1311 	bundleToImport = (CFBundleRef) refCon;
       
  1312 	
       
  1313 	// Shame there's no way to validate that bundleToImport is really a bundle.
       
  1314 	
       
  1315 	// We can only find function pointers because CFBundleGetFunctionPointerForName 
       
  1316 	// only works for function pointers.  So if the client is asking for something 
       
  1317 	// other than a function pointer (ie TVector symbol) then we don't even true.
       
  1318 	// Also assert in the debug build because this shows a certain lack of 
       
  1319 	// understanding on the part of the client.
       
  1320 	//
       
  1321 	// CF is being revise to support accessing data symbols using a new API
       
  1322 	// (currently this is available to Apple internal developers as 
       
  1323 	// CFBundleGetDataPointerForName).  When the new API is available in a 
       
  1324 	// public header file I should revise this code to lift this restriction.
       
  1325 	
       
  1326 	err = noErr;
       
  1327 	if (symClass != kTVectorCFragSymbol) {
       
  1328 		MoreAssertQ(false);
       
  1329 		err = cfragNoSymbolErr;
       
  1330 	}
       
  1331 	if (err == noErr) {
       
  1332 		symNameStr = CFStringCreateWithPascalString(kCFAllocatorSystemDefault, 
       
  1333 													symName, kCFStringEncodingMacRoman);
       
  1334 		if (symNameStr == nil) {
       
  1335 			err = coreFoundationUnknownErr;
       
  1336 		}
       
  1337 	}
       
  1338 	if (err == noErr) {
       
  1339 		*symAddr = CFBundleGetFunctionPointerForName(bundleToImport, symNameStr);
       
  1340 		if (*symAddr == nil) {
       
  1341 			err = cfragNoSymbolErr;
       
  1342 		}
       
  1343 	}
       
  1344 	if (symNameStr != nil) {
       
  1345 		CFRelease(symNameStr);
       
  1346 	}
       
  1347 	return err;
       
  1348 }
       
  1349 
       
  1350 extern pascal OSStatus CFMLateImportBundle(const CFragSystem7DiskFlatLocator *fragToFixLocator,
       
  1351 										CFragConnectionID fragToFixConnID,
       
  1352 										CFragInitFunction fragToFixInitRoutine,
       
  1353 										ConstStr255Param weakLinkedLibraryName,
       
  1354 										CFBundleRef bundleToImport)
       
  1355 	// See comments in interface part.
       
  1356 {
       
  1357 	MoreAssertQ(bundleToImport != nil);
       
  1358 	return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
       
  1359 										weakLinkedLibraryName, BundleLookup, bundleToImport);
       
  1360 }