• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FSReadAtOffset(SInt16 refNum,SInt32 offset,SInt32 count,void * buffer)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 
ReadContainerBasics(FragToFixInfo * fragToFix)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 
DecodeVCountValue(const UInt8 * start,UInt32 * outCount)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 
DecodeInstrCountValue(const UInt8 * inOpStart,UInt32 * outCount)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 
UnpackPEFDataSection(const UInt8 * const packedData,UInt32 packedSize,UInt8 * const unpackedData,UInt32 unpackedSize)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 
SetupSectionBaseAddresses(FragToFixInfo * fragToFix)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 
GetSectionBaseAddress(const FragToFixInfo * fragToFix,UInt16 sectionIndex)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 
FindImportLibrary(PEFLoaderInfoHeader * loaderSection,const char * libraryName,PEFImportedLibrary ** importLibrary)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 
LookupSymbol(CFMLateImportLookupProc lookup,void * refCon,PEFLoaderInfoHeader * loaderSection,UInt32 symbolIndex,UInt32 * symbolValue)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 
InitEngineState(const FragToFixInfo * fragToFix,UInt16 relocHeaderIndex,EngineState * state)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 
RunRelocationEngine(const FragToFixInfo * fragToFix,PEFImportedLibrary * importLibrary,CFMLateImportLookupProc lookup,void * refCon)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 practice 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 
CFMLateImportCore(const CFragSystem7DiskFlatLocator * fragToFixLocator,CFragConnectionID fragToFixConnID,CFragInitFunction fragToFixInitRoutine,ConstStr255Param weakLinkedLibraryName,CFMLateImportLookupProc lookup,void * refCon)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 
FragmentLookup(ConstStr255Param symName,CFragSymbolClass symClass,void ** symAddr,void * refCon)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 
CFMLateImportLibrary(const CFragSystem7DiskFlatLocator * fragToFixLocator,CFragConnectionID fragToFixConnID,CFragInitFunction fragToFixInitRoutine,ConstStr255Param weakLinkedLibraryName,CFragConnectionID connIDToImport)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 
BundleLookup(ConstStr255Param symName,CFragSymbolClass symClass,void ** symAddr,void * refCon)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 
CFMLateImportBundle(const CFragSystem7DiskFlatLocator * fragToFixLocator,CFragConnectionID fragToFixConnID,CFragInitFunction fragToFixInitRoutine,ConstStr255Param weakLinkedLibraryName,CFBundleRef bundleToImport)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 }
1361