/* * 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@ */ /* * Copyright (c) 1997 Apple Computer, Inc. * * * HISTORY * * sdouglas 22 Oct 97 - first checked in. * sdouglas 21 July 98 - start IOKit */ /* File: PEFLoader.c Contains: PEF loader implementation. Version: Maxwell Copyright: © 1994-1996 by Apple Computer, Inc., all rights reserved. File Ownership: DRI: Alan Lillich Other Contact: <> Technology: Core Runtime Writers: (AWL) Alan Lillich (ELE) Erik Eidt Change History (most recent first): <26> 10/4/96 AWL Disable partial unpacking tests. <25> 9/26/96 AWL Fix assertions to have the right polarity. <24> 9/18/96 AWL Simplify UnpackPartialSection. <23> 8/27/96 AWL Support partial unpacking in PEF_UnpackSection. <22> 8/23/96 AWL (1379028) Propagate changes from CodeFragmentContainerPriv. <21> 8/16/96 AWL Isolate memory utilities to work with both CFM and ProtoCFM. <20> 4/18/96 AWL (1342167) Fix problems with relocations for in-place sections. <19> 4/2/96 AWL (1336962) Fix checks for missing optional parameters. <18> 3/7/96 AWL Remove unused variable in PEF_UnpackSection. <17> 2/28/96 AWL Adapt for new container handler model. <16> 1/19/96 AWL Changes for D11. <15> 10/10/95 AWL Minor cleanup for CodeWarrior's strict checking. <14> 6/14/95 AWL Pick up flags from CFMWhere ASAP. <13> 5/23/95 AWL Introduce temporary hack to workaround build problem for 68K ModernOS booting code. *** THIS BREAKS REAL 68K BUILDS! *** <12> 2/8/95 AWL Update debug output calls. <11> 12/14/94 AWL Changes for Maxwell D4 build. <10> 12/2/94 AWL Disable reexported import optimization because of problems with missing weak libraries. It could be put back later with the addition of a "resolvedImports" bit vector. <9> 9/9/94 AWL Switch to the "real" API and SPI headers. <8> 9/2/94 AWL Error codes are now in Errors.h. <7> 7/28/94 AWL Return cfragSymbolNotFound instead of paramErr from PLFindExportInfo. (#1177313) <6> 7/12/94 AWL Fix load-in-place processing in SetRegionAddress. <5> 6/20/94 AWL Allow the CFL info pointer to be NULL for a "get procs" call to OpenContainer. <4> 5/9/94 AWL Change PLGetSpecialSectionInfo to handle some of the wierdness in nonloaded sections. <3> 4/28/94 AWL Simplify cross address space use for booting. Fix problem with load in place, should not require SetRegionAddress. <2> 2/25/94 AWL Update for Q&D solution to loading across address spaces. Fix problem in PLGetSpecialSectionInfo switch statement. <1> 2/15/94 AWL Initial checkin for kernel based CFM. ------------------------------------------------------------------------------------ <31> 09/15/93 AWL (&ELE) Add CFL prefix to hash functions. <30> 09/08/93 ELE (&AWL) Fix sneaky little typo that causes load failure. <29> 08/30/93 AWL Add declaration so that 68K native CFM compiles. <28> 08/26/93 AWL Move CFTypes.h and CFLoader.h up with other Apple private headers. <26> 07/08/93 AWL (&ELE) Fixed version field names in import file IDs. Remove version < 0 checks as versions are unsigned. <25> 06/16/93 ELE ELE & AWL Change to New Pool allocation. <24> 06/09/93 ELE ELE & AWL Fix bug in GetSpecialSection for debugger. <23> 06/09/93 JRG ELE & AWL Changes: <22> 06/08/93 ELE (&AWL) Shift to allocation bottleneck. Added support for packed data sections. Switched to new CFLoader section attribute bits. <21> 02/15/93 ELE Changed NewPtr->NewPtrSys <20> 02/03/93 ELE Added architecture pass thru to GetVersion per CFL Spec. <19> 12/23/92 ELE Fixed bug where init routine was being returned for the term routine. <17> 10/29/92 ELE GetVersion - added dateStamp. <16> 10/01/92 ELE fix bug in use in place, update of header! <15> 10/01/92 ELE fix bug in use in place! <14> 09/28/92 ELE needed to update field expIndex from Find/GetExportInfo. <13> 09/23/92 ELE updated to new PEF format, updated to new CF Loader SPI. <12> 09/23/92 ELE Latest version. */ #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) extern Boolean PCFM_CompareBytes ( const Byte * left, const Byte * right, ByteCount count ); #define PEF_CompareBytes(a,b,c) PCFM_CompareBytes(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 == 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 != -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, KernelProcessID runningProcessID, const CFContHashedName * cfragName, CFContOpenOptions options, CFContAllocateMem Allocate, CFContReleaseMem Release, CFContHandlerRef * containerRef, CFContHandlerProcsPtr * handlerProcs ) { #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; // ----------------------------------------------- // 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; 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 ( 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 ( (outPosLimit - outputPos) < count1 ) goto FragmentCorruptError; PEF_BlockClear ( outputPos, count1 ); outputPos += count1; break; case kPEFPkDataBlock : if ( (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 ( (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 ( (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 ( (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 ( 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 ); } } else { if ( section->initSize < sectionOffset ) { PEF_BlockClear ( bufferAddress, bufferLength ); } else { err = UnpackPartialSection ( packedBase, packedEnd, outputBase, outputEnd, sectionOffset ); if ( err != noErr ) goto ERROR; } 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 ); } } 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 ( i >= pefPrivate->sectionCount ) return noErr; // No relocations for this section. ldRelHdr = & pefPrivate->ldrSections [i]; if ( 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 ()