/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #if __ppc__ #include "IOPEFInternals.h" // =========================================================================================== #define PEF_Assert(a) if( !(a)) kprintf("PEF_Assert:") #define PEF_BlockMove(src,dst,len) memcpy(dst,src,len) #define PEF_BlockClear(dst,len) memset(dst,0,len) #define PEF_CompareBytes(a,b,c) (0 == bcmp(a,b,c)) #define EnableCFMDebugging 0 // =========================================================================================== enum { kPEFHandlerProcCount = 18 }; static CFContHandlerProcs PEFHandlerProcs = { kPEFHandlerProcCount, kCFContHandlerABIVersion, PEF_OpenContainer, // 1 PEF_CloseContainer, // 2 PEF_GetContainerInfo, // 3 PEF_GetSectionCount, // 4 PEF_GetSectionInfo, // 5 PEF_FindSectionInfo, // 6 PEF_SetSectionAddress, // 7 PEF_GetAnonymousSymbolLocations, // 8 PEF_GetExportedSymbolCount, // 9 PEF_GetExportedSymbolInfo, // 10 PEF_FindExportedSymbolInfo, // 11 PEF_GetImportCounts, // 12 PEF_GetImportedLibraryInfo, // 13 PEF_GetImportedSymbolInfo, // 14 PEF_SetImportedSymbolAddress, // 15 PEF_UnpackSection, // 16 PEF_RelocateSection, // 17 PEF_RelocateImportsOnly, // 18 }; #if EnableCFMDebugging static char gDebugMessage [256]; #endif // =========================================================================================== const unsigned char opcode [128] = { krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krDDAT,krDDAT,krDDAT,krDDAT, krCODE,krDATA,krDESC,krDSC2, krVTBL,krSYMR,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krSYMB,krCDIS,krDTIS,krSECN, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krDELT,krDELT,krDELT,krDELT, krDELT,krDELT,krDELT,krDELT, krRPT ,krRPT ,krRPT ,krRPT , krRPT ,krRPT ,krRPT ,krRPT , krLABS,krLABS,krLSYM,krLSYM, krXXXX,krXXXX,krXXXX,krXXXX, krLRPT,krLRPT,krLSEC,krLSEC, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, krXXXX,krXXXX,krXXXX,krXXXX, }; // ¤ // =========================================================================================== // GetNameLength () // ================ static ByteCount GetNameLength ( BytePtr nameStart ) { BytePtr nameEnd = nameStart; if (nameStart != NULL) { while (*nameEnd != 0) nameEnd += 1; } return (nameEnd - nameStart); } // GetNameLength () // ¤ // =========================================================================================== // FindRelocationInfo () // ===================== static LoaderRelExpHeader * FindRelocationInfo ( PEFPrivateInfo * pefPrivate, ItemCount sectionIndex ) { LoaderRelExpHeader * relocInfo = NULL; const ItemCount loopLimit = pefPrivate->ldrHeader->numSections; ItemCount relocIndex; for (relocIndex = 0; relocIndex < loopLimit; relocIndex += 1) { relocInfo = &pefPrivate->ldrSections[relocIndex]; if (sectionIndex == (ItemCount) relocInfo->sectionNumber) return relocInfo; } return NULL; } // FindRelocationInfo () // ¤ // =========================================================================================== // GetSectionName () // ================= static void GetSectionName ( PEFPrivateInfo * pefPrivate, SectionHeader * sectionHeader, CFContHashedName * sectionName ) { CFContStringHash nameHash = 0; BytePtr nameText = NULL; ByteCount nameLength; if (sectionHeader->sectionName != ((ByteCount) -1)) { nameText = pefPrivate->stringTable + sectionHeader->sectionName; nameLength = GetNameLength ( nameText ); nameHash = CFContHashName ( nameText, nameLength ); } sectionName->nameHash = nameHash; sectionName->nameText = nameText; } // GetSectionName () // ¤ // =========================================================================================== // PEF_OpenContainer () // ==================== OSStatus PEF_OpenContainer ( LogicalAddress mappedAddress, LogicalAddress runningAddress, ByteCount containerLength, CFContOpenOptions options, CFContAllocateMem Allocate, CFContReleaseMem Release, CFContHandlerRef * containerRef, CFContHandlerProcsPtr * handlerProcs, UInt32 * createDate ) { #pragma unused ( containerLength ) #pragma unused ( runningProcessID ) #pragma unused ( cfragName ) OSStatus err = -1;//cfragCFMInternalErr; FileHeader * fileHeader = (FileHeader *) mappedAddress; PEFPrivateInfo * pefPrivate = NULL; SectionHeader * loaderSection = NULL; SInt32 sectionIndex; if ((sizeof (PEF_SBits32) != 4) | (sizeof (PEF_UBits32) != 4)) goto InternalError; // ! Is "int" 32 bits? if ((Allocate == NULL) || (Release == NULL) || (containerRef == NULL) || (handlerProcs == NULL)) goto ParameterError; *containerRef = NULL; // Clear for errors, only set on OK path. *handlerProcs = NULL; // --------------------------------------------------------------------------------- // Allow the container address to be null as a special case to get the loader procs. // Otherwise validate the header as acceptable PEF. if (mappedAddress == NULL) goto OK; if ((fileHeader->magic1 != kPEFMagic1) || (fileHeader->magic2 != kPEFMagic2) || (fileHeader->fileTypeID != kPEFTypeID) || (fileHeader->versionNumber != kPEFVersion)) goto FragmentFormatError; if (createDate) *createDate = fileHeader->dateTimeStamp; // ----------------------------------------------- // Allocate and initialize the private info block. pefPrivate = (PEFPrivateInfo *) ((*Allocate) ( sizeof ( PEFPrivateInfo ) )); if (pefPrivate == NULL) goto PrivateMemoryError; PEF_BlockClear ( pefPrivate, sizeof ( *pefPrivate ) ); pefPrivate->Allocate = Allocate; pefPrivate->Release = Release; pefPrivate->mappedContainer = (BytePtr) mappedAddress; pefPrivate->runningContainer = (BytePtr) runningAddress; pefPrivate->sectionCount = fileHeader->loadableSections; pefPrivate->sections = (SectionHeader *) (fileHeader + 1); pefPrivate->stringTable = (BytePtr) (&pefPrivate->sections[fileHeader->numberSections]); pefPrivate->loadInPlace = ((options & kCFContPrepareInPlaceMask) != 0); // ----------------------------------------------------- // Find the loader section and extract important fields. for (sectionIndex = 0; sectionIndex < fileHeader->numberSections; sectionIndex += 1) { loaderSection = & pefPrivate->sections[sectionIndex]; if (loaderSection->regionKind == kPEFLoaderSection) break; } if (sectionIndex == fileHeader->numberSections) goto FragmentCorruptError; pefPrivate->ldrSectionNo = sectionIndex; pefPrivate->ldrHeader = (LoaderHeader *) ((BytePtr)mappedAddress + loaderSection->containerOffset); pefPrivate->ldrStringTable = (BytePtr)pefPrivate->ldrHeader + pefPrivate->ldrHeader->stringsOffset; pefPrivate->ldrImportFiles = (LoaderImportFileID *) (pefPrivate->ldrHeader + 1); pefPrivate->ldrImportSymbols = (LoaderImport *) (pefPrivate->ldrImportFiles + pefPrivate->ldrHeader->numImportFiles); pefPrivate->ldrSections = (LoaderRelExpHeader *) (pefPrivate->ldrImportSymbols + pefPrivate->ldrHeader->numImportSyms); pefPrivate->ldrRelocations = (BytePtr)pefPrivate->ldrHeader + pefPrivate->ldrHeader->relocationsOffset; pefPrivate->ldrHashSlot = (HashSlotEntry *) ((BytePtr)pefPrivate->ldrHeader + pefPrivate->ldrHeader->hashSlotTable); pefPrivate->ldrHashChain = (HashChainEntry *) (pefPrivate->ldrHashSlot + (1 << pefPrivate->ldrHeader->hashSlotTabSize)); pefPrivate->ldrExportSymbols = (LoaderExport *) (pefPrivate->ldrHashChain + pefPrivate->ldrHeader->numExportSyms); // ---------------------------------------------------- // Set up the array to store resolved import addresses. if (pefPrivate->ldrHeader->numImportSyms > 0) { pefPrivate->imports = (BytePtr *) ((*Allocate) ( pefPrivate->ldrHeader->numImportSyms * sizeof ( BytePtr ) )); if (pefPrivate->imports == NULL) goto PrivateMemoryError; } // ----------------------------------------------------------------- // Set up the pointers to the arrays of section origins and offsets. if (pefPrivate->sectionCount <= kBuiltinSectionArraySize) { pefPrivate->mappedOrigins = & pefPrivate->originArray[0]; pefPrivate->runningOffsets = & pefPrivate->offsetArray[0]; } else { pefPrivate->mappedOrigins = (BytePtr *) ((*Allocate) ( pefPrivate->sectionCount * sizeof ( BytePtr ) )); if (pefPrivate->mappedOrigins == NULL) goto PrivateMemoryError; pefPrivate->runningOffsets = (ByteCount *) ((*Allocate) ( pefPrivate->sectionCount * sizeof ( ByteCount ) )); if (pefPrivate->runningOffsets == NULL) goto PrivateMemoryError; } // --------------------------------------------------------------------------------------- // Fill in the origin and offset arrays. The origin array gives the base address of the // section instance as visible in the loader's address space. I.e. it tells the loader // where it can access the loaded section contents. The offset array tells what to add // for relocations refering to that section. So it must be based on running addresses and // must "remove" the presumed running address. If the section will be used in place we // must compute the final values here. Otherwise SetRegionAddress will be called later to // provide the mapped and running addresses. Validate load in place restrictions too. // ??? We really ought to consider getting rid of the preset for in-place usage and make // ??? that case as close as possible to the normal case. // ! Note that although the ByteCount type used in the offset arrays is unsigned, ignoring // ! overflow lets things work right for a full -4GB to +4GB offset range. for (sectionIndex = 0; ((ItemCount) sectionIndex) < pefPrivate->sectionCount; sectionIndex += 1) { SectionHeader * section = & pefPrivate->sections[sectionIndex]; pefPrivate->mappedOrigins[sectionIndex] = (BytePtr) -1; // ! Just a diagnostic tag. pefPrivate->runningOffsets[sectionIndex] = - ((ByteCount) section->sectionAddress); // Subtract the presumed address. if (pefPrivate->loadInPlace) { if ((section->regionKind == kPEFPIDataSection) || (section->execSize != section->rawSize)) goto FragmentUsageError; section->sectionAddress = pefPrivate->runningContainer + section->containerOffset; pefPrivate->mappedOrigins[sectionIndex] = pefPrivate->mappedContainer + section->containerOffset; pefPrivate->runningOffsets[sectionIndex] += (ByteCount) section->sectionAddress; // Add in the new address. } } if (options & kCFContPrepareInPlaceMask) fileHeader->memoryAddress = runningAddress; OK: err = noErr; *handlerProcs = &PEFHandlerProcs; *containerRef = (CFContHandlerRef) pefPrivate; EXIT: return err; ERROR: (void) PEF_CloseContainer ( (CFContHandlerRef) pefPrivate, kNilOptions ); goto EXIT; InternalError: err = cfragCFMInternalErr; goto ERROR; ParameterError: err = paramErr; goto ERROR; FragmentFormatError: err = cfragFragmentFormatErr; goto ERROR; PrivateMemoryError: err = cfragNoPrivateMemErr; goto ERROR; FragmentCorruptError: err = cfragFragmentCorruptErr; goto ERROR; FragmentUsageError: err = cfragFragmentUsageErr; goto ERROR; } // PEF_OpenContainer () // ¤ // =========================================================================================== // PEF_CloseContainer () // ===================== OSStatus PEF_CloseContainer ( CFContHandlerRef containerRef, CFContCloseOptions options ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; CFContReleaseMem Release = NULL; if (pefPrivate == NULL) goto OK; // Simplifies error cleanup from PEF_OpenContainer. Release = pefPrivate->Release; if (pefPrivate->sectionCount > kBuiltinSectionArraySize) { if (pefPrivate->mappedOrigins != NULL) { (*Release) ( pefPrivate->mappedOrigins ); pefPrivate->mappedOrigins = NULL; } if (pefPrivate->runningOffsets != NULL) { (*Release) ( pefPrivate->runningOffsets ); pefPrivate->runningOffsets = NULL; } } if (pefPrivate->imports != NULL) { (*Release) ( pefPrivate->imports ); pefPrivate->imports = NULL; } pefPrivate->resolved = 0; // ! Disables reexported import optimization. if (! (options & kCFContPartialCloseMask)) (*Release) ( pefPrivate ); OK: err = noErr; return err; } // PEF_CloseContainer () // ¤ // =========================================================================================== // PEF_GetContainerInfo () // ======================= OSStatus PEF_GetContainerInfo ( CFContHandlerRef containerRef, PBVersion infoVersion, CFContContainerInfo * containerInfo ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; FileHeader * fileHeader = NULL; if ((pefPrivate == NULL) || (containerInfo == NULL)) goto ParameterError; if (infoVersion != kCFContContainerInfoVersion) goto ParameterError; fileHeader = (FileHeader *) pefPrivate->mappedContainer; containerInfo->cfragName.nameHash = 0; // PEF does not have an embedded name. containerInfo->cfragName.nameText = NULL; containerInfo->modDate = fileHeader->dateTimeStamp; containerInfo->architecture = fileHeader->architectureID; containerInfo->currentVersion = fileHeader->currentVersion; containerInfo->oldImpVersion = fileHeader->oldImpVersion; containerInfo->oldDefVersion = fileHeader->oldDefVersion; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetContainerInfo () // ¤ // =========================================================================================== // PEF_GetSectionCount () // ====================== OSStatus PEF_GetSectionCount ( CFContHandlerRef containerRef, ItemCount * sectionCount ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; if ((pefPrivate == NULL) || (sectionCount == NULL)) goto ParameterError; *sectionCount = pefPrivate->sectionCount; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetSectionCount () // ¤ // =========================================================================================== // PEF_GetSectionInfo () // ===================== OSStatus PEF_GetSectionInfo ( CFContHandlerRef containerRef, ItemCount sectionIndex, PBVersion infoVersion, CFContSectionInfo * sectionInfo ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; SectionHeader * sectionHeader = NULL; if ((pefPrivate == NULL) || (sectionInfo == NULL)) goto ParameterError; if (infoVersion != kCFContSectionInfoVersion) goto ParameterError; if (sectionIndex >= pefPrivate->sectionCount) goto ParameterError; sectionHeader = &pefPrivate->sections[sectionIndex]; GetSectionName ( pefPrivate, sectionHeader, §ionInfo->sectionName ); sectionInfo->sharing = sectionHeader->shareKind; sectionInfo->alignment = sectionHeader->alignment; sectionInfo->reservedA = 0; sectionInfo->containerOffset = sectionHeader->containerOffset; sectionInfo->containerLength = sectionHeader->rawSize; sectionInfo->unpackedLength = sectionHeader->initSize; sectionInfo->totalLength = sectionHeader->execSize; sectionInfo->defaultAddress = sectionHeader->sectionAddress; sectionInfo->options = kNilOptions; if (FindRelocationInfo (pefPrivate, sectionIndex) != NULL) sectionInfo->options |= kRelocatedCFContSectionMask; switch (pefPrivate->sections[sectionIndex].regionKind) { case kPEFCodeSection : sectionInfo->access = kCFContNormalCode; break; case kPEFDataSection : sectionInfo->access = kCFContWriteableData; break; case kPEFPIDataSection : sectionInfo->access = kCFContWriteableData; sectionInfo->options |= kPackedCFContSectionMask; break; case kPEFConstantSection : sectionInfo->access = kCFContReadOnlyData; break; case kPEFExecDataSection : sectionInfo->access = kCFContWriteableData | kCFContMemExecuteMask; break; default : sectionInfo->access = kCFContReadOnlyData; // ! Not necessarily right, but safe. break; } err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetSectionInfo () // ¤ // =========================================================================================== // PEF_FindSectionInfo () // ====================== OSStatus PEF_FindSectionInfo ( CFContHandlerRef containerRef, const CFContHashedName * sectionName, PBVersion infoVersion, ItemCount * sectionIndex, // May be null. CFContSectionInfo * sectionInfo ) // May be null. { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; SectionHeader * sectionHeader = NULL; CFContHashedName hashedName; ItemCount tempIndex; CFContSectionInfo tempInfo; if (pefPrivate == NULL) goto ParameterError; if ((sectionInfo != NULL) && (infoVersion != kCFContSectionInfoVersion)) goto ParameterError; if (sectionIndex == NULL) sectionIndex = &tempIndex; if (sectionInfo == NULL) sectionInfo = &tempInfo; for (tempIndex = 0; tempIndex < pefPrivate->sectionCount; tempIndex += 1) { sectionHeader = &pefPrivate->sections[tempIndex]; GetSectionName ( pefPrivate, sectionHeader, &hashedName ); if ((hashedName.nameHash == sectionName->nameHash) && (PEF_CompareBytes (hashedName.nameText, sectionName->nameText, CFContStringHashLength (hashedName.nameHash)))) break; } if (tempIndex == pefPrivate->sectionCount) goto NoSectionError; *sectionIndex = tempIndex; err = PEF_GetSectionInfo ( containerRef, tempIndex, infoVersion, sectionInfo ); if (err != noErr) goto ERROR; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; NoSectionError: err = cfragNoSectionErr; goto ERROR; } // PEF_FindSectionInfo () // ¤ // =========================================================================================== // PEF_SetSectionAddress () // ======================== OSStatus PEF_SetSectionAddress ( CFContHandlerRef containerRef, ItemCount sectionIndex, LogicalAddress mappedAddress, LogicalAddress runningAddress ) { OSErr err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; SectionHeader * section = NULL; if ((pefPrivate == NULL) || (sectionIndex >= pefPrivate->sectionCount)) goto ParameterError; // -------------------------------------------------------------------------------------- // For a load in place usage we've already set the addresses, make sure these match. // Otherwise set both addresses. Note that the "presumed" address is already subtracted. section = & pefPrivate->sections[sectionIndex]; if (! pefPrivate->loadInPlace) { pefPrivate->mappedOrigins[sectionIndex] = (BytePtr) mappedAddress; pefPrivate->runningOffsets[sectionIndex] += (ByteCount) runningAddress; } else { if ((runningAddress != section->sectionAddress) || (mappedAddress != pefPrivate->mappedOrigins[sectionIndex])) goto UsageError; } err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; UsageError: err = cfragFragmentUsageErr; goto ERROR; } // PEF_SetSectionAddress () // ¤ // =========================================================================================== // PEF_GetAnonymousSymbolLocations () // ================================== extern OSStatus PEF_GetAnonymousSymbolLocations ( CFContHandlerRef containerRef, CFContLogicalLocation * mainLocation, // May be null. CFContLogicalLocation * initLocation, // May be null. CFContLogicalLocation * termLocation ) // May be null. { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; LoaderHeader * ldrHeader = NULL; CFContLogicalLocation tempLocation; if ((pefPrivate == NULL)) goto ParameterError; if (mainLocation == NULL) mainLocation = &tempLocation; if (initLocation == NULL) initLocation = &tempLocation; if (termLocation == NULL) termLocation = &tempLocation; ldrHeader = pefPrivate->ldrHeader; mainLocation->section = ldrHeader->entryPointSection; mainLocation->offset = ldrHeader->entryPointOffset; initLocation->section = ldrHeader->initPointSection; initLocation->offset = ldrHeader->initPointOffset; termLocation->section = ldrHeader->termPointSection; termLocation->offset = ldrHeader->termPointOffset; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetAnonymousSymbolLocations () // ¤ // =========================================================================================== // PEF_GetExportedSymbolCount () // ============================= extern OSStatus PEF_GetExportedSymbolCount ( CFContHandlerRef containerRef, ItemCount * exportCount ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; if ((pefPrivate == NULL) || (exportCount == NULL)) goto ParameterError; *exportCount = pefPrivate->ldrHeader->numExportSyms; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetExportedSymbolCount () // ¤ // =========================================================================================== // PEF_GetExportedSymbolInfo () // ============================ OSStatus PEF_GetExportedSymbolInfo ( CFContHandlerRef containerRef, CFContSignedIndex exportIndex, PBVersion infoVersion, CFContExportedSymbolInfo * exportInfo ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; LoaderExport * exportedSymbol = NULL; if ((pefPrivate == NULL) || (exportInfo == NULL)) goto ParameterError; if ((ItemCount) exportIndex >= pefPrivate->ldrHeader->numExportSyms) goto ParameterError; if (infoVersion != kCFContExportedSymbolInfoVersion) goto ParameterError; if (exportIndex >= 0) { exportedSymbol = &pefPrivate->ldrExportSymbols[exportIndex]; exportInfo->symbolName.nameHash = pefPrivate->ldrHashChain[exportIndex].hashword; exportInfo->symbolName.nameText = &pefPrivate->ldrStringTable[exportedSymbol->nameOffset]; exportInfo->symbolClass = exportedSymbol->symClass; exportInfo->reservedA = 0; exportInfo->reservedB = 0; exportInfo->options = kNilOptions; exportInfo->location.section = exportedSymbol->sectionNumber; #if 1 // *** Disable the reexported import optimization. exportInfo->location.offset = exportedSymbol->offset; #else // This is the buggy optimization. It has problems with missing weak libraries. // Addition of a "resolvedImports" bit vector is probably the way to fix it, but it // may not be much of an optimization then. if ((! pefPrivate->resolved) || (exportedSymbol->sectionNumber != kReExportImport)) { exportInfo->location.offset = exportedSymbol->address; } else { exportInfo->location.section = kPhysicalExport; exportInfo->location.offset = pefPrivate->imports[exportedSymbol->address]; } #endif } else { CFContLogicalLocation mainLocation; CFContLogicalLocation initLocation; CFContLogicalLocation termLocation; err = PEF_GetAnonymousSymbolLocations ( containerRef, &mainLocation, &initLocation, &termLocation ); if (err != noErr) goto ERROR; switch (exportIndex) { case kMainCFragSymbolIndex : exportInfo->location = mainLocation; exportInfo->symbolClass = 0xFF; // !!! Ought to have a kUnknownCFragSymbol constant. break; case kInitCFragSymbolIndex : exportInfo->location = initLocation; exportInfo->symbolClass = kTVectorCFragSymbol; // ! Very well better be! break; case kTermCFragSymbolIndex : exportInfo->location = termLocation; exportInfo->symbolClass = kTVectorCFragSymbol; // ! Very well better be! break; default : goto ParameterError; } exportInfo->symbolName.nameHash = 0; exportInfo->symbolName.nameText = NULL; exportInfo->reservedA = 0; exportInfo->reservedB = 0; exportInfo->options = kNilOptions; } err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetExportedSymbolInfo () // ¤ // =========================================================================================== // PEF_FindExportedSymbolInfo () // ============================= OSStatus PEF_FindExportedSymbolInfo ( CFContHandlerRef containerRef, const CFContHashedName * exportName, PBVersion infoVersion, ItemCount * exportIndex_o, // May be null. CFContExportedSymbolInfo * exportInfo ) // May be null. { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; LoaderExport * exportedSymbol = NULL; CFContStringHash * hashwordList = NULL; CFContStringHash * nextHashword = NULL; HashSlotEntry * hashSlot = NULL; ByteCount nameLength = CFContStringHashLength ( exportName->nameHash ); ItemCount exportIndex; ItemCount slotIndex; ItemCount chainLimit; Boolean nameMatch; if (pefPrivate == NULL) goto ParameterError; if (infoVersion != kCFContExportedSymbolInfoVersion) goto ParameterError; hashwordList = &pefPrivate->ldrHashChain[0].hashword; slotIndex = GetPEFHashSlot ( exportName->nameHash, pefPrivate->ldrHeader->hashSlotTabSize ); hashSlot = &pefPrivate->ldrHashSlot[slotIndex]; exportIndex = hashSlot->chainIndex; chainLimit = exportIndex + hashSlot->chainCount; nextHashword = &hashwordList[exportIndex]; while (exportIndex < chainLimit) { if (*nextHashword == exportName->nameHash) { exportedSymbol = &pefPrivate->ldrExportSymbols[exportIndex]; nameMatch = PEF_CompareBytes ( exportName->nameText, &pefPrivate->ldrStringTable[exportedSymbol->nameOffset], nameLength ); if (nameMatch) goto Found; } exportIndex += 1; nextHashword += 1; // ! Pointer arithmetic. } goto NotFoundError; Found: if (exportIndex_o != NULL) *exportIndex_o = exportIndex; if (exportInfo != NULL) { err = PEF_GetExportedSymbolInfo ( containerRef, exportIndex, infoVersion, exportInfo ); if (err != noErr) goto ERROR; } err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; NotFoundError: err = cfragNoSymbolErr; goto ERROR; } // PEF_FindExportedSymbolInfo () // ¤ // =========================================================================================== // PEF_GetImportCounts () // ====================== OSStatus PEF_GetImportCounts ( CFContHandlerRef containerRef, ItemCount * libraryCount, // May be null. ItemCount * symbolCount ) // May be null. { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; if (pefPrivate == NULL) goto ParameterError; if (libraryCount != NULL) *libraryCount = pefPrivate->ldrHeader->numImportFiles; if (symbolCount != NULL) *symbolCount = pefPrivate->ldrHeader->numImportSyms; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetImportCounts () // ¤ // =========================================================================================== // PEF_GetImportedLibraryInfo () // ============================= OSStatus PEF_GetImportedLibraryInfo ( CFContHandlerRef containerRef, ItemCount libraryIndex, PBVersion infoVersion, CFContImportedLibraryInfo * libraryInfo ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; LoaderImportFileID * importedLibrary = NULL; BytePtr nameText = NULL; ByteCount nameLength; if ((pefPrivate == NULL) || (libraryInfo == NULL)) goto ParameterError; if (infoVersion != kCFContImportedLibraryInfoVersion) goto ParameterError; if (libraryIndex >= pefPrivate->ldrHeader->numImportFiles) goto ParameterError; importedLibrary = &pefPrivate->ldrImportFiles[libraryIndex]; nameText = &pefPrivate->ldrStringTable[importedLibrary->fileNameOffset]; nameLength = GetNameLength ( nameText ); libraryInfo->libraryName.nameHash = CFContHashName ( nameText, nameLength ); libraryInfo->libraryName.nameText = nameText; libraryInfo->linkedVersion = importedLibrary->linkedVersion; libraryInfo->oldImpVersion = importedLibrary->oldImpVersion; libraryInfo->options = kNilOptions; if (importedLibrary->options & kPEFInitBeforeMask) libraryInfo->options |= kCFContInitBeforeMask; if (importedLibrary->options & kPEFWeakLibraryMask) libraryInfo->options |= kCFContWeakLibraryMask; if (importedLibrary->options & kPEFDeferredBindMask) libraryInfo->options |= kCFContDeferredBindMask; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_GetImportedLibraryInfo () // ¤ // =========================================================================================== // PEF_GetImportedSymbolInfo () // ============================ OSStatus PEF_GetImportedSymbolInfo ( CFContHandlerRef containerRef, ItemCount symbolIndex, PBVersion infoVersion, CFContImportedSymbolInfo * symbolInfo ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; LoaderImport * importedSymbol = NULL; LoaderImportFileID * importedLibrary = NULL; BytePtr nameText = NULL; ByteCount nameLength; ItemCount libraryCount; ItemCount libraryIndex; if ((pefPrivate == NULL) || (symbolInfo == NULL)) goto ParameterError; if (infoVersion != kCFContImportedSymbolInfoVersion) goto ParameterError; if (symbolIndex >= pefPrivate->ldrHeader->numImportSyms) goto ParameterError; importedSymbol = &pefPrivate->ldrImportSymbols[symbolIndex]; libraryCount = pefPrivate->ldrHeader->numImportFiles; nameText = &pefPrivate->ldrStringTable[importedSymbol->nameOffset]; nameLength = GetNameLength ( nameText ); symbolInfo->symbolName.nameHash = CFContHashName ( nameText, nameLength ); symbolInfo->symbolName.nameText = nameText; symbolInfo->symbolClass = importedSymbol->symClass & 0x0F; symbolInfo->reservedA = 0; symbolInfo->reservedB = 0; symbolInfo->options = 0; if (importedSymbol->symClass & kPEFWeakSymbolMask) symbolInfo->options |= kCFContWeakSymbolMask; for (libraryIndex = 0; libraryIndex < libraryCount; libraryIndex += 1) { importedLibrary = &pefPrivate->ldrImportFiles[libraryIndex]; if ((importedLibrary->impFirst <= symbolIndex) && (symbolIndex < (importedLibrary->impFirst + importedLibrary->numImports))) { break; } } if (libraryIndex == libraryCount) goto FragmentCorruptError; symbolInfo->libraryIndex = libraryIndex; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; FragmentCorruptError: err = cfragFragmentCorruptErr; goto ERROR; } // PEF_GetImportedSymbolInfo () // ¤ // =========================================================================================== // PEF_SetImportedSymbolAddress () // =============================== OSStatus PEF_SetImportedSymbolAddress ( CFContHandlerRef containerRef, ItemCount symbolIndex, LogicalAddress symbolAddress ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; if (pefPrivate == NULL) goto ParameterError; if (symbolIndex >= pefPrivate->ldrHeader->numImportSyms) goto ParameterError; pefPrivate->imports[symbolIndex] = symbolAddress; err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_SetImportedSymbolAddress () // ¤ // =========================================================================================== // GetPackedDataCount () // ===================== static UInt32 GetPackedDataCount ( UInt8 * * byteHandle ) { UInt32 count = 0; UInt8 * bytePtr = *byteHandle; UInt8 currByte; do { currByte = *bytePtr++; count = (count << kPEFPkDataVCountShift) | (currByte & kPEFPkDataVCountMask); } while ((currByte & kPEFPkDataVCountEndMask) != 0); *byteHandle = bytePtr; return count; } // GetPackedDataCount () // ¤ // =========================================================================================== // UnpackFullSection () // ==================== // ------------------------------------------------------------------------------------------ // This is the "normal" case from CFM, unpacking all of the packed portion. Along the way we // make sure we're not writing beyond the end of the unpacked data. At the end we make sure // that all we didn't read past the end of the packed data, and that all of the output was // written. // ! Note that the xyzEnd pointers are the actual end of the range, not one byte beyond. This // ! routine will work if the output end address is 0xFFFFFFFF, but not if the packed end is. // ! Don't do range comparisons as "(lowAddr + length) > highAddr", because this might wrap // ! the end high end of the address space. Always do "(highAddr - lowAddr) > length". // ??? We should gather some statistics on actual usage to see whether it is worthwhile to // ??? have local customized code for common cases. E.g. block fill of 1, 2, or 4 bytes, or // ??? of interleaved repeats with 1/2/4 byte common or custom portions. static OSStatus UnpackFullSection ( BytePtr packedBase, BytePtr packedEnd, BytePtr outputBase, BytePtr outputEnd ) { OSStatus err = cfragCFMInternalErr; BytePtr packedPos = packedBase; BytePtr outputPos = outputBase; BytePtr outPosLimit = outputEnd + 1; // ! Might be zero if outputEnd is 0xFFFFFFFF. UInt8 currByte; UInt8 opcode; UInt32 count1; UInt32 count2; UInt32 count3; if ((packedEnd + 1) == 0) goto FragmentUsageError; while (packedPos <= packedEnd) { currByte = *packedPos++; opcode = currByte >> kPEFPkDataOpcodeShift; count1 = currByte & kPEFPkDataCount5Mask; if (count1 == 0) count1 = GetPackedDataCount ( &packedPos ); switch (opcode) { case kPEFPkDataZero : if (((UInt32) (outPosLimit - outputPos)) < count1) goto FragmentCorruptError; PEF_BlockClear ( outputPos, count1 ); outputPos += count1; break; case kPEFPkDataBlock : if (((UInt32)(outPosLimit - outputPos)) < count1) goto FragmentCorruptError; PEF_BlockMove ( packedPos, outputPos, count1 ); packedPos += count1; outputPos += count1; break; case kPEFPkDataRepeat : // ??? Need a BlockFill routine? count2 = GetPackedDataCount ( &packedPos ) + 1; // ! Stored count is 1 less. if (((UInt32)(outPosLimit - outputPos)) < (count1 * count2)) goto FragmentCorruptError; if (count1 == 1) { // ??? Is this worth the bother? Other sizes? currByte = *packedPos++; for (; count2 != 0; count2 -= 1) *outputPos++ = currByte; } else { for (; count2 != 0; count2 -= 1) { PEF_BlockMove ( packedPos, outputPos, count1 ); outputPos += count1; } packedPos += count1; } break; case kPEFPkDataRepeatBlock : count2 = GetPackedDataCount ( &packedPos ); count3 = GetPackedDataCount ( &packedPos ); if (((UInt32)(outPosLimit - outputPos)) < (((count1 + count2) * count3) + count1)) goto FragmentCorruptError; { BytePtr commonPos = packedPos; packedPos += count1; // Skip the common part. for (; count3 != 0; count3 -= 1) { PEF_BlockMove ( commonPos, outputPos, count1 ); outputPos += count1; PEF_BlockMove ( packedPos, outputPos, count2 ); packedPos += count2; outputPos += count2; } PEF_BlockMove ( commonPos, outputPos, count1 ); outputPos += count1; } break; case kPEFPkDataRepeatZero : count2 = GetPackedDataCount ( &packedPos ); count3 = GetPackedDataCount ( &packedPos ); if (((UInt32)(outPosLimit - outputPos)) < (((count1 + count2) * count3) + count1)) goto FragmentCorruptError; PEF_BlockClear ( outputPos, count1 ); outputPos += count1; for (; count3 != 0; count3 -= 1) { PEF_BlockMove ( packedPos, outputPos, count2 ); packedPos += count2; outputPos += count2; PEF_BlockClear ( outputPos, count1 ); outputPos += count1; } break; default : goto FragmentCorruptError; } } if ((packedPos != (packedEnd + 1)) || (outputPos != outPosLimit)) goto FragmentCorruptError; err = noErr; EXIT: return err; ERROR: goto EXIT; FragmentUsageError: err = cfragFragmentUsageErr; goto ERROR; FragmentCorruptError: err = cfragFragmentCorruptErr; goto ERROR; } // UnpackFullSection () // ¤ // =========================================================================================== // UnpackPartialSection () // ======================= // ------------------------------------------------------------------------------------------- // This is the case where we want to extract some arbitrary portion of a section as it would // be when instantiated but not relocated. We have to interpret the packed part up to the // desired output start, then continue begin unpacking for real. If we run out of packed data // before filling the output, we fill the rest of the output with zeroes. // ! We have to be very careful in the skip logic because the current operation probably spans // ! the skip/output boundary. We have to be similarly careful at the output end because the // ! current operation probably spans the tail of the output. Don't forget that the partial // ! output at the start could also fill the output and overflow the tail! // ! Note that the xyzEnd pointers are the actual end of the range, not one byte beyond. This // ! routine might not work if outputEnd is 0xFFFFFFFF. This is because outputPos points to // ! the next byte to be written. The loops that are controlled by "outputPos < outputBase" // ! or "outputPos <= outputEnd" would fail in this case if outputPos were "outputEnd + 1", // ! i.e. outputPos would be zero. // ! Don't do range comparisons as "(lowAddr + length) > highAddr", because this might wrap // ! the end high end of the address space. Always do "(highAddr - lowAddr) > length". // ------------------------------------------------------------------------------------------- static void PartialBlockClear ( BytePtr outputBase, ByteCount outputStartOffset, ByteCount outputEndOffset, ByteCount outputOffset, ByteCount count ) { if (((outputOffset + count) <= outputStartOffset) || (outputOffset > outputEndOffset)) return ; // Nothing to output. if (outputOffset < outputStartOffset) { count -= (outputStartOffset - outputOffset); outputOffset = outputStartOffset; } if (count > (outputEndOffset - outputOffset + 1)) count = outputEndOffset - outputOffset + 1; PEF_BlockClear ( outputBase + (outputOffset - outputStartOffset), count ); } // PartialBlockClear (); // ------------------------------------------------------------------------------------------- static void PartialBlockMove ( BytePtr source, BytePtr outputBase, ByteCount outputStartOffset, ByteCount outputEndOffset, ByteCount outputOffset, ByteCount count ) { if (((outputOffset + count) <= outputStartOffset) || (outputOffset > outputEndOffset)) return ; // Nothing to output. if (outputOffset < outputStartOffset) { const ByteCount skipCount = outputStartOffset - outputOffset; source += skipCount; count -= skipCount; outputOffset = outputStartOffset; } if (count > (outputEndOffset - outputOffset + 1)) count = outputEndOffset - outputOffset + 1; PEF_BlockMove ( source, outputBase + (outputOffset - outputStartOffset), count ); } // PartialBlockClear (); // ------------------------------------------------------------------------------------------- static OSStatus UnpackPartialSection ( BytePtr packedBase, BytePtr packedEnd, BytePtr outputBase, BytePtr outputEnd, ByteCount outputStartOffset ) { OSStatus err = cfragCFMInternalErr; const ByteCount outputEndOffset = outputStartOffset + (outputEnd - outputBase); BytePtr packedPos = NULL; BytePtr packedBoundary = NULL; ByteCount outputOffset; ByteCount outputBoundary; UInt8 currByte; UInt8 opcode; UInt32 count1; UInt32 count2; UInt32 count3; if (((packedEnd + 1) == 0) || ((outputEnd + 1) == 0)) goto FragmentUsageError; // -------------------------------------------------------------------------------------- // Skip the packed data until we get within the output range. We know there is something // to unpack, otherwise the zero fill of the output would be done by the caller. This // loop sets outputOffset to the end of what would be unpacked, until the outputOffset is // beyond the outputStartOffset. I.e. until we hit the first operation that would create // actual output. outputOffset = 0; packedPos = packedBase; do { packedBoundary = packedPos; // The start of the current operation. outputBoundary = outputOffset; currByte = *packedPos++; opcode = currByte >> kPEFPkDataOpcodeShift; count1 = currByte & kPEFPkDataCount5Mask; if (count1 == 0) count1 = GetPackedDataCount ( &packedPos ); switch (opcode) { case kPEFPkDataZero : outputOffset += count1; break; case kPEFPkDataBlock : packedPos += count1; outputOffset += count1; break; case kPEFPkDataRepeat : count2 = GetPackedDataCount ( &packedPos ) + 1; // ! Stored count is 1 less. packedPos += count1; outputOffset += count1 * count2; break; case kPEFPkDataRepeatBlock : count2 = GetPackedDataCount ( &packedPos ); count3 = GetPackedDataCount ( &packedPos ); packedPos += count1 + (count2 * count3); outputOffset += count1 + ((count1 + count2) * count3); break; case kPEFPkDataRepeatZero : count2 = GetPackedDataCount ( &packedPos ); count3 = GetPackedDataCount ( &packedPos ); packedPos += count2 * count3; outputOffset += count1 + ((count1 + count2) * count3); break; default : goto FragmentCorruptError; } } while (outputOffset <= outputStartOffset); //---------------------------------------------------------------------------------------- // Now do the actual unpacking. This uses a copy of the full unpack logic with special // block copy/clear routines. These special routines do the bounds checking, only writing // output where actually allowed. This involves "unnecessary" checks for the "middle" // operations that are fully within the range, but vastly simplifies the boundary cases. packedPos = packedBoundary; // Reset to the operation that spans the output start. outputOffset = outputBoundary; do { currByte = *packedPos++; opcode = currByte >> kPEFPkDataOpcodeShift; count1 = currByte & kPEFPkDataCount5Mask; if (count1 == 0) count1 = GetPackedDataCount ( &packedPos ); switch (opcode) { case kPEFPkDataZero : PartialBlockClear ( outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); outputOffset += count1; break; case kPEFPkDataBlock : PartialBlockMove ( packedPos, outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); packedPos += count1; outputOffset += count1; break; case kPEFPkDataRepeat : // ??? Need a BlockFill routine? count2 = GetPackedDataCount ( &packedPos ) + 1; // ! Stored count is 1 less. for (; count2 != 0; count2 -= 1) { PartialBlockMove ( packedPos, outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); outputOffset += count1; } packedPos += count1; break; case kPEFPkDataRepeatBlock : count2 = GetPackedDataCount ( &packedPos ); count3 = GetPackedDataCount ( &packedPos ); { BytePtr commonPos = packedPos; packedPos += count1; // Skip the common part. for (; count3 != 0; count3 -= 1) { PartialBlockMove ( commonPos, outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); outputOffset += count1; PartialBlockMove ( packedPos, outputBase, outputStartOffset, outputEndOffset, outputOffset, count2 ); packedPos += count2; outputOffset += count2; } PartialBlockMove ( commonPos, outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); outputOffset += count1; } break; case kPEFPkDataRepeatZero : count2 = GetPackedDataCount ( &packedPos ); count3 = GetPackedDataCount ( &packedPos ); PartialBlockClear ( outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); outputOffset += count1; for (; count3 != 0; count3 -= 1) { PartialBlockMove ( packedPos, outputBase, outputStartOffset, outputEndOffset, outputOffset, count2 ); packedPos += count2; outputOffset += count2; PartialBlockClear ( outputBase, outputStartOffset, outputEndOffset, outputOffset, count1 ); outputOffset += count1; } break; default : goto FragmentCorruptError; } } while ((outputOffset <= outputEndOffset) && (packedPos <= packedEnd)); // ------------------------------------------ // Finally block clear anything that is left. if (outputOffset <= outputEndOffset) { PEF_BlockClear ( outputBase + (outputOffset - outputStartOffset), outputEndOffset - outputOffset + 1 ); } err = noErr; EXIT: return err; ERROR: goto EXIT; FragmentUsageError: err = cfragFragmentUsageErr; goto ERROR; FragmentCorruptError: err = cfragFragmentCorruptErr; goto ERROR; } // UnpackPartialSection () // ¤ // =========================================================================================== // PEF_UnpackSection () // ==================== OSStatus PEF_UnpackSection ( CFContHandlerRef containerRef, ItemCount sectionIndex, ByteCount sectionOffset, LogicalAddress bufferAddress, ByteCount bufferLength ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; SectionHeader * section = NULL; BytePtr packedBase = NULL; BytePtr packedEnd = NULL; BytePtr outputBase = bufferAddress; BytePtr outputEnd = outputBase + bufferLength - 1; if (pefPrivate == NULL) goto ParameterError; if (sectionIndex >= pefPrivate->sectionCount) goto ParameterError; if ((bufferAddress == NULL) && (bufferLength != 0)) goto ParameterError; section = &pefPrivate->sections[sectionIndex]; if ((sectionOffset + bufferLength) > section->execSize) goto ParameterError; packedBase = pefPrivate->mappedContainer + section->containerOffset; packedEnd = packedBase + section->rawSize - 1; if ((sectionOffset == 0) && (bufferLength == section->initSize)) { err = UnpackFullSection ( packedBase, packedEnd, outputBase, outputEnd ); if (err != noErr) goto ERROR; #if EnableCFMDebugging if (false && EnableCFMDebugging && (section->execSize > 8)) { // Force some tests of partial unpacking. UInt32 word; BytePtr partContents = (*pefPrivate->Allocate) ( section->execSize - 2 ); PEF_Assert ( partContents != NULL ); err = PEF_UnpackSection ( containerRef, sectionIndex, 1, &word, 4 ); PEF_Assert ( err == noErr ); err = PEF_UnpackSection ( containerRef, sectionIndex, section->execSize / 2, &word, 4 ); PEF_Assert ( err == noErr ); err = PEF_UnpackSection ( containerRef, sectionIndex, section->execSize - 5, &word, 4 ); PEF_Assert ( err == noErr ); err = PEF_UnpackSection ( containerRef, sectionIndex, 1, partContents, section->execSize - 2 ); PEF_Assert ( err == noErr ); (*pefPrivate->Release) ( partContents ); } #endif } else { if (section->initSize < sectionOffset) { PEF_BlockClear ( bufferAddress, bufferLength ); } else { err = UnpackPartialSection ( packedBase, packedEnd, outputBase, outputEnd, sectionOffset ); if (err != noErr) goto ERROR; } #if EnableCFMDebugging if (EnableCFMDebugging) { // See if the partial output agrees with full output. BytePtr fullContents = (*pefPrivate->Allocate) ( section->execSize ); PEF_Assert ( fullContents != NULL ); PEF_BlockClear ( fullContents, section->execSize ); err = UnpackFullSection ( packedBase, packedEnd, fullContents, fullContents + section->initSize - 1 ); PEF_Assert ( err == noErr ); PEF_Assert ( PEF_CompareBytes ( fullContents + sectionOffset, bufferAddress, bufferLength ) ); (*pefPrivate->Release) ( fullContents ); } #endif } err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_UnpackSection () // ¤ // =========================================================================================== // PEF_RelocateSection () // ====================== // *** This needs cleaning up. OSStatus PEF_RelocateSection ( CFContHandlerRef containerRef, ItemCount sectionIndex ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; BytePtr * raddr; ByteCount dataA; int cnt; // ! Must be signed. ByteCount codeA; LoaderRelExpHeader * ldRelHdr; Relocation *reloc, *rlend; Relocation r; long rpt; // ! Must be signed. long secn; long rsymi; BytePtr *imports; ByteCount *regions; long i; long relNum; BytePtr regStart; SectionHeader * section; if (pefPrivate == NULL) goto ParameterError; if (sectionIndex >= pefPrivate->sectionCount) goto ParameterError; regStart = pefPrivate->mappedOrigins[sectionIndex]; section = & pefPrivate->sections [sectionIndex]; pefPrivate->resolved = 1; // !!! Really means relocated, and should be set on exit. for (i = 0; ; i++) { if (((ItemCount) i) >= pefPrivate->sectionCount) return noErr; // No relocations for this section. ldRelHdr = & pefPrivate->ldrSections [i]; if (((ItemCount) ldRelHdr->sectionNumber) == sectionIndex) break; } regions = pefPrivate->runningOffsets; imports = pefPrivate->imports; reloc = (Relocation *) (pefPrivate->ldrRelocations + ldRelHdr->relocationsOffset); rlend = (Relocation *) ((RelocInstr *) reloc + ldRelHdr->numRelocations); raddr = (BytePtr *) regStart; // ! Change the stride from 1 to 4. rsymi = 0; codeA = regions [0]; dataA = regions [1]; rpt = 0; #if 0 sprintf ( gDebugMessage, "PLPrepareRegion: start @ %.8X\n", raddr ); PutSerialMesssage ( gDebugMessage ); #endif relNum = 0; while (reloc < rlend) { r = *reloc; reloc = (Relocation *) ((RelocInstr *) reloc + 1); switch (opcode [r.opcode.op]) { case krDDAT : raddr = (BytePtr *) ((BytePtr)raddr + (r.deltadata.delta_d4 * 4)); // ! Reduce stride to 1. cnt = r.deltadata.cnt; while (--cnt >= 0) { *raddr++ += dataA; } break; case krCODE : cnt = r.run.cnt_m1 + 1; while (--cnt >= 0) { *raddr++ += codeA; } break; case krDATA : cnt = r.run.cnt_m1 + 1; while (--cnt >= 0) { *raddr++ += dataA; } break; case krDESC : cnt = r.run.cnt_m1 + 1; while (--cnt >= 0) { *raddr++ += codeA; *raddr++ += dataA; raddr++; } break; case krDSC2 : cnt = r.run.cnt_m1 + 1; while (--cnt >= 0) { *raddr++ += codeA; *raddr++ += dataA; } break; case krVTBL : cnt = r.run.cnt_m1 + 1; while (--cnt >= 0) { *raddr++ += dataA; raddr++; } break; case krSYMR : cnt = r.run.cnt_m1 + 1; while (--cnt >= 0) { *raddr++ += (ByteCount) imports [rsymi++]; } break; case krSYMB : rsymi = r.glp.idx; *raddr++ += (ByteCount) imports [rsymi++]; break; case krCDIS : codeA = regions [r.glp.idx]; break; case krDTIS : dataA = regions [r.glp.idx]; break; case krSECN : *raddr++ += regions [r.glp.idx]; break; case krDELT : raddr = (BytePtr *) ((BytePtr) raddr + r.delta.delta_m1 + 1); // ! Reduce stride to 1. #if 0 sprintf ( gDebugMessage, "PLPrepareRegion: delta to %.8X\n", raddr ); PutSerialMesssage ( gDebugMessage ); #endif break; case krRPT : if (--rpt == 0) break; // count was 1 --> rpt done if (rpt < 0) // first time rpt encountered? rpt = r.rpt.rcnt_m1 + 1; // yes- initialize rpt count cnt = r.rpt.icnt_m1 + 2; // yes or no - back up cnt instrs reloc = (Relocation *) ((RelocInstr *) reloc - cnt); break; case krLABS : raddr = (BytePtr *) ((r.large1.idx_top << 16) + reloc->bot + regStart); reloc = (Relocation *) ((RelocInstr *) reloc + 1); #if 0 sprintf ( gDebugMessage, "PLPrepareRegion: abs to %.8X\n", raddr ); PutSerialMesssage ( gDebugMessage ); #endif break; case krLSYM : rsymi = (r.large1.idx_top << 16) + reloc->bot; reloc = (Relocation *) ((RelocInstr *) reloc + 1); *raddr++ += (ByteCount) imports [rsymi++]; break; case krLRPT : if (--rpt == 0) { reloc = (Relocation *) ((RelocInstr *) reloc + 1); break; } if (rpt < 0) rpt = (r.large2.idx_top << 16) + reloc->bot; cnt = r.large2.cnt_m1 + 2; reloc = (Relocation *) ((RelocInstr *) reloc - cnt); break; case krLSEC : secn = (r.large2.idx_top << 16) + reloc->bot; switch (r.large2.cnt_m1) { case 0 : *raddr++ += regions [secn]; break; case 1 : codeA = regions [secn]; break; case 2 : dataA = regions [secn]; break; } reloc = (Relocation *) ((RelocInstr *) reloc + 1); break; default : goto FragmentCorruptError; } } #if 0 sprintf ( gDebugMessage, "PLPrepareRegion: end @ %.8X\n", raddr ); PutSerialMesssage ( gDebugMessage ); #endif err = noErr; EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; FragmentCorruptError: err = cfragFragmentCorruptErr; goto ERROR; } // PEF_RelocateSection () // ¤ // =========================================================================================== // PEF_RelocateImportsOnly () // ========================== OSStatus PEF_RelocateImportsOnly ( CFContHandlerRef containerRef, ItemCount sectionIndex, ItemCount libraryIndex ) { OSStatus err = cfragCFMInternalErr; PEFPrivateInfo * pefPrivate = (PEFPrivateInfo *) containerRef; if (pefPrivate == NULL) goto ParameterError; if (sectionIndex >= pefPrivate->sectionCount) goto ParameterError; if (libraryIndex >= pefPrivate->ldrHeader->numImportFiles) goto ParameterError; if (pefPrivate == NULL) goto ParameterError; return unimpErr; // !!! Fix this! EXIT: return err; ERROR: goto EXIT; ParameterError: err = paramErr; goto ERROR; } // PEF_RelocateImportsOnly () /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #endif /* __ppc__ */