»Core Development>Code coverage>Mac/Modules/cg/CFMLateImport.c

Python code coverage for Mac/Modules/cg/CFMLateImport.c

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