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