summaryrefslogtreecommitdiffstats
path: root/Mac/Modules/cg/CFMLateImport.c
diff options
context:
space:
mode:
Diffstat (limited to 'Mac/Modules/cg/CFMLateImport.c')
-rwxr-xr-xMac/Modules/cg/CFMLateImport.c1360
1 files changed, 0 insertions, 1360 deletions
diff --git a/Mac/Modules/cg/CFMLateImport.c b/Mac/Modules/cg/CFMLateImport.c
deleted file mode 100755
index bc2976e..0000000
--- a/Mac/Modules/cg/CFMLateImport.c
+++ /dev/null
@@ -1,1360 +0,0 @@
-/*
- File: CFMLateImport.c
-
- Contains: Implementation of CFM late import library.
-
- Written by: Quinn
-
- Copyright: Copyright © 1999 by Apple Computer, Inc., all rights reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
-
- <13> 24/9/01 Quinn Fixes to compile with C++ activated.
- <12> 21/9/01 Quinn [2710489] Fix typo in the comments for FragmentLookup.
- <11> 21/9/01 Quinn Changes for CWPro7 Mach-O build.
- <10> 19/9/01 Quinn Corrected implementation of kPEFRelocSmBySection. Added
- implementations of kPEFRelocSetPosition and kPEFRelocLgByImport
- (from code contributed by Eric Grant, Ned Holbrook, and Steve
- Kalkwarf), although I can't test them yet.
- <9> 19/9/01 Quinn We now handle unpacked data sections, courtesy of some code from
- Ned Holbrook.
- <8> 19/9/01 Quinn Minor fixes for the previous checkin. Updated some comments and
- killed some dead code.
- <7> 19/9/01 Quinn Simplified API and implementation after a suggestion by Eric
- Grant. You no longer have to CFM export a dummy function; you
- can just pass in the address of your fragment's init routine.
- <6> 15/2/01 Quinn Modify compile-time warnings to complain if you try to build
- this module into a Mach-O binary.
- <5> 5/2/01 Quinn Removed redundant assignment in CFMLateImportCore.
- <4> 30/11/00 Quinn Added comment about future of data symbols in CF.
- <3> 16/11/00 Quinn Allow symbol finding via a callback and use that to implement
- CFBundle support.
- <2> 18/10/99 Quinn Renamed CFMLateImport to CFMLateImportLibrary to allow for
- possible future API expansion.
- <1> 15/6/99 Quinn First checked in.
-*/
-
-// To Do List:
-//
-// o get rid of dependence on ANSI "string.h", but how?
-//
-// Done:
-//
-// Ã investigate alternative APIs, like an external lookup routine
-// renamed CFMLateImport to CFMLateImportLibrary to allow for
-// future expansion of the APIs for things like CFMLateImportSymbol
-// Ã test with non-zero fragment offset in the file
-// Ã test more with MPW fragments
-// Ã test data imports
-
-/////////////////////////////////////////////////////////////////
-
-// MoreIsBetter Setup
-
-//#include "MoreSetup.h"
-#define MoreAssert(x) (true)
-#define MoreAssertQ(x)
-
-// Mac OS Interfaces
-
-#if ! MORE_FRAMEWORK_INCLUDES
- #include <CodeFragments.h>
- #include <PEFBinaryFormat.h>
-#endif
-
-// Standard C Interfaces
-
-#include <string.h>
-
-// MIB Prototypes
-
-//#include "MoreInterfaceLib.h"
-#define MoreBlockZero BlockZero
-
-// Our Prototypes
-
-#include "CFMLateImport.h"
-
-/////////////////////////////////////////////////////////////////
-
-#if TARGET_RT_MAC_MACHO
- #error CFMLateImport is not suitable for use in a Mach-O project.
-#elif !TARGET_RT_MAC_CFM || !TARGET_CPU_PPC
- #error CFMLateImport has not been qualified for 68K or CFM-68K use.
-#endif
-
-/////////////////////////////////////////////////////////////////
-#pragma mark ----- Utility Routines -----
-
-static OSStatus FSReadAtOffset(SInt16 refNum, SInt32 offset, SInt32 count, void *buffer)
- // A convenient wrapper around PBRead which has two advantages
- // over FSRead. First, it takes count as a value parameter.
- // Second, it reads from an arbitrary offset into the file,
- // which avoids a bunch of SetFPos calls.
- //
- // I guess this should go into "MoreFiles.h", but I'm not sure
- // how we're going to integrate such a concept into MIB yet.
-{
- ParamBlockRec pb;
-
- pb.ioParam.ioRefNum = refNum;
- pb.ioParam.ioBuffer = (Ptr) buffer;
- pb.ioParam.ioReqCount = count;
- pb.ioParam.ioPosMode = fsFromStart;
- pb.ioParam.ioPosOffset = offset;
-
- return PBReadSync(&pb);
-}
-
-/////////////////////////////////////////////////////////////////
-#pragma mark ----- Late Import Engine -----
-
-// This structure represents the core data structure of the late import
-// engine. It basically holds information about the fragment we're going
-// to fix up. It starts off with the first three fields, which are
-// provided by the client. Then, as we procede through the operation,
-// we fill out more fields.
-
-struct FragToFixInfo {
- CFragSystem7DiskFlatLocator locator; // How to find the fragment's container.
- CFragConnectionID connID; // CFM connection to the fragment.
- CFragInitFunction initRoutine; // The CFM init routine for the fragment.
- PEFContainerHeader containerHeader; // The CFM header, read in from the container.
- PEFSectionHeader *sectionHeaders; // The CFM section headers. A pointer block containing an array of containerHeader.sectionCount elements.
- PEFLoaderInfoHeader *loaderSection; // The entire CFM loader section in a pointer block.
- 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.
- void *section0Base; // The base address of section 0, which we go through hoops to calculate.
- void *section1Base; // The base address of section 1, which we go through hoops to calculate.
- Boolean disposeSectionPointers; // See below.
-};
-typedef struct FragToFixInfo FragToFixInfo;
-
-// The disposeSectionPointers Boolean is designed for future cool VM
-// support. If VM is on, the entire code fragment is file mapped into
-// high memory, including the data we're forced to allocate the
-// sectionHeaders and loaderSection memory blocks to maintain. If
-// we could find the address of the entire file mapped container,
-// we could access the information directly from there and thus
-// we wouldn't need to allocate (or dispose of) the memory blocks
-// for sectionHeaders and loaderSection.
-//
-// I haven't implemented this yet because a) I'm not sure how to do
-// it with documented APIs, and b) I couldn't be bothered, but
-// disposeSectionPointers remains as vestigial support for the concept.
-
-static OSStatus ReadContainerBasics(FragToFixInfo *fragToFix)
- // Reads some basic information from the container of the
- // fragment to fix and stores it in various fields of
- // fragToFix. This includes:
- //
- // o containerHeader -- The contain header itself.
- // o sectionHeaders -- The array of section headers (in a newly allocated pointer block).
- // o loaderSection -- The entire loader section (in a newly allocated pointer block).
- //
- // Also sets disposeSectionPointers to indicate whether
- // the last two pointers should be disposed of.
- //
- // Finally, it leaves the container file open for later
- // folks who want to read data from it.
-{
- OSStatus err;
- UInt16 sectionIndex;
- Boolean found;
-
- MoreAssertQ(fragToFix != nil);
- MoreAssertQ(fragToFix->locator.fileSpec != nil);
- MoreAssertQ(fragToFix->connID != nil);
- MoreAssertQ(fragToFix->loaderSection == nil);
- MoreAssertQ(fragToFix->sectionHeaders == nil);
- MoreAssertQ(fragToFix->fileRef == 0);
-
- fragToFix->disposeSectionPointers = true;
-
- // Open up the file, read the container head, then read in
- // all the section headers, then go looking through the
- // section headers for the loader section (PEF defines
- // that there can be only one).
-
- err = FSpOpenDF(fragToFix->locator.fileSpec, fsRdPerm, &fragToFix->fileRef);
- if (err == noErr) {
- err = FSReadAtOffset(fragToFix->fileRef,
- fragToFix->locator.offset,
- sizeof(fragToFix->containerHeader),
- &fragToFix->containerHeader);
- if (err == noErr) {
- if ( fragToFix->containerHeader.tag1 != kPEFTag1
- || fragToFix->containerHeader.tag2 != kPEFTag2
- || fragToFix->containerHeader.architecture != kCompiledCFragArch
- || fragToFix->containerHeader.formatVersion != kPEFVersion) {
- err = cfragFragmentFormatErr;
- }
- }
- if (err == noErr) {
- fragToFix->sectionHeaders = (PEFSectionHeader *) NewPtr(fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader));
- err = MemError();
- }
- if (err == noErr) {
- err = FSReadAtOffset(fragToFix->fileRef,
- fragToFix->locator.offset + sizeof(fragToFix->containerHeader),
- fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader),
- fragToFix->sectionHeaders);
- }
- if (err == noErr) {
- sectionIndex = 0;
- found = false;
- while ( sectionIndex < fragToFix->containerHeader.sectionCount && ! found ) {
- found = (fragToFix->sectionHeaders[sectionIndex].sectionKind == kPEFLoaderSection);
- if ( ! found ) {
- sectionIndex += 1;
- }
- }
- }
- if (err == noErr && ! found) {
- err = cfragNoSectionErr;
- }
-
- // Now read allocate a pointer block and read the loader section into it.
-
- if (err == noErr) {
- fragToFix->loaderSection = (PEFLoaderInfoHeader *) NewPtr(fragToFix->sectionHeaders[sectionIndex].containerLength);
- err = MemError();
- }
- if (err == noErr) {
- err = FSReadAtOffset(fragToFix->fileRef,
- fragToFix->locator.offset + fragToFix->sectionHeaders[sectionIndex].containerOffset,
- fragToFix->sectionHeaders[sectionIndex].containerLength,
- fragToFix->loaderSection);
- }
- }
-
- // No clean up. The client must init fragToFix to zeros and then
- // clean up regardless of whether we return an error.
-
- return err;
-}
-
-static UInt32 DecodeVCountValue(const UInt8 *start, UInt32 *outCount)
- // Given a pointer to the start of a variable length PEF value,
- // work out the value (in *outCount). Returns the number of bytes
- // consumed by the value.
-{
- UInt8 * bytePtr;
- UInt8 byte;
- UInt32 count;
-
- bytePtr = (UInt8 *)start;
-
- // Code taken from "PEFBinaryFormat.h".
- count = 0;
- do {
- byte = *bytePtr++;
- count = (count << kPEFPkDataVCountShift) | (byte & kPEFPkDataVCountMask);
- } while ((byte & kPEFPkDataVCountEndMask) != 0);
-
- *outCount = count;
- return bytePtr - start;
-}
-
-static UInt32 DecodeInstrCountValue(const UInt8 *inOpStart, UInt32 *outCount)
- // Given a pointer to the start of an opcode (inOpStart), work out the
- // count argument for that opcode (*outCount). Returns the number of
- // bytes consumed by the opcode and count combination.
-{
- MoreAssertQ(inOpStart != nil);
- MoreAssertQ(outCount != nil);
-
- if (PEFPkDataCount5(*inOpStart) != 0)
- {
- // Simple case, count encoded in opcode.
- *outCount = PEFPkDataCount5(*inOpStart);
- return 1;
- }
- else
- {
- // Variable-length case.
- return 1 + DecodeVCountValue(inOpStart + 1, outCount);
- }
-}
-
-static OSStatus UnpackPEFDataSection(const UInt8 * const packedData, UInt32 packedSize,
- UInt8 * const unpackedData, UInt32 unpackedSize)
-{
- OSErr err;
- UInt32 offset;
- UInt8 opCode;
- UInt8 * unpackCursor;
-
- MoreAssertQ(packedData != nil);
- MoreAssertQ(unpackedData != nil);
- MoreAssertQ(unpackedSize >= packedSize);
-
- // The following asserts assume that the client allocated the memory with NewPtr,
- // which may not always be true. However, the asserts' value in preventing accidental
- // memory block overruns outweighs the possible maintenance effort.
-
- MoreAssertQ( packedSize == GetPtrSize( (Ptr) packedData ) );
- MoreAssertQ( unpackedSize == GetPtrSize( (Ptr) unpackedData) );
-
- err = noErr;
- offset = 0;
- unpackCursor = unpackedData;
- while (offset < packedSize) {
- MoreAssertQ(unpackCursor < &unpackedData[unpackedSize]);
-
- opCode = packedData[offset];
-
- switch (PEFPkDataOpcode(opCode)) {
- case kPEFPkDataZero:
- {
- UInt32 count;
-
- offset += DecodeInstrCountValue(&packedData[offset], &count);
-
- MoreBlockZero(unpackCursor, count);
- unpackCursor += count;
- }
- break;
-
- case kPEFPkDataBlock:
- {
- UInt32 blockSize;
-
- offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
-
- BlockMoveData(&packedData[offset], unpackCursor, blockSize);
- unpackCursor += blockSize;
- offset += blockSize;
- }
- break;
-
- case kPEFPkDataRepeat:
- {
- UInt32 blockSize;
- UInt32 repeatCount;
- UInt32 loopCounter;
-
- offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
- offset += DecodeVCountValue(&packedData[offset], &repeatCount);
- repeatCount += 1; // stored value is (repeatCount - 1)
-
- for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
- BlockMoveData(&packedData[offset], unpackCursor, blockSize);
- unpackCursor += blockSize;
- }
- offset += blockSize;
- }
- break;
-
- case kPEFPkDataRepeatBlock:
- {
- UInt32 commonSize;
- UInt32 customSize;
- UInt32 repeatCount;
- const UInt8 *commonData;
- const UInt8 *customData;
- UInt32 loopCounter;
-
- offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
- offset += DecodeVCountValue(&packedData[offset], &customSize);
- offset += DecodeVCountValue(&packedData[offset], &repeatCount);
-
- commonData = &packedData[offset];
- customData = &packedData[offset + commonSize];
-
- for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
- BlockMoveData(commonData, unpackCursor, commonSize);
- unpackCursor += commonSize;
- BlockMoveData(customData, unpackCursor, customSize);
- unpackCursor += customSize;
- customData += customSize;
- }
- BlockMoveData(commonData, unpackCursor, commonSize);
- unpackCursor += commonSize;
- offset += (repeatCount * (commonSize + customSize)) + commonSize;
- }
- break;
-
- case kPEFPkDataRepeatZero:
- {
- UInt32 commonSize;
- UInt32 customSize;
- UInt32 repeatCount;
- const UInt8 *customData;
- UInt32 loopCounter;
-
- offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
- offset += DecodeVCountValue(&packedData[offset], &customSize);
- offset += DecodeVCountValue(&packedData[offset], &repeatCount);
-
- customData = &packedData[offset];
-
- for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
- MoreBlockZero(unpackCursor, commonSize);
- unpackCursor += commonSize;
- BlockMoveData(customData, unpackCursor, customSize);
- unpackCursor += customSize;
- customData += customSize;
- }
- MoreBlockZero(unpackCursor, commonSize);
- unpackCursor += commonSize;
- offset += repeatCount * customSize;
- }
- break;
-
- default:
- #if MORE_DEBUG
- DebugStr("\pUnpackPEFDataSection: Unexpected data opcode");
- #endif
- err = cfragFragmentCorruptErr;
- goto leaveNow;
- break;
- }
- }
-
-leaveNow:
- return err;
-}
-
-/* SetupSectionBaseAddresses Rationale
- -----------------------------------
-
- OK, here's where things get weird. In order to run the relocation
- engine, I need to be able to find the base address of an instantiated
- section of the fragment we're fixing up given only its section number.
- This isn't hard for CFM to do because it's the one that instantiated the
- sections in the first place. It's surprisingly difficult to do if
- you're not CFM. [And you don't have access to the private CFM APis for
- doing it.]
-
- [Alan Lillich is going to kill me when he reads this! I should point out
- that TVector's don't have to contain two words, they can be longer,
- and that the second word isn't necessarily a TOC pointer, it's
- just that the calling conventions require that it be put in the
- TOC register when the code is called.
-
- Furthermore, the code section isn't always section 0, and the data
- section isn't always section 1, and there can be zero to many sections
- of each type.
-
- But these niceties are besides the point: I'm doing something tricky
- because I don't have a nice API for getting section base addresses.
- If I had a nice API for doing that, none of this code would exist.
- ]
-
- The technique is very sneaky (thanks to Eric Grant). The fragment to
- fix necessarily has a CFM init routine (because it needs that routine
- in order to capture the fragment location and connection ID). Thus the
- fragment to fix must have a TVector in its data section. TVectors are
- interesting because they're made up of two words. The first is a pointer
- to the code that implements the routine; the second is a pointer to the TOC
- for the fragment that's exporting the TVector. How TVectors are
- created is interesting too. On disk, a TVector consists of two words,
- the first being the offset from the start of the code section to the
- routine, the second being the offset from the start of the data section
- to the TOC base. When CFM prepares a TVector, it applies the following
- transform:
-
- tvector.codePtr = tvector.codeOffset + base of code section
- tvector.tocPtr = tvector.tocOffset + base of data section
-
- Now, you can reverse these questions to make them:
-
- base of code section = tvector.codePtr - tvector.codeOffset
- base of data section = tvector.dataPtr - tvector.dataOffset
-
- So if you can find the relocated contents of the TVector and
- find the original offsets that made up the TVector, you can then
- calculate the base address of both the code and data sections.
-
- Finding the relocated contents of the TVector is easy; I simply
- require the client to pass in a pointer to its init routine.
- A routine pointer is a TVector pointer, so you can just cast it
- and extract the pair of words.
-
- Finding the original offsets is a trickier. My technique is to
- look up the init routine in the fragment's loader info header. This
- yields the section number and offset where the init routine's unrelocated
- TVector exists. Once I have that, I can just read the unrelocated TVector
- out of the file and extract the offsets.
-*/
-
-struct TVector {
- void *codePtr;
- void *tocPtr;
-};
-typedef struct TVector TVector;
-
-static OSStatus SetupSectionBaseAddresses(FragToFixInfo *fragToFix)
- // This routine initialises the section0Base and section1Base
- // base fields of fragToFix to the base addresses of the
- // instantiated fragment represented by the other fields
- // of fragToFix. The process works in three states:
- //
- // 1. Find the contents of the relocated TVector of the
- // fragment's initialisation routine, provided to us by
- // the caller.
- //
- // 2. Find the contents of the non-relocated TVector by
- // looking it up in the PEF loader info header and then
- // using that to read the TVector contents from disk.
- // This yields the offsets from the section bases for
- // the init routine.
- //
- // 3. Subtract 2 from 3.
-{
- OSStatus err;
- TVector * relocatedExport;
- SInt32 initSection;
- UInt32 initOffset;
- PEFSectionHeader * initSectionHeader;
- Ptr packedDataSection;
- Ptr unpackedDataSection;
- TVector originalOffsets;
-
- packedDataSection = nil;
- unpackedDataSection = nil;
-
- // Step 1.
-
- // First find the init routine's TVector, which gives us the relocated
- // offsets of the init routine into the data and code sections.
-
- relocatedExport = (TVector *) fragToFix->initRoutine;
-
- // Step 2.
-
- // Now find the init routine's TVector's offsets in the data section on
- // disk. This gives us the raw offsets from the data and code section
- // of the beginning of the init routine.
-
- err = noErr;
- initSection = fragToFix->loaderSection->initSection;
- initOffset = fragToFix->loaderSection->initOffset;
- if (initSection == -1) {
- err = cfragFragmentUsageErr;
- }
- if (err == noErr) {
- MoreAssertQ( initSection >= 0 ); // Negative indexes are pseudo-sections which are just not allowed!
- MoreAssertQ( initSection < fragToFix->containerHeader.sectionCount );
-
- initSectionHeader = &fragToFix->sectionHeaders[initSection];
-
- // If the data section is packed, unpack it to a temporary buffer and then get the
- // original offsets from that buffer. If the data section is unpacked, just read
- // the original offsets directly off the disk.
-
- if ( initSectionHeader->sectionKind == kPEFPackedDataSection ) {
-
- // Allocate space for packed and unpacked copies of the section.
-
- packedDataSection = NewPtr(initSectionHeader->containerLength);
- err = MemError();
-
- if (err == noErr) {
- unpackedDataSection = NewPtr(initSectionHeader->unpackedLength);
- err = MemError();
- }
-
- // Read the contents of the packed section.
-
- if (err == noErr) {
- err = FSReadAtOffset( fragToFix->fileRef,
- fragToFix->locator.offset
- + initSectionHeader->containerOffset,
- initSectionHeader->containerLength,
- packedDataSection);
- }
-
- // Unpack the data into the unpacked section.
-
- if (err == noErr) {
- err = UnpackPEFDataSection( (UInt8 *) packedDataSection, initSectionHeader->containerLength,
- (UInt8 *) unpackedDataSection, initSectionHeader->unpackedLength);
- }
-
- // Extract the init routine's TVector from the unpacked section.
-
- if (err == noErr) {
- BlockMoveData(unpackedDataSection + initOffset, &originalOffsets, sizeof(TVector));
- }
-
- } else {
- MoreAssertQ(fragToFix->sectionHeaders[initSection].sectionKind == kPEFUnpackedDataSection);
- err = FSReadAtOffset(fragToFix->fileRef,
- fragToFix->locator.offset
- + fragToFix->sectionHeaders[initSection].containerOffset
- + initOffset,
- sizeof(TVector),
- &originalOffsets);
- }
- }
-
- // Step 3.
-
- // Do the maths to subtract the unrelocated offsets from the current address
- // to get the base address.
-
- if (err == noErr) {
- fragToFix->section0Base = ((char *) relocatedExport->codePtr) - (UInt32) originalOffsets.codePtr;
- fragToFix->section1Base = ((char *) relocatedExport->tocPtr) - (UInt32) originalOffsets.tocPtr;
- }
-
- // Clean up.
-
- if (packedDataSection != nil) {
- DisposePtr(packedDataSection);
- MoreAssertQ( MemError() == noErr );
- }
- if (unpackedDataSection != nil) {
- DisposePtr(unpackedDataSection);
- MoreAssertQ( MemError() == noErr );
- }
- return err;
-}
-
-static void *GetSectionBaseAddress(const FragToFixInfo *fragToFix, UInt16 sectionIndex)
- // This routine returns the base of the instantiated section
- // whose index is sectionIndex. This routine is the evil twin
- // of SetupSectionBaseAddresses. It simply returns the values
- // for section 0 and 1 that we derived in SetupSectionBaseAddresses.
- // In a real implementation, this routine would call CFM API
- // to get this information, and SetupSectionBaseAddresses would
- // not exist, but CFM does not export the necessary APIs to
- // third parties.
-{
- void *result;
-
- MoreAssertQ(fragToFix != nil);
- MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
-
- switch (sectionIndex) {
- case 0:
- result = fragToFix->section0Base;
- break;
- case 1:
- result = fragToFix->section1Base;
- break;
- default:
- result = nil;
- break;
- }
- return result;
-}
-
-
-static OSStatus FindImportLibrary(PEFLoaderInfoHeader *loaderSection, const char *libraryName, PEFImportedLibrary **importLibrary)
- // This routine finds the import library description (PEFImportedLibrary)
- // for the import library libraryName in the PEF loader section.
- // It sets *importLibrary to the address of the description.
-{
- OSStatus err;
- UInt32 librariesRemaining;
- PEFImportedLibrary *thisImportLibrary;
- Boolean found;
-
- MoreAssertQ(loaderSection != nil);
- MoreAssertQ(libraryName != nil);
- MoreAssertQ(importLibrary != nil);
-
- // Loop through each import library looking for a matching name.
-
- // Initialise thisImportLibrary to point to the byte after the
- // end of the loader section's header.
-
- thisImportLibrary = (PEFImportedLibrary *) (loaderSection + 1);
- librariesRemaining = loaderSection->importedLibraryCount;
- found = false;
- while ( librariesRemaining > 0 && ! found ) {
- // PEF defines that import library names will have
- // a null terminator, so we can just use strcmp.
- found = (strcmp( libraryName,
- ((char *)loaderSection)
- + loaderSection->loaderStringsOffset
- + thisImportLibrary->nameOffset) == 0);
- // *** Remove ANSI strcmp eventually.
- if ( ! found ) {
- thisImportLibrary += 1;
- librariesRemaining -= 1;
- }
- }
-
- if (found) {
- *importLibrary = thisImportLibrary;
- err = noErr;
- } else {
- *importLibrary = nil;
- err = cfragNoLibraryErr;
- }
- return err;
-}
-
-static OSStatus LookupSymbol(CFMLateImportLookupProc lookup, void *refCon,
- PEFLoaderInfoHeader *loaderSection,
- UInt32 symbolIndex,
- UInt32 *symbolValue)
- // This routine is used to look up a symbol during relocation.
- // "lookup" is a client callback and refCon is its argument.
- // Typically refCon is the CFM connection to the library that is
- // substituting for the weak linked library. loaderSection
- // is a pointer to the loader section of the fragment to fix up.
- // symbolIndex is the index of the imported symbol in the loader section.
- // The routine sets the word pointed to by symbolValue to the
- // value of the symbol.
- //
- // The routine works by using symbolIndex to index into the imported
- // symbol table to find the offset of the symbol's name in the string
- // table. It then looks up the symbol by calling the client's "lookup"
- // function and passes the resulting symbol address back in symbolValue.
-{
- OSStatus err;
- UInt32 *importSymbolTable;
- UInt32 symbolStringOffset;
- Boolean symbolIsWeak;
- CFragSymbolClass symbolClass;
- char *symbolStringAddress;
- Str255 symbolString;
-
- MoreAssertQ(lookup != nil);
- MoreAssertQ(loaderSection != nil);
- MoreAssertQ(symbolIndex < loaderSection->totalImportedSymbolCount);
- MoreAssertQ(symbolValue != nil);
-
- // Find the base of the imported symbol table.
-
- importSymbolTable = (UInt32 *)(((char *)(loaderSection + 1)) + (loaderSection->importedLibraryCount * sizeof(PEFImportedLibrary)));
-
- // Grab the appropriate entry out of the table and
- // extract the information from that entry.
-
- symbolStringOffset = importSymbolTable[symbolIndex];
- symbolClass = PEFImportedSymbolClass(symbolStringOffset);
- symbolIsWeak = ((symbolClass & kPEFWeakImportSymMask) != 0);
- symbolClass = symbolClass & ~kPEFWeakImportSymMask;
- symbolStringOffset = PEFImportedSymbolNameOffset(symbolStringOffset);
-
- // Find the string for the symbol in the strings table and
- // extract it from the table into a Pascal string on the stack.
-
- symbolStringAddress = ((char *)loaderSection) + loaderSection->loaderStringsOffset + symbolStringOffset;
- symbolString[0] = strlen(symbolStringAddress); // *** remove ANSI strlen
- BlockMoveData(symbolStringAddress, &symbolString[1], symbolString[0]);
-
- // Look up the symbol in substitute library. If it fails, return
- // a 0 value and check whether the error is fatal (a strong linked
- // symbol) or benign (a weak linked symbol).
-
- err = lookup(symbolString, symbolClass, (void **) symbolValue, refCon);
- if (err != noErr) {
- *symbolValue = 0;
- if (symbolIsWeak) {
- err = noErr;
- }
- }
- return err;
-}
-
-// The EngineState structure encapsulates all of the persistent state
-// of the CFM relocation engine virtual machine. I originally defined
-// this structure so I could pass the state around between routines
-// that implement various virtual opcodes, however I later worked
-// out that the relocation was sufficiently simple that I could put it
-// in in one routine. Still, I left the state in this structure in
-// case I ever need to reverse that decision. It's also a convenient
-// instructional design.
-
-struct EngineState {
- UInt32 currentReloc; // Index of current relocation opcodes
- UInt32 terminatingReloc; // Index of relocation opcodes which terminates relocation
- UInt32 *sectionBase; // Start of the section
- UInt32 *relocAddress; // Address within the section where the relocations are to be performed
- UInt32 importIndex; // Symbol index, which is used to access an imported symbol's address
- void *sectionC; // Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses
- void *sectionD; // Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses
-};
-typedef struct EngineState EngineState;
-
-// Note:
-// If I ever have to support the repeat opcodes, I'll probably
-// have to add a repeat counter to EngineState.
-
-static OSStatus InitEngineState(const FragToFixInfo *fragToFix,
- UInt16 relocHeaderIndex,
- EngineState *state)
- // This routine initialises the engine state suitably for
- // running the relocation opcodes for the section whose
- // index is relocHeaderIndex. relocHeaderIndex is not a
- // a section number. See the comment where it's used below
- // for details. The routine basically fills out all the fields
- // in the EngineState structure as described by
- // "Mac OS Runtime Architectures".
-{
- OSStatus err;
- PEFLoaderRelocationHeader *relocHeader;
-
- MoreAssertQ(fragToFix != nil);
- MoreAssertQ(state != nil);
-
- // This bit is tricky. relocHeaderIndex is an index into the relocation
- // header table, starting at relocSectionCount (which is in the loader
- // section header) for the first relocated section and decrementing
- // down to 1 for the last relocated section. I find the relocation
- // header by using relocHeaderIndex as a index backwards from the
- // start of the relocation opcodes (ie relocInstrOffset). If you
- // look at the diagram of the layout of the container in
- // "PEFBinaryFormat.h", you'll see that the relocation opcodes
- // immediately follow the relocation headers.
- //
- // I did this because the alternative (starting at the loader
- // header and stepping past the import library table and the
- // import symbol table) was a pain.
-
- relocHeader = (PEFLoaderRelocationHeader *) (((char *) fragToFix->loaderSection) + fragToFix->loaderSection->relocInstrOffset - relocHeaderIndex * sizeof(PEFLoaderRelocationHeader));
-
- MoreAssertQ(relocHeader->reservedA == 0); // PEF spec says it must be; we check to try to catch bugs in calculation of relocHeader
-
- state->currentReloc = relocHeader->firstRelocOffset;
- state->terminatingReloc = relocHeader->firstRelocOffset + relocHeader->relocCount;
- state->sectionBase = (UInt32 *) GetSectionBaseAddress(fragToFix, relocHeader->sectionIndex);
- state->relocAddress = state->sectionBase;
- state->importIndex = 0;
-
- // From "Mac OS Runtime Architectures":
- //
- // The sectionC and sectionD variables actually contain the
- // memory address of an instantiated section minus the
- // default address for that section. The default address for a
- // section is contained in the defaultAddress field of the
- // section header. However, in almost all cases the default
- // address should be 0, so the simplified definition suffices.
- //
- // In the debug version, we drop into MacsBug if this weird case
- // ever executes because it's more likely we made a mistake than
- // we encountered a section with a default address.
-
- state->sectionC = GetSectionBaseAddress(fragToFix, 0);
- if (state->sectionC != nil) {
- #if MORE_DEBUG
- if (fragToFix->sectionHeaders[0].defaultAddress != 0) {
- DebugStr("\pInitEngineState: Executing weird case.");
- }
- #endif
- (char *) state->sectionC -= fragToFix->sectionHeaders[0].defaultAddress;
- }
- state->sectionD = GetSectionBaseAddress(fragToFix, 1);
- if (state->sectionD != nil) {
- #if MORE_DEBUG
- if (fragToFix->sectionHeaders[1].defaultAddress != 0) {
- DebugStr("\pInitEngineState: Executing weird case.");
- }
- #endif
- (char *) state->sectionD -= fragToFix->sectionHeaders[1].defaultAddress;
- }
-
- err = noErr;
- if (state->relocAddress == nil) {
- err = cfragFragmentUsageErr;
- }
- return err;
-}
-
-// kPEFRelocBasicOpcodes is a table that maps the top 7 bits of the opcode
-// to a fundamental action. It's contents are defined for me in "PEFBinaryFormat.h",
-// which is really convenient.
-
-static UInt8 kPEFRelocBasicOpcodes[kPEFRelocBasicOpcodeRange] = { PEFMaskedBasicOpcodes };
-
-static OSStatus RunRelocationEngine(const FragToFixInfo *fragToFix,
- PEFImportedLibrary *importLibrary,
- CFMLateImportLookupProc lookup, void *refCon)
- // This is where the rubber really hits the. Given a fully
- // populated fragToFix structure, the import library description
- // of the weak imported library we're resolving, and a connection
- // to the library we're going to substitute it, re-execute the
- // relocation instructions (CFM has already executed them once)
- // but only *do* instructions (ie store the change to the data section)
- // that CFM skipped because the weak symbols were missing.
-{
- OSStatus err;
- EngineState state;
- UInt16 sectionsLeftToRelocate;
- UInt32 totalRelocs;
- UInt16 *relocInstrTable;
- UInt16 opCode;
-
- MoreAssertQ(fragToFix != nil);
- MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
- MoreAssertQ(fragToFix->sectionHeaders != nil);
- MoreAssertQ(fragToFix->loaderSection != nil);
- MoreAssertQ(fragToFix->section0Base != nil); // Technically, having a nil for these two is not a problem, ...
- MoreAssertQ(fragToFix->section1Base != nil); // but in practise it a wildly deviant case and we should know about it.
- MoreAssertQ(importLibrary != nil);
- MoreAssertQ(lookup != nil);
-
- // Before entering the loop, work out some information in advance.
-
- // totalRelocs is only used for debugging, to make sure our
- // relocation PC (state.currentReloc) doesn't run wild.
-
- totalRelocs = (fragToFix->loaderSection->loaderStringsOffset - fragToFix->loaderSection->relocInstrOffset) / sizeof(UInt16);
-
- // relocInstrTable is the base address of the table of relocation
- // instructions in the fragment to fix.
-
- relocInstrTable = (UInt16 *)((char *) fragToFix->loaderSection + fragToFix->loaderSection->relocInstrOffset);
-
- // sectionsLeftToRelocate is the loop counter for the outer loop.
-
- MoreAssertQ(fragToFix->loaderSection->relocSectionCount <= 0x0FFFF);
- sectionsLeftToRelocate = fragToFix->loaderSection->relocSectionCount;
-
- // Now let's run the relocation engine. We run it once per
- // section in the table. Each time around, we init the engine
- // and then loop again, this time executing individual opcodes.
- // The opcode loop terminates when the relocation PC
- // (state.currentReloc) hits the final opcode (state.terminatingReloc).
-
- // Note:
- // One design decision I made was to totally re-init the engine state
- // for each section. The CFM spec is unclear as to whether you're supposed
- // to totally re-init the engine state, or just re-init the section-specific
- // state (ie currentReloc, terminatingReloc, and relocAddress). I hope this
- // is correct, but it's hard to test without having a fragment with multiple
- // relocated sections, which is difficult to create.
-
- // How do I decide which opcodes should be effective (ie make changes to
- // the section being relocated) and which opcodes should just be executed
- // for their side effects (ie updated state.relocAddress or state.importIndex)?
- // The answer is both simple and subtle. Opcodes whose actions are dependent
- // on a symbol that was in the weak linked library are effective, those that
- // an independent of those symbols are not. The only opcodes that use
- // symbolic values are kPEFRelocImportRun and kPEFRelocSmByImport, and
- // these are only if the symbol is in the weak linked library.
- // All other cases are executed for their side effects only.
- //
- // How do I determine if a symbol is in the weak linked library?
- // Well I know the symbol's index and I know the lower bound and count
- // of the symbols in the weak linked library, so I just do a simple
- // bounds test, ie
- //
- // firstImportedSymbol <= importIndex < firstImportedSymbol + importedSymbolCount
-
- // From this code, it's relatively easy to see which relocation opcodes
- // aren't implemented. If you ever encounter one, you'll find yourself
- // in MacsBug with a message telling you which opcode was found. The
- // two big groups of opcodes I skipped were the large format opcodes
- // and the repeating opcodes. I skipped them because:
- //
- // a) I haven't got a way to generate them in a PEF container that I can
- // test against. Without that, there's no way I could be assured that
- // the code worked.
- //
- // b) I'm lazy.
-
- err = noErr;
- while ( sectionsLeftToRelocate > 0 ) {
- err = InitEngineState(fragToFix, sectionsLeftToRelocate, &state);
- if (err != noErr) {
- goto leaveNow;
- }
-
- while ( state.currentReloc != state.terminatingReloc ) {
-
- MoreAssertQ( state.currentReloc < totalRelocs );
-
- opCode = relocInstrTable[state.currentReloc];
- switch ( PEFRelocBasicOpcode(opCode) ) {
- case kPEFRelocBySectDWithSkip:
- {
- UInt16 skipCount;
- UInt16 relocCount;
-
- skipCount = ((opCode >> 6) & 0x00FF);
- relocCount = (opCode & 0x003F);
- state.relocAddress += skipCount;
- state.relocAddress += relocCount;
- }
- break;
- case kPEFRelocBySectC:
- case kPEFRelocBySectD:
- {
- UInt16 runLength;
-
- runLength = (opCode & 0x01FF) + 1;
- state.relocAddress += runLength;
- }
- break;
- case kPEFRelocTVector12:
- {
- UInt16 runLength;
-
- runLength = (opCode & 0x01FF) + 1;
- state.relocAddress += (runLength * 3);
- }
- break;
- case kPEFRelocTVector8:
- case kPEFRelocVTable8:
- {
- UInt16 runLength;
-
- runLength = (opCode & 0x01FF) + 1;
- state.relocAddress += (runLength * 2);
- }
- break;
- case kPEFRelocImportRun:
- {
- UInt32 symbolValue;
- UInt16 runLength;
-
- runLength = (opCode & 0x01FF) + 1;
- while (runLength > 0) {
- if ( state.importIndex >= importLibrary->firstImportedSymbol && state.importIndex < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
- err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, state.importIndex, &symbolValue);
- if (err != noErr) {
- goto leaveNow;
- }
- *(state.relocAddress) += symbolValue;
- }
- state.importIndex += 1;
- state.relocAddress += 1;
- runLength -= 1;
- }
- }
- break;
- case kPEFRelocSmByImport:
- {
- UInt32 symbolValue;
- UInt32 index;
-
- index = (opCode & 0x01FF);
- if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
- err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue);
- if (err != noErr) {
- goto leaveNow;
- }
- *(state.relocAddress) += symbolValue;
- }
- state.importIndex = index + 1;
- state.relocAddress += 1;
- }
- break;
- case kPEFRelocSmSetSectC:
- {
- UInt32 index;
-
- index = (opCode & 0x01FF);
- state.sectionC = GetSectionBaseAddress(fragToFix, index);
- MoreAssertQ(state.sectionC != nil);
- }
- break;
- case kPEFRelocSmSetSectD:
- {
- UInt32 index;
-
- index = (opCode & 0x01FF);
- state.sectionD = GetSectionBaseAddress(fragToFix, index);
- MoreAssertQ(state.sectionD != nil);
- }
- break;
- case kPEFRelocSmBySection:
- state.relocAddress += 1;
- break;
- case kPEFRelocIncrPosition:
- {
- UInt16 offset;
-
- offset = (opCode & 0x0FFF) + 1;
- ((char *) state.relocAddress) += offset;
- }
- break;
- case kPEFRelocSmRepeat:
- #if MORE_DEBUG
- DebugStr("\pRunRelocationEngine: kPEFRelocSmRepeat not yet implemented");
- #endif
- err = unimpErr;
- goto leaveNow;
- break;
- case kPEFRelocSetPosition:
- {
- UInt32 offset;
-
- // Lot's of folks have tried various interpretations of the description of
- // this opCode in "Mac OS Runtime Architectures" (which states "This instruction
- // sets relocAddress to the address of the section offset offset." *smile*).
- // I eventually dug into the CFM source code to find my interpretation, which
- // I believe is correct. The key point is tht the offset is relative to
- // the start of the section for which these relocations are being performed.
-
- // Skip to next reloc word, which is the second chunk of the offset.
-
- state.currentReloc += 1;
-
- // Extract offset based on the most significant 10 bits in opCode and
- // the next significant 16 bits in the next reloc word.
-
- offset = PEFRelocSetPosFullOffset(opCode, relocInstrTable[state.currentReloc]);
-
- state.relocAddress = (UInt32 *) ( ((char *) state.sectionBase) + offset);
- }
- break;
- case kPEFRelocLgByImport:
- {
- UInt32 symbolValue;
- UInt32 index;
-
- // Get the 26 bit symbol index from the current and next reloc words.
-
- state.currentReloc += 1;
- index = PEFRelocLgByImportFullIndex(opCode, relocInstrTable[state.currentReloc]);
-
- if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) {
- err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue);
- if (err != noErr) {
- goto leaveNow;
- }
- *(state.relocAddress) += symbolValue;
- }
- state.importIndex = index + 1;
- state.relocAddress += 1;
- }
- break;
- case kPEFRelocLgRepeat:
- #if MORE_DEBUG
- DebugStr("\pRunRelocationEngine: kPEFRelocLgRepeat not yet implemented");
- #endif
- err = unimpErr;
- goto leaveNow;
- break;
- case kPEFRelocLgSetOrBySection:
- #if MORE_DEBUG
- DebugStr("\pRunRelocationEngine: kPEFRelocLgSetOrBySection not yet implemented");
- #endif
- err = unimpErr;
- goto leaveNow;
- break;
- case kPEFRelocUndefinedOpcode:
- err = cfragFragmentCorruptErr;
- goto leaveNow;
- break;
- default:
- MoreAssertQ(false);
- err = cfragFragmentCorruptErr;
- goto leaveNow;
- break;
- }
- state.currentReloc += 1;
- }
-
- sectionsLeftToRelocate -= 1;
- }
-
-leaveNow:
- return err;
-}
-
-extern pascal OSStatus CFMLateImportCore(const CFragSystem7DiskFlatLocator *fragToFixLocator,
- CFragConnectionID fragToFixConnID,
- CFragInitFunction fragToFixInitRoutine,
- ConstStr255Param weakLinkedLibraryName,
- CFMLateImportLookupProc lookup,
- void *refCon)
- // See comments in interface part.
-{
- OSStatus err;
- OSStatus junk;
- FragToFixInfo fragToFix;
- PEFImportedLibrary *importLibrary;
- char weakLinkedLibraryNameCString[256];
-
- MoreAssertQ(fragToFixLocator != nil);
- MoreAssertQ(fragToFixConnID != nil);
- MoreAssertQ(fragToFixInitRoutine != nil);
- MoreAssertQ(weakLinkedLibraryName != nil);
- MoreAssertQ(lookup != nil);
-
- // Fill out the bits of fragToFix which are passed in
- // by the client.
-
- MoreBlockZero(&fragToFix, sizeof(fragToFix));
- fragToFix.locator = *fragToFixLocator;
- fragToFix.connID = fragToFixConnID;
- fragToFix.initRoutine = fragToFixInitRoutine;
-
- // Make a C string from weakLinkedLibraryName.
-
- BlockMoveData(weakLinkedLibraryName + 1, weakLinkedLibraryNameCString, weakLinkedLibraryName[0]);
- weakLinkedLibraryNameCString[weakLinkedLibraryName[0]] = 0;
-
- // Get the basic information from the fragment.
- // Fills out the containerHeader, sectionHeaders, loaderSection and fileRef fields
- // of fragToFix.
-
- err = ReadContainerBasics(&fragToFix);
-
- // Set up the base address fields in fragToFix (ie section0Base and section1Base)
- // by looking up our init routine (fragToFix.initRoutine) and subtracting
- // away the section offsets (which we get from the disk copy of the section)
- // to derive the bases of the sections themselves.
-
- if (err == noErr) {
- err = SetupSectionBaseAddresses(&fragToFix);
- }
-
- // Look inside the loader section for the import library description
- // of weakLinkedLibraryName. We need this to know the range of symbol
- // indexes we're going to fix up.
-
- if (err == noErr) {
- err = FindImportLibrary(fragToFix.loaderSection, weakLinkedLibraryNameCString, &importLibrary);
- }
-
- // Do a quick check to ensure that the library was actually imported weak.
- // If it wasn't, it doesn't make much sense to resolve its weak imports
- // later on. Resolving them again is likely to be bad.
-
- if (err == noErr) {
- if ((importLibrary->options & kPEFWeakImportLibMask) == 0) {
- err = cfragFragmentUsageErr;
- }
- }
-
- // Now run the main relocation engine.
-
- if (err == noErr) {
- err = RunRelocationEngine(&fragToFix, importLibrary, lookup, refCon);
- }
-
- // Clean up.
-
- if (fragToFix.disposeSectionPointers) {
- if (fragToFix.fileRef != 0) {
- junk = FSClose(fragToFix.fileRef);
- MoreAssertQ(junk == noErr);
- }
- if (fragToFix.loaderSection != nil) {
- DisposePtr( (Ptr) fragToFix.loaderSection);
- MoreAssertQ(MemError() == noErr);
- }
- if (fragToFix.sectionHeaders != nil) {
- DisposePtr( (Ptr) fragToFix.sectionHeaders);
- MoreAssertQ(MemError() == noErr);
- }
- }
- return err;
-}
-
-static pascal OSStatus FragmentLookup(ConstStr255Param symName, CFragSymbolClass symClass,
- void **symAddr, void *refCon)
- // This is the CFMLateImportLookupProc callback used when
- // late importing from a CFM shared library.
-{
- OSStatus err;
- CFragConnectionID connIDToImport;
- CFragSymbolClass foundSymClass;
-
- MoreAssertQ(symName != nil);
- MoreAssertQ(symAddr != nil);
- MoreAssertQ(refCon != nil);
-
- connIDToImport = (CFragConnectionID) refCon;
-
- // Shame there's no way to validate that connIDToImport is valid.
-
- err = FindSymbol(connIDToImport, symName, (Ptr *) symAddr, &foundSymClass);
- if (err == noErr) {
- // If the symbol isn't of the right class, we act like we didn't
- // find it, but also assert in the debug build because weird things
- // are afoot.
- if (foundSymClass != symClass) {
- MoreAssertQ(false);
- *symAddr = nil;
- err = cfragNoSymbolErr;
- }
- }
- return err;
-}
-
-extern pascal OSStatus CFMLateImportLibrary(const CFragSystem7DiskFlatLocator *fragToFixLocator,
- CFragConnectionID fragToFixConnID,
- CFragInitFunction fragToFixInitRoutine,
- ConstStr255Param weakLinkedLibraryName,
- CFragConnectionID connIDToImport)
- // See comments in interface part.
-{
- MoreAssertQ(connIDToImport != nil);
- return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
- weakLinkedLibraryName, FragmentLookup, connIDToImport);
-}
-
-static pascal OSStatus BundleLookup(ConstStr255Param symName, CFragSymbolClass symClass,
- void **symAddr, void *refCon)
- // This is the CFMLateImportLookupProc callback used when
- // late importing from a CFBundle.
-{
- OSStatus err;
- CFBundleRef bundleToImport;
- CFStringRef symNameStr;
-
- MoreAssertQ(symName != nil);
- MoreAssertQ(symAddr != nil);
- MoreAssertQ(refCon != nil);
-
- symNameStr = nil;
-
- bundleToImport = (CFBundleRef) refCon;
-
- // Shame there's no way to validate that bundleToImport is really a bundle.
-
- // We can only find function pointers because CFBundleGetFunctionPointerForName
- // only works for function pointers. So if the client is asking for something
- // other than a function pointer (ie TVector symbol) then we don't even true.
- // Also assert in the debug build because this shows a certain lack of
- // understanding on the part of the client.
- //
- // CF is being revise to support accessing data symbols using a new API
- // (currently this is available to Apple internal developers as
- // CFBundleGetDataPointerForName). When the new API is available in a
- // public header file I should revise this code to lift this restriction.
-
- err = noErr;
- if (symClass != kTVectorCFragSymbol) {
- MoreAssertQ(false);
- err = cfragNoSymbolErr;
- }
- if (err == noErr) {
- symNameStr = CFStringCreateWithPascalString(kCFAllocatorSystemDefault,
- symName, kCFStringEncodingMacRoman);
- if (symNameStr == nil) {
- err = coreFoundationUnknownErr;
- }
- }
- if (err == noErr) {
- *symAddr = CFBundleGetFunctionPointerForName(bundleToImport, symNameStr);
- if (*symAddr == nil) {
- err = cfragNoSymbolErr;
- }
- }
- if (symNameStr != nil) {
- CFRelease(symNameStr);
- }
- return err;
-}
-
-extern pascal OSStatus CFMLateImportBundle(const CFragSystem7DiskFlatLocator *fragToFixLocator,
- CFragConnectionID fragToFixConnID,
- CFragInitFunction fragToFixInitRoutine,
- ConstStr255Param weakLinkedLibraryName,
- CFBundleRef bundleToImport)
- // See comments in interface part.
-{
- MoreAssertQ(bundleToImport != nil);
- return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
- weakLinkedLibraryName, BundleLookup, bundleToImport);
-}