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