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