This commit was manufactured by cvs2svn to create tag 'r221'.
[python/dscho.git] / Mac / Modules / cg / CFMLateImport.c
blobbc2976e72f9c41980e4d6626fff0ba517eb4ce53
1 /*
2 File: CFMLateImport.c
4 Contains: Implementation of CFM late import library.
6 Written by: Quinn
8 Copyright: Copyright © 1999 by Apple Computer, Inc., all rights reserved.
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.
18 Change History (most recent first):
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.
45 // To Do List:
47 // o get rid of dependence on ANSI "string.h", but how?
49 // Done:
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
58 /////////////////////////////////////////////////////////////////
60 // MoreIsBetter Setup
62 //#include "MoreSetup.h"
63 #define MoreAssert(x) (true)
64 #define MoreAssertQ(x)
66 // Mac OS Interfaces
68 #if ! MORE_FRAMEWORK_INCLUDES
69 #include <CodeFragments.h>
70 #include <PEFBinaryFormat.h>
71 #endif
73 // Standard C Interfaces
75 #include <string.h>
77 // MIB Prototypes
79 //#include "MoreInterfaceLib.h"
80 #define MoreBlockZero BlockZero
82 // Our Prototypes
84 #include "CFMLateImport.h"
86 /////////////////////////////////////////////////////////////////
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
94 /////////////////////////////////////////////////////////////////
95 #pragma mark ----- Utility Routines -----
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.
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.
106 ParamBlockRec pb;
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;
114 return PBReadSync(&pb);
117 /////////////////////////////////////////////////////////////////
118 #pragma mark ----- Late Import Engine -----
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.
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.
138 typedef struct FragToFixInfo FragToFixInfo;
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.
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.
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:
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).
162 // Also sets disposeSectionPointers to indicate whether
163 // the last two pointers should be disposed of.
165 // Finally, it leaves the container file open for later
166 // folks who want to read data from it.
168 OSStatus err;
169 UInt16 sectionIndex;
170 Boolean found;
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);
179 fragToFix->disposeSectionPointers = true;
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).
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;
200 if (err == noErr) {
201 fragToFix->sectionHeaders = (PEFSectionHeader *) NewPtr(fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader));
202 err = MemError();
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);
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;
220 if (err == noErr && ! found) {
221 err = cfragNoSectionErr;
224 // Now read allocate a pointer block and read the loader section into it.
226 if (err == noErr) {
227 fragToFix->loaderSection = (PEFLoaderInfoHeader *) NewPtr(fragToFix->sectionHeaders[sectionIndex].containerLength);
228 err = MemError();
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);
238 // No clean up. The client must init fragToFix to zeros and then
239 // clean up regardless of whether we return an error.
241 return err;
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.
249 UInt8 * bytePtr;
250 UInt8 byte;
251 UInt32 count;
253 bytePtr = (UInt8 *)start;
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);
262 *outCount = count;
263 return bytePtr - start;
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.
271 MoreAssertQ(inOpStart != nil);
272 MoreAssertQ(outCount != nil);
274 if (PEFPkDataCount5(*inOpStart) != 0)
276 // Simple case, count encoded in opcode.
277 *outCount = PEFPkDataCount5(*inOpStart);
278 return 1;
280 else
282 // Variable-length case.
283 return 1 + DecodeVCountValue(inOpStart + 1, outCount);
287 static OSStatus UnpackPEFDataSection(const UInt8 * const packedData, UInt32 packedSize,
288 UInt8 * const unpackedData, UInt32 unpackedSize)
290 OSErr err;
291 UInt32 offset;
292 UInt8 opCode;
293 UInt8 * unpackCursor;
295 MoreAssertQ(packedData != nil);
296 MoreAssertQ(unpackedData != nil);
297 MoreAssertQ(unpackedSize >= packedSize);
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.
303 MoreAssertQ( packedSize == GetPtrSize( (Ptr) packedData ) );
304 MoreAssertQ( unpackedSize == GetPtrSize( (Ptr) unpackedData) );
306 err = noErr;
307 offset = 0;
308 unpackCursor = unpackedData;
309 while (offset < packedSize) {
310 MoreAssertQ(unpackCursor < &unpackedData[unpackedSize]);
312 opCode = packedData[offset];
314 switch (PEFPkDataOpcode(opCode)) {
315 case kPEFPkDataZero:
317 UInt32 count;
319 offset += DecodeInstrCountValue(&packedData[offset], &count);
321 MoreBlockZero(unpackCursor, count);
322 unpackCursor += count;
324 break;
326 case kPEFPkDataBlock:
328 UInt32 blockSize;
330 offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
332 BlockMoveData(&packedData[offset], unpackCursor, blockSize);
333 unpackCursor += blockSize;
334 offset += blockSize;
336 break;
338 case kPEFPkDataRepeat:
340 UInt32 blockSize;
341 UInt32 repeatCount;
342 UInt32 loopCounter;
344 offset += DecodeInstrCountValue(&packedData[offset], &blockSize);
345 offset += DecodeVCountValue(&packedData[offset], &repeatCount);
346 repeatCount += 1; // stored value is (repeatCount - 1)
348 for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) {
349 BlockMoveData(&packedData[offset], unpackCursor, blockSize);
350 unpackCursor += blockSize;
352 offset += blockSize;
354 break;
356 case kPEFPkDataRepeatBlock:
358 UInt32 commonSize;
359 UInt32 customSize;
360 UInt32 repeatCount;
361 const UInt8 *commonData;
362 const UInt8 *customData;
363 UInt32 loopCounter;
365 offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
366 offset += DecodeVCountValue(&packedData[offset], &customSize);
367 offset += DecodeVCountValue(&packedData[offset], &repeatCount);
369 commonData = &packedData[offset];
370 customData = &packedData[offset + commonSize];
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;
379 BlockMoveData(commonData, unpackCursor, commonSize);
380 unpackCursor += commonSize;
381 offset += (repeatCount * (commonSize + customSize)) + commonSize;
383 break;
385 case kPEFPkDataRepeatZero:
387 UInt32 commonSize;
388 UInt32 customSize;
389 UInt32 repeatCount;
390 const UInt8 *customData;
391 UInt32 loopCounter;
393 offset += DecodeInstrCountValue(&packedData[offset], &commonSize);
394 offset += DecodeVCountValue(&packedData[offset], &customSize);
395 offset += DecodeVCountValue(&packedData[offset], &repeatCount);
397 customData = &packedData[offset];
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;
406 MoreBlockZero(unpackCursor, commonSize);
407 unpackCursor += commonSize;
408 offset += repeatCount * customSize;
410 break;
412 default:
413 #if MORE_DEBUG
414 DebugStr("\pUnpackPEFDataSection: Unexpected data opcode");
415 #endif
416 err = cfragFragmentCorruptErr;
417 goto leaveNow;
418 break;
422 leaveNow:
423 return err;
426 /* SetupSectionBaseAddresses Rationale
427 -----------------------------------
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.]
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.
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.
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.
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:
465 tvector.codePtr = tvector.codeOffset + base of code section
466 tvector.tocPtr = tvector.tocOffset + base of data section
468 Now, you can reverse these questions to make them:
470 base of code section = tvector.codePtr - tvector.codeOffset
471 base of data section = tvector.dataPtr - tvector.dataOffset
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.
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.
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.
489 struct TVector {
490 void *codePtr;
491 void *tocPtr;
493 typedef struct TVector TVector;
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:
501 // 1. Find the contents of the relocated TVector of the
502 // fragment's initialisation routine, provided to us by
503 // the caller.
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.
511 // 3. Subtract 2 from 3.
513 OSStatus err;
514 TVector * relocatedExport;
515 SInt32 initSection;
516 UInt32 initOffset;
517 PEFSectionHeader * initSectionHeader;
518 Ptr packedDataSection;
519 Ptr unpackedDataSection;
520 TVector originalOffsets;
522 packedDataSection = nil;
523 unpackedDataSection = nil;
525 // Step 1.
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.
530 relocatedExport = (TVector *) fragToFix->initRoutine;
532 // Step 2.
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.
538 err = noErr;
539 initSection = fragToFix->loaderSection->initSection;
540 initOffset = fragToFix->loaderSection->initOffset;
541 if (initSection == -1) {
542 err = cfragFragmentUsageErr;
544 if (err == noErr) {
545 MoreAssertQ( initSection >= 0 ); // Negative indexes are pseudo-sections which are just not allowed!
546 MoreAssertQ( initSection < fragToFix->containerHeader.sectionCount );
548 initSectionHeader = &fragToFix->sectionHeaders[initSection];
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.
554 if ( initSectionHeader->sectionKind == kPEFPackedDataSection ) {
556 // Allocate space for packed and unpacked copies of the section.
558 packedDataSection = NewPtr(initSectionHeader->containerLength);
559 err = MemError();
561 if (err == noErr) {
562 unpackedDataSection = NewPtr(initSectionHeader->unpackedLength);
563 err = MemError();
566 // Read the contents of the packed section.
568 if (err == noErr) {
569 err = FSReadAtOffset( fragToFix->fileRef,
570 fragToFix->locator.offset
571 + initSectionHeader->containerOffset,
572 initSectionHeader->containerLength,
573 packedDataSection);
576 // Unpack the data into the unpacked section.
578 if (err == noErr) {
579 err = UnpackPEFDataSection( (UInt8 *) packedDataSection, initSectionHeader->containerLength,
580 (UInt8 *) unpackedDataSection, initSectionHeader->unpackedLength);
583 // Extract the init routine's TVector from the unpacked section.
585 if (err == noErr) {
586 BlockMoveData(unpackedDataSection + initOffset, &originalOffsets, sizeof(TVector));
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);
600 // Step 3.
602 // Do the maths to subtract the unrelocated offsets from the current address
603 // to get the base address.
605 if (err == noErr) {
606 fragToFix->section0Base = ((char *) relocatedExport->codePtr) - (UInt32) originalOffsets.codePtr;
607 fragToFix->section1Base = ((char *) relocatedExport->tocPtr) - (UInt32) originalOffsets.tocPtr;
610 // Clean up.
612 if (packedDataSection != nil) {
613 DisposePtr(packedDataSection);
614 MoreAssertQ( MemError() == noErr );
616 if (unpackedDataSection != nil) {
617 DisposePtr(unpackedDataSection);
618 MoreAssertQ( MemError() == noErr );
620 return err;
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.
633 void *result;
635 MoreAssertQ(fragToFix != nil);
636 MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
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;
649 return result;
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.
658 OSStatus err;
659 UInt32 librariesRemaining;
660 PEFImportedLibrary *thisImportLibrary;
661 Boolean found;
663 MoreAssertQ(loaderSection != nil);
664 MoreAssertQ(libraryName != nil);
665 MoreAssertQ(importLibrary != nil);
667 // Loop through each import library looking for a matching name.
669 // Initialise thisImportLibrary to point to the byte after the
670 // end of the loader section's header.
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;
689 if (found) {
690 *importLibrary = thisImportLibrary;
691 err = noErr;
692 } else {
693 *importLibrary = nil;
694 err = cfragNoLibraryErr;
696 return err;
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.
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.
717 OSStatus err;
718 UInt32 *importSymbolTable;
719 UInt32 symbolStringOffset;
720 Boolean symbolIsWeak;
721 CFragSymbolClass symbolClass;
722 char *symbolStringAddress;
723 Str255 symbolString;
725 MoreAssertQ(lookup != nil);
726 MoreAssertQ(loaderSection != nil);
727 MoreAssertQ(symbolIndex < loaderSection->totalImportedSymbolCount);
728 MoreAssertQ(symbolValue != nil);
730 // Find the base of the imported symbol table.
732 importSymbolTable = (UInt32 *)(((char *)(loaderSection + 1)) + (loaderSection->importedLibraryCount * sizeof(PEFImportedLibrary)));
734 // Grab the appropriate entry out of the table and
735 // extract the information from that entry.
737 symbolStringOffset = importSymbolTable[symbolIndex];
738 symbolClass = PEFImportedSymbolClass(symbolStringOffset);
739 symbolIsWeak = ((symbolClass & kPEFWeakImportSymMask) != 0);
740 symbolClass = symbolClass & ~kPEFWeakImportSymMask;
741 symbolStringOffset = PEFImportedSymbolNameOffset(symbolStringOffset);
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.
746 symbolStringAddress = ((char *)loaderSection) + loaderSection->loaderStringsOffset + symbolStringOffset;
747 symbolString[0] = strlen(symbolStringAddress); // *** remove ANSI strlen
748 BlockMoveData(symbolStringAddress, &symbolString[1], symbolString[0]);
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).
754 err = lookup(symbolString, symbolClass, (void **) symbolValue, refCon);
755 if (err != noErr) {
756 *symbolValue = 0;
757 if (symbolIsWeak) {
758 err = noErr;
761 return err;
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.
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
782 typedef struct EngineState EngineState;
784 // Note:
785 // If I ever have to support the repeat opcodes, I'll probably
786 // have to add a repeat counter to EngineState.
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".
799 OSStatus err;
800 PEFLoaderRelocationHeader *relocHeader;
802 MoreAssertQ(fragToFix != nil);
803 MoreAssertQ(state != nil);
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.
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.
819 relocHeader = (PEFLoaderRelocationHeader *) (((char *) fragToFix->loaderSection) + fragToFix->loaderSection->relocInstrOffset - relocHeaderIndex * sizeof(PEFLoaderRelocationHeader));
821 MoreAssertQ(relocHeader->reservedA == 0); // PEF spec says it must be; we check to try to catch bugs in calculation of relocHeader
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;
829 // From "Mac OS Runtime Architectures":
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.
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.
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.");
848 #endif
849 (char *) state->sectionC -= fragToFix->sectionHeaders[0].defaultAddress;
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.");
857 #endif
858 (char *) state->sectionD -= fragToFix->sectionHeaders[1].defaultAddress;
861 err = noErr;
862 if (state->relocAddress == nil) {
863 err = cfragFragmentUsageErr;
865 return err;
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.
872 static UInt8 kPEFRelocBasicOpcodes[kPEFRelocBasicOpcodeRange] = { PEFMaskedBasicOpcodes };
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.
885 OSStatus err;
886 EngineState state;
887 UInt16 sectionsLeftToRelocate;
888 UInt32 totalRelocs;
889 UInt16 *relocInstrTable;
890 UInt16 opCode;
892 MoreAssertQ(fragToFix != nil);
893 MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1);
894 MoreAssertQ(fragToFix->sectionHeaders != nil);
895 MoreAssertQ(fragToFix->loaderSection != nil);
896 MoreAssertQ(fragToFix->section0Base != nil); // Technically, having a nil for these two is not a problem, ...
897 MoreAssertQ(fragToFix->section1Base != nil); // but in practise it a wildly deviant case and we should know about it.
898 MoreAssertQ(importLibrary != nil);
899 MoreAssertQ(lookup != nil);
901 // Before entering the loop, work out some information in advance.
903 // totalRelocs is only used for debugging, to make sure our
904 // relocation PC (state.currentReloc) doesn't run wild.
906 totalRelocs = (fragToFix->loaderSection->loaderStringsOffset - fragToFix->loaderSection->relocInstrOffset) / sizeof(UInt16);
908 // relocInstrTable is the base address of the table of relocation
909 // instructions in the fragment to fix.
911 relocInstrTable = (UInt16 *)((char *) fragToFix->loaderSection + fragToFix->loaderSection->relocInstrOffset);
913 // sectionsLeftToRelocate is the loop counter for the outer loop.
915 MoreAssertQ(fragToFix->loaderSection->relocSectionCount <= 0x0FFFF);
916 sectionsLeftToRelocate = fragToFix->loaderSection->relocSectionCount;
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).
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.
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.
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
947 // firstImportedSymbol <= importIndex < firstImportedSymbol + importedSymbolCount
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:
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.
959 // b) I'm lazy.
961 err = noErr;
962 while ( sectionsLeftToRelocate > 0 ) {
963 err = InitEngineState(fragToFix, sectionsLeftToRelocate, &state);
964 if (err != noErr) {
965 goto leaveNow;
968 while ( state.currentReloc != state.terminatingReloc ) {
970 MoreAssertQ( state.currentReloc < totalRelocs );
972 opCode = relocInstrTable[state.currentReloc];
973 switch ( PEFRelocBasicOpcode(opCode) ) {
974 case kPEFRelocBySectDWithSkip:
976 UInt16 skipCount;
977 UInt16 relocCount;
979 skipCount = ((opCode >> 6) & 0x00FF);
980 relocCount = (opCode & 0x003F);
981 state.relocAddress += skipCount;
982 state.relocAddress += relocCount;
984 break;
985 case kPEFRelocBySectC:
986 case kPEFRelocBySectD:
988 UInt16 runLength;
990 runLength = (opCode & 0x01FF) + 1;
991 state.relocAddress += runLength;
993 break;
994 case kPEFRelocTVector12:
996 UInt16 runLength;
998 runLength = (opCode & 0x01FF) + 1;
999 state.relocAddress += (runLength * 3);
1001 break;
1002 case kPEFRelocTVector8:
1003 case kPEFRelocVTable8:
1005 UInt16 runLength;
1007 runLength = (opCode & 0x01FF) + 1;
1008 state.relocAddress += (runLength * 2);
1010 break;
1011 case kPEFRelocImportRun:
1013 UInt32 symbolValue;
1014 UInt16 runLength;
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;
1023 *(state.relocAddress) += symbolValue;
1025 state.importIndex += 1;
1026 state.relocAddress += 1;
1027 runLength -= 1;
1030 break;
1031 case kPEFRelocSmByImport:
1033 UInt32 symbolValue;
1034 UInt32 index;
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;
1042 *(state.relocAddress) += symbolValue;
1044 state.importIndex = index + 1;
1045 state.relocAddress += 1;
1047 break;
1048 case kPEFRelocSmSetSectC:
1050 UInt32 index;
1052 index = (opCode & 0x01FF);
1053 state.sectionC = GetSectionBaseAddress(fragToFix, index);
1054 MoreAssertQ(state.sectionC != nil);
1056 break;
1057 case kPEFRelocSmSetSectD:
1059 UInt32 index;
1061 index = (opCode & 0x01FF);
1062 state.sectionD = GetSectionBaseAddress(fragToFix, index);
1063 MoreAssertQ(state.sectionD != nil);
1065 break;
1066 case kPEFRelocSmBySection:
1067 state.relocAddress += 1;
1068 break;
1069 case kPEFRelocIncrPosition:
1071 UInt16 offset;
1073 offset = (opCode & 0x0FFF) + 1;
1074 ((char *) state.relocAddress) += offset;
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:
1086 UInt32 offset;
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.
1095 // Skip to next reloc word, which is the second chunk of the offset.
1097 state.currentReloc += 1;
1099 // Extract offset based on the most significant 10 bits in opCode and
1100 // the next significant 16 bits in the next reloc word.
1102 offset = PEFRelocSetPosFullOffset(opCode, relocInstrTable[state.currentReloc]);
1104 state.relocAddress = (UInt32 *) ( ((char *) state.sectionBase) + offset);
1106 break;
1107 case kPEFRelocLgByImport:
1109 UInt32 symbolValue;
1110 UInt32 index;
1112 // Get the 26 bit symbol index from the current and next reloc words.
1114 state.currentReloc += 1;
1115 index = PEFRelocLgByImportFullIndex(opCode, relocInstrTable[state.currentReloc]);
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;
1122 *(state.relocAddress) += symbolValue;
1124 state.importIndex = index + 1;
1125 state.relocAddress += 1;
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;
1152 state.currentReloc += 1;
1155 sectionsLeftToRelocate -= 1;
1158 leaveNow:
1159 return err;
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.
1170 OSStatus err;
1171 OSStatus junk;
1172 FragToFixInfo fragToFix;
1173 PEFImportedLibrary *importLibrary;
1174 char weakLinkedLibraryNameCString[256];
1176 MoreAssertQ(fragToFixLocator != nil);
1177 MoreAssertQ(fragToFixConnID != nil);
1178 MoreAssertQ(fragToFixInitRoutine != nil);
1179 MoreAssertQ(weakLinkedLibraryName != nil);
1180 MoreAssertQ(lookup != nil);
1182 // Fill out the bits of fragToFix which are passed in
1183 // by the client.
1185 MoreBlockZero(&fragToFix, sizeof(fragToFix));
1186 fragToFix.locator = *fragToFixLocator;
1187 fragToFix.connID = fragToFixConnID;
1188 fragToFix.initRoutine = fragToFixInitRoutine;
1190 // Make a C string from weakLinkedLibraryName.
1192 BlockMoveData(weakLinkedLibraryName + 1, weakLinkedLibraryNameCString, weakLinkedLibraryName[0]);
1193 weakLinkedLibraryNameCString[weakLinkedLibraryName[0]] = 0;
1195 // Get the basic information from the fragment.
1196 // Fills out the containerHeader, sectionHeaders, loaderSection and fileRef fields
1197 // of fragToFix.
1199 err = ReadContainerBasics(&fragToFix);
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.
1206 if (err == noErr) {
1207 err = SetupSectionBaseAddresses(&fragToFix);
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.
1214 if (err == noErr) {
1215 err = FindImportLibrary(fragToFix.loaderSection, weakLinkedLibraryNameCString, &importLibrary);
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.
1222 if (err == noErr) {
1223 if ((importLibrary->options & kPEFWeakImportLibMask) == 0) {
1224 err = cfragFragmentUsageErr;
1228 // Now run the main relocation engine.
1230 if (err == noErr) {
1231 err = RunRelocationEngine(&fragToFix, importLibrary, lookup, refCon);
1234 // Clean up.
1236 if (fragToFix.disposeSectionPointers) {
1237 if (fragToFix.fileRef != 0) {
1238 junk = FSClose(fragToFix.fileRef);
1239 MoreAssertQ(junk == noErr);
1241 if (fragToFix.loaderSection != nil) {
1242 DisposePtr( (Ptr) fragToFix.loaderSection);
1243 MoreAssertQ(MemError() == noErr);
1245 if (fragToFix.sectionHeaders != nil) {
1246 DisposePtr( (Ptr) fragToFix.sectionHeaders);
1247 MoreAssertQ(MemError() == noErr);
1250 return err;
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.
1258 OSStatus err;
1259 CFragConnectionID connIDToImport;
1260 CFragSymbolClass foundSymClass;
1262 MoreAssertQ(symName != nil);
1263 MoreAssertQ(symAddr != nil);
1264 MoreAssertQ(refCon != nil);
1266 connIDToImport = (CFragConnectionID) refCon;
1268 // Shame there's no way to validate that connIDToImport is valid.
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;
1281 return err;
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.
1291 MoreAssertQ(connIDToImport != nil);
1292 return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
1293 weakLinkedLibraryName, FragmentLookup, connIDToImport);
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.
1301 OSStatus err;
1302 CFBundleRef bundleToImport;
1303 CFStringRef symNameStr;
1305 MoreAssertQ(symName != nil);
1306 MoreAssertQ(symAddr != nil);
1307 MoreAssertQ(refCon != nil);
1309 symNameStr = nil;
1311 bundleToImport = (CFBundleRef) refCon;
1313 // Shame there's no way to validate that bundleToImport is really a bundle.
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.
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.
1326 err = noErr;
1327 if (symClass != kTVectorCFragSymbol) {
1328 MoreAssertQ(false);
1329 err = cfragNoSymbolErr;
1331 if (err == noErr) {
1332 symNameStr = CFStringCreateWithPascalString(kCFAllocatorSystemDefault,
1333 symName, kCFStringEncodingMacRoman);
1334 if (symNameStr == nil) {
1335 err = coreFoundationUnknownErr;
1338 if (err == noErr) {
1339 *symAddr = CFBundleGetFunctionPointerForName(bundleToImport, symNameStr);
1340 if (*symAddr == nil) {
1341 err = cfragNoSymbolErr;
1344 if (symNameStr != nil) {
1345 CFRelease(symNameStr);
1347 return err;
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.
1357 MoreAssertQ(bundleToImport != nil);
1358 return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine,
1359 weakLinkedLibraryName, BundleLookup, bundleToImport);