4 Contains: Implementation of CFM late import library.
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
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
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.
47 // o get rid of dependence on ANSI "string.h", but how?
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 /////////////////////////////////////////////////////////////////
62 //#include "MoreSetup.h"
63 #define MoreAssert(x) (true)
64 #define MoreAssertQ(x)
68 #if ! MORE_FRAMEWORK_INCLUDES
69 #include <CodeFragments.h>
70 #include <PEFBinaryFormat.h>
73 // Standard C Interfaces
79 //#include "MoreInterfaceLib.h"
80 #define MoreBlockZero BlockZero
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.
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.
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.
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
);
188 err
= FSReadAtOffset(fragToFix
->fileRef
,
189 fragToFix
->locator
.offset
,
190 sizeof(fragToFix
->containerHeader
),
191 &fragToFix
->containerHeader
);
193 if ( fragToFix
->containerHeader
.tag1
!= kPEFTag1
194 || fragToFix
->containerHeader
.tag2
!= kPEFTag2
195 || fragToFix
->containerHeader
.architecture
!= kCompiledCFragArch
196 || fragToFix
->containerHeader
.formatVersion
!= kPEFVersion
) {
197 err
= cfragFragmentFormatErr
;
201 fragToFix
->sectionHeaders
= (PEFSectionHeader
*) NewPtr(fragToFix
->containerHeader
.sectionCount
* sizeof(PEFSectionHeader
));
205 err
= FSReadAtOffset(fragToFix
->fileRef
,
206 fragToFix
->locator
.offset
+ sizeof(fragToFix
->containerHeader
),
207 fragToFix
->containerHeader
.sectionCount
* sizeof(PEFSectionHeader
),
208 fragToFix
->sectionHeaders
);
213 while ( sectionIndex
< fragToFix
->containerHeader
.sectionCount
&& ! found
) {
214 found
= (fragToFix
->sectionHeaders
[sectionIndex
].sectionKind
== kPEFLoaderSection
);
220 if (err
== noErr
&& ! found
) {
221 err
= cfragNoSectionErr
;
224 // Now read allocate a pointer block and read the loader section into it.
227 fragToFix
->loaderSection
= (PEFLoaderInfoHeader
*) NewPtr(fragToFix
->sectionHeaders
[sectionIndex
].containerLength
);
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.
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.
253 bytePtr
= (UInt8
*)start
;
255 // Code taken from "PEFBinaryFormat.h".
259 count
= (count
<< kPEFPkDataVCountShift
) | (byte
& kPEFPkDataVCountMask
);
260 } while ((byte
& kPEFPkDataVCountEndMask
) != 0);
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
);
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
)
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
) );
308 unpackCursor
= unpackedData
;
309 while (offset
< packedSize
) {
310 MoreAssertQ(unpackCursor
< &unpackedData
[unpackedSize
]);
312 opCode
= packedData
[offset
];
314 switch (PEFPkDataOpcode(opCode
)) {
319 offset
+= DecodeInstrCountValue(&packedData
[offset
], &count
);
321 MoreBlockZero(unpackCursor
, count
);
322 unpackCursor
+= count
;
326 case kPEFPkDataBlock
:
330 offset
+= DecodeInstrCountValue(&packedData
[offset
], &blockSize
);
332 BlockMoveData(&packedData
[offset
], unpackCursor
, blockSize
);
333 unpackCursor
+= blockSize
;
338 case kPEFPkDataRepeat
:
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
;
356 case kPEFPkDataRepeatBlock
:
361 const UInt8
*commonData
;
362 const UInt8
*customData
;
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
;
385 case kPEFPkDataRepeatZero
:
390 const UInt8
*customData
;
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
;
414 DebugStr("\pUnpackPEFDataSection: Unexpected data opcode");
416 err
= cfragFragmentCorruptErr
;
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
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
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
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.
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
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
511 // 3. Subtract 2 from 3.
514 TVector
* relocatedExport
;
517 PEFSectionHeader
* initSectionHeader
;
518 Ptr packedDataSection
;
519 Ptr unpackedDataSection
;
520 TVector originalOffsets
;
522 packedDataSection
= nil
;
523 unpackedDataSection
= nil
;
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
;
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.
539 initSection
= fragToFix
->loaderSection
->initSection
;
540 initOffset
= fragToFix
->loaderSection
->initOffset
;
541 if (initSection
== -1) {
542 err
= cfragFragmentUsageErr
;
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
);
562 unpackedDataSection
= NewPtr(initSectionHeader
->unpackedLength
);
566 // Read the contents of the packed section.
569 err
= FSReadAtOffset( fragToFix
->fileRef
,
570 fragToFix
->locator
.offset
571 + initSectionHeader
->containerOffset
,
572 initSectionHeader
->containerLength
,
576 // Unpack the data into the unpacked section.
579 err
= UnpackPEFDataSection( (UInt8
*) packedDataSection
, initSectionHeader
->containerLength
,
580 (UInt8
*) unpackedDataSection
, initSectionHeader
->unpackedLength
);
583 // Extract the init routine's TVector from the unpacked section.
586 BlockMoveData(unpackedDataSection
+ initOffset
, &originalOffsets
, sizeof(TVector
));
590 MoreAssertQ(fragToFix
->sectionHeaders
[initSection
].sectionKind
== kPEFUnpackedDataSection
);
591 err
= FSReadAtOffset(fragToFix
->fileRef
,
592 fragToFix
->locator
.offset
593 + fragToFix
->sectionHeaders
[initSection
].containerOffset
602 // Do the maths to subtract the unrelocated offsets from the current address
603 // to get the base address.
606 fragToFix
->section0Base
= ((char *) relocatedExport
->codePtr
) - (UInt32
) originalOffsets
.codePtr
;
607 fragToFix
->section1Base
= ((char *) relocatedExport
->tocPtr
) - (UInt32
) originalOffsets
.tocPtr
;
612 if (packedDataSection
!= nil
) {
613 DisposePtr(packedDataSection
);
614 MoreAssertQ( MemError() == noErr
);
616 if (unpackedDataSection
!= nil
) {
617 DisposePtr(unpackedDataSection
);
618 MoreAssertQ( MemError() == noErr
);
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
635 MoreAssertQ(fragToFix
!= nil
);
636 MoreAssertQ(fragToFix
->containerHeader
.tag1
== kPEFTag1
);
638 switch (sectionIndex
) {
640 result
= fragToFix
->section0Base
;
643 result
= fragToFix
->section1Base
;
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.
659 UInt32 librariesRemaining
;
660 PEFImportedLibrary
*thisImportLibrary
;
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
;
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.
684 thisImportLibrary
+= 1;
685 librariesRemaining
-= 1;
690 *importLibrary
= thisImportLibrary
;
693 *importLibrary
= nil
;
694 err
= cfragNoLibraryErr
;
699 static OSStatus
LookupSymbol(CFMLateImportLookupProc lookup
, void *refCon
,
700 PEFLoaderInfoHeader
*loaderSection
,
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.
718 UInt32
*importSymbolTable
;
719 UInt32 symbolStringOffset
;
720 Boolean symbolIsWeak
;
721 CFragSymbolClass symbolClass
;
722 char *symbolStringAddress
;
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
);
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.
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
;
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
,
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".
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
) {
845 if (fragToFix
->sectionHeaders
[0].defaultAddress
!= 0) {
846 DebugStr("\pInitEngineState: Executing weird case.");
849 (char *) state
->sectionC
-= fragToFix
->sectionHeaders
[0].defaultAddress
;
851 state
->sectionD
= GetSectionBaseAddress(fragToFix
, 1);
852 if (state
->sectionD
!= nil
) {
854 if (fragToFix
->sectionHeaders
[1].defaultAddress
!= 0) {
855 DebugStr("\pInitEngineState: Executing weird case.");
858 (char *) state
->sectionD
-= fragToFix
->sectionHeaders
[1].defaultAddress
;
862 if (state
->relocAddress
== nil
) {
863 err
= cfragFragmentUsageErr
;
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.
887 UInt16 sectionsLeftToRelocate
;
889 UInt16
*relocInstrTable
;
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).
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
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
962 while ( sectionsLeftToRelocate
> 0 ) {
963 err
= InitEngineState(fragToFix
, sectionsLeftToRelocate
, &state
);
968 while ( state
.currentReloc
!= state
.terminatingReloc
) {
970 MoreAssertQ( state
.currentReloc
< totalRelocs
);
972 opCode
= relocInstrTable
[state
.currentReloc
];
973 switch ( PEFRelocBasicOpcode(opCode
) ) {
974 case kPEFRelocBySectDWithSkip
:
979 skipCount
= ((opCode
>> 6) & 0x00FF);
980 relocCount
= (opCode
& 0x003F);
981 state
.relocAddress
+= skipCount
;
982 state
.relocAddress
+= relocCount
;
985 case kPEFRelocBySectC
:
986 case kPEFRelocBySectD
:
990 runLength
= (opCode
& 0x01FF) + 1;
991 state
.relocAddress
+= runLength
;
994 case kPEFRelocTVector12
:
998 runLength
= (opCode
& 0x01FF) + 1;
999 state
.relocAddress
+= (runLength
* 3);
1002 case kPEFRelocTVector8
:
1003 case kPEFRelocVTable8
:
1007 runLength
= (opCode
& 0x01FF) + 1;
1008 state
.relocAddress
+= (runLength
* 2);
1011 case kPEFRelocImportRun
:
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
);
1023 *(state
.relocAddress
) += symbolValue
;
1025 state
.importIndex
+= 1;
1026 state
.relocAddress
+= 1;
1031 case kPEFRelocSmByImport
:
1036 index
= (opCode
& 0x01FF);
1037 if ( index
>= importLibrary
->firstImportedSymbol
&& index
< (importLibrary
->firstImportedSymbol
+ importLibrary
->importedSymbolCount
) ) {
1038 err
= LookupSymbol(lookup
, refCon
, fragToFix
->loaderSection
, index
, &symbolValue
);
1042 *(state
.relocAddress
) += symbolValue
;
1044 state
.importIndex
= index
+ 1;
1045 state
.relocAddress
+= 1;
1048 case kPEFRelocSmSetSectC
:
1052 index
= (opCode
& 0x01FF);
1053 state
.sectionC
= GetSectionBaseAddress(fragToFix
, index
);
1054 MoreAssertQ(state
.sectionC
!= nil
);
1057 case kPEFRelocSmSetSectD
:
1061 index
= (opCode
& 0x01FF);
1062 state
.sectionD
= GetSectionBaseAddress(fragToFix
, index
);
1063 MoreAssertQ(state
.sectionD
!= nil
);
1066 case kPEFRelocSmBySection
:
1067 state
.relocAddress
+= 1;
1069 case kPEFRelocIncrPosition
:
1073 offset
= (opCode
& 0x0FFF) + 1;
1074 ((char *) state
.relocAddress
) += offset
;
1077 case kPEFRelocSmRepeat
:
1079 DebugStr("\pRunRelocationEngine: kPEFRelocSmRepeat not yet implemented");
1084 case kPEFRelocSetPosition
:
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
);
1107 case kPEFRelocLgByImport
:
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
);
1122 *(state
.relocAddress
) += symbolValue
;
1124 state
.importIndex
= index
+ 1;
1125 state
.relocAddress
+= 1;
1128 case kPEFRelocLgRepeat
:
1130 DebugStr("\pRunRelocationEngine: kPEFRelocLgRepeat not yet implemented");
1135 case kPEFRelocLgSetOrBySection
:
1137 DebugStr("\pRunRelocationEngine: kPEFRelocLgSetOrBySection not yet implemented");
1142 case kPEFRelocUndefinedOpcode
:
1143 err
= cfragFragmentCorruptErr
;
1148 err
= cfragFragmentCorruptErr
;
1152 state
.currentReloc
+= 1;
1155 sectionsLeftToRelocate
-= 1;
1162 extern pascal OSStatus
CFMLateImportCore(const CFragSystem7DiskFlatLocator
*fragToFixLocator
,
1163 CFragConnectionID fragToFixConnID
,
1164 CFragInitFunction fragToFixInitRoutine
,
1165 ConstStr255Param weakLinkedLibraryName
,
1166 CFMLateImportLookupProc lookup
,
1168 // See comments in interface part.
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
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
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.
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.
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.
1223 if ((importLibrary
->options
& kPEFWeakImportLibMask
) == 0) {
1224 err
= cfragFragmentUsageErr
;
1228 // Now run the main relocation engine.
1231 err
= RunRelocationEngine(&fragToFix
, importLibrary
, lookup
, refCon
);
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
);
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.
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
);
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
1275 if (foundSymClass
!= symClass
) {
1278 err
= cfragNoSymbolErr
;
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.
1302 CFBundleRef bundleToImport
;
1303 CFStringRef symNameStr
;
1305 MoreAssertQ(symName
!= nil
);
1306 MoreAssertQ(symAddr
!= nil
);
1307 MoreAssertQ(refCon
!= 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.
1327 if (symClass
!= kTVectorCFragSymbol
) {
1329 err
= cfragNoSymbolErr
;
1332 symNameStr
= CFStringCreateWithPascalString(kCFAllocatorSystemDefault
,
1333 symName
, kCFStringEncodingMacRoman
);
1334 if (symNameStr
== nil
) {
1335 err
= coreFoundationUnknownErr
;
1339 *symAddr
= CFBundleGetFunctionPointerForName(bundleToImport
, symNameStr
);
1340 if (*symAddr
== nil
) {
1341 err
= cfragNoSymbolErr
;
1344 if (symNameStr
!= nil
) {
1345 CFRelease(symNameStr
);
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
);