Home | History | Annotate | Download | only in cg
      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 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 
   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 }
   1361