{ File: CarbonCore/PEFBinaryFormat.h Contains: PEF Types and Macros Version: CarbonCore-859.2~1 Copyright: © 1993-2008 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://www.freepascal.org/bugs.html } { Pascal Translation Updated: Jonas Maebe, , October 2009 } { Modified for use with Free Pascal Version 308 Please report any bugs to } {$ifc not defined MACOSALLINCLUDE or not MACOSALLINCLUDE} {$mode macpas} {$packenum 1} {$macro on} {$inline on} {$calling mwpascal} unit PEFBinaryFormat; interface {$setc UNIVERSAL_INTERFACES_VERSION := $0400} {$setc GAP_INTERFACES_VERSION := $0308} {$ifc not defined USE_CFSTR_CONSTANT_MACROS} {$setc USE_CFSTR_CONSTANT_MACROS := TRUE} {$endc} {$ifc defined CPUPOWERPC and defined CPUI386} {$error Conflicting initial definitions for CPUPOWERPC and CPUI386} {$endc} {$ifc defined FPC_BIG_ENDIAN and defined FPC_LITTLE_ENDIAN} {$error Conflicting initial definitions for FPC_BIG_ENDIAN and FPC_LITTLE_ENDIAN} {$endc} {$ifc not defined __ppc__ and defined CPUPOWERPC32} {$setc __ppc__ := 1} {$elsec} {$setc __ppc__ := 0} {$endc} {$ifc not defined __ppc64__ and defined CPUPOWERPC64} {$setc __ppc64__ := 1} {$elsec} {$setc __ppc64__ := 0} {$endc} {$ifc not defined __i386__ and defined CPUI386} {$setc __i386__ := 1} {$elsec} {$setc __i386__ := 0} {$endc} {$ifc not defined __x86_64__ and defined CPUX86_64} {$setc __x86_64__ := 1} {$elsec} {$setc __x86_64__ := 0} {$endc} {$ifc not defined __arm__ and defined CPUARM} {$setc __arm__ := 1} {$elsec} {$setc __arm__ := 0} {$endc} {$ifc defined cpu64} {$setc __LP64__ := 1} {$elsec} {$setc __LP64__ := 0} {$endc} {$ifc defined __ppc__ and __ppc__ and defined __i386__ and __i386__} {$error Conflicting definitions for __ppc__ and __i386__} {$endc} {$ifc defined __ppc__ and __ppc__} {$setc TARGET_CPU_PPC := TRUE} {$setc TARGET_CPU_PPC64 := FALSE} {$setc TARGET_CPU_X86 := FALSE} {$setc TARGET_CPU_X86_64 := FALSE} {$setc TARGET_CPU_ARM := FALSE} {$setc TARGET_OS_MAC := TRUE} {$setc TARGET_OS_IPHONE := FALSE} {$setc TARGET_IPHONE_SIMULATOR := FALSE} {$elifc defined __ppc64__ and __ppc64__} {$setc TARGET_CPU_PPC := FALSE} {$setc TARGET_CPU_PPC64 := TRUE} {$setc TARGET_CPU_X86 := FALSE} {$setc TARGET_CPU_X86_64 := FALSE} {$setc TARGET_CPU_ARM := FALSE} {$setc TARGET_OS_MAC := TRUE} {$setc TARGET_OS_IPHONE := FALSE} {$setc TARGET_IPHONE_SIMULATOR := FALSE} {$elifc defined __i386__ and __i386__} {$setc TARGET_CPU_PPC := FALSE} {$setc TARGET_CPU_PPC64 := FALSE} {$setc TARGET_CPU_X86 := TRUE} {$setc TARGET_CPU_X86_64 := FALSE} {$setc TARGET_CPU_ARM := FALSE} {$ifc defined(iphonesim)} {$setc TARGET_OS_MAC := FALSE} {$setc TARGET_OS_IPHONE := TRUE} {$setc TARGET_IPHONE_SIMULATOR := TRUE} {$elsec} {$setc TARGET_OS_MAC := TRUE} {$setc TARGET_OS_IPHONE := FALSE} {$setc TARGET_IPHONE_SIMULATOR := FALSE} {$endc} {$elifc defined __x86_64__ and __x86_64__} {$setc TARGET_CPU_PPC := FALSE} {$setc TARGET_CPU_PPC64 := FALSE} {$setc TARGET_CPU_X86 := FALSE} {$setc TARGET_CPU_X86_64 := TRUE} {$setc TARGET_CPU_ARM := FALSE} {$setc TARGET_OS_MAC := TRUE} {$setc TARGET_OS_IPHONE := FALSE} {$setc TARGET_IPHONE_SIMULATOR := FALSE} {$elifc defined __arm__ and __arm__} {$setc TARGET_CPU_PPC := FALSE} {$setc TARGET_CPU_PPC64 := FALSE} {$setc TARGET_CPU_X86 := FALSE} {$setc TARGET_CPU_X86_64 := FALSE} {$setc TARGET_CPU_ARM := TRUE} { will require compiler define when/if other Apple devices with ARM cpus ship } {$setc TARGET_OS_MAC := FALSE} {$setc TARGET_OS_IPHONE := TRUE} {$setc TARGET_IPHONE_SIMULATOR := FALSE} {$elsec} {$error __ppc__ nor __ppc64__ nor __i386__ nor __x86_64__ nor __arm__ is defined.} {$endc} {$ifc defined __LP64__ and __LP64__ } {$setc TARGET_CPU_64 := TRUE} {$elsec} {$setc TARGET_CPU_64 := FALSE} {$endc} {$ifc defined FPC_BIG_ENDIAN} {$setc TARGET_RT_BIG_ENDIAN := TRUE} {$setc TARGET_RT_LITTLE_ENDIAN := FALSE} {$elifc defined FPC_LITTLE_ENDIAN} {$setc TARGET_RT_BIG_ENDIAN := FALSE} {$setc TARGET_RT_LITTLE_ENDIAN := TRUE} {$elsec} {$error Neither FPC_BIG_ENDIAN nor FPC_LITTLE_ENDIAN are defined.} {$endc} {$setc ACCESSOR_CALLS_ARE_FUNCTIONS := TRUE} {$setc CALL_NOT_IN_CARBON := FALSE} {$setc OLDROUTINENAMES := FALSE} {$setc OPAQUE_TOOLBOX_STRUCTS := TRUE} {$setc OPAQUE_UPP_TYPES := TRUE} {$setc OTCARBONAPPLICATION := TRUE} {$setc OTKERNEL := FALSE} {$setc PM_USE_SESSION_APIS := TRUE} {$setc TARGET_API_MAC_CARBON := TRUE} {$setc TARGET_API_MAC_OS8 := FALSE} {$setc TARGET_API_MAC_OSX := TRUE} {$setc TARGET_CARBON := TRUE} {$setc TARGET_CPU_68K := FALSE} {$setc TARGET_CPU_MIPS := FALSE} {$setc TARGET_CPU_SPARC := FALSE} {$setc TARGET_OS_UNIX := FALSE} {$setc TARGET_OS_WIN32 := FALSE} {$setc TARGET_RT_MAC_68881 := FALSE} {$setc TARGET_RT_MAC_CFM := FALSE} {$setc TARGET_RT_MAC_MACHO := TRUE} {$setc TYPED_FUNCTION_POINTERS := TRUE} {$setc TYPE_BOOL := FALSE} {$setc TYPE_EXTENDED := FALSE} {$setc TYPE_LONGLONG := TRUE} uses MacTypes; {$endc} {not MACOSALLINCLUDE} {$ifc TARGET_OS_MAC} {$ALIGN MAC68K} { -------------------------------------------------------------------------------------------- } { Almost all types are padded for natural alignment. However the PEFExportedSymbol type is } { 10 bytes long, containing two 32 bit fields and one 16 bit field. Arrays of it must be } { packed, so it requires "68K" alignment. Setting this globally to 68K should also help } { ensure consistent treatment across compilers. } { ======================================================================================== } { Overall Structure } { ================= } { -------------------------------------------------------------------------------------------- } { This header contains a complete set of types and macros for dealing with the PEF executable } { format. While some description is provided, this header is not meant as a primary source } { of documentation on PEF. An excellent specification of PEF can be found in the Macintosh } { Runtime Architectures book. This header is primarily a physical format description. Thus } { it depends on as few other headers as possible and structure fields have obvious sizes. } { The physical storage for a PEF executable is known as a "container". This refers to just } { the executable itself, not the file etc. E.g. if five DLLs are packaged in a single file's } { data fork, that one data fork has five containers within it. } { A PEF container consists of an overall header, followed by one or more section headers, } { followed by the section name table, followed by the contents for the sections. Some kinds } { of sections have specific internal representation. The "loader" section is the most common } { of these special sections. It contains information on the exports, imports, and runtime } { relocations required to prepare the executable. PEF containers are self contained, all } { portions are located via relative offsets. } { +-------------------------------+ } { | Container Header | 40 bytes } { +-------------------------------+ } { | Section 0 header | 28 bytes each } { |...............................| } { | - - - - | } { |...............................| } { | Section n-1 header | } { +-------------------------------+ } { | Section Name Table | } { +-------------------------------+ } { | Section x raw data | } { +-------------------------------+ } { | - - - - | } { +-------------------------------+ } { | Section y raw data | } { +-------------------------------+ } { The sections are implicitly numbered from 0 to n according to the order of their headers. } { The headers of the instantiated sections must precede those of the non-instantiated } { sections. The ordering of the raw data is independent of the section header ordering. } { Each section header contains the offset for that section's raw data. } { =========================================================================================== } { Container Header } { ================ } type PEFContainerHeaderPtr = ^PEFContainerHeader; PEFContainerHeader = record tag1: OSType; { Must contain 'Joy!'.} tag2: OSType; { Must contain 'peff'. (Yes, with two 'f's.)} architecture: OSType; { The ISA for code sections. Constants in CodeFragments.h.} formatVersion: UInt32; { The physical format version.} dateTimeStamp: UInt32; { Macintosh format creation/modification stamp.} oldDefVersion: UInt32; { Old definition version number for the code fragment.} oldImpVersion: UInt32; { Old implementation version number for the code fragment.} currentVersion: UInt32; { Current version number for the code fragment.} sectionCount: UInt16; { Total number of section headers that follow.} instSectionCount: UInt16; { Number of instantiated sections.} reservedA: UInt32; { Reserved, must be written as zero.} end; const kPEFTag1 = FourCharCode('Joy!'); { For non-Apple compilers: 0x4A6F7921.} kPEFTag2 = FourCharCode('peff'); { For non-Apple compilers: 0x70656666.} kPEFVersion = $00000001; const kPEFFirstSectionHeaderOffset = SizeOf(PEFContainerHeader); (* #define PEFFirstSectionNameOffset(container) \ ( kPEFFirstSectionHeaderOffset + ((container)->sectionCount * sizeof ( PEFSectionHeader )) ) *) { =========================================================================================== } { Section Headers } { =============== } type PEFSectionHeaderPtr = ^PEFSectionHeader; PEFSectionHeader = record nameOffset: SInt32; { Offset of name within the section name table, -1 => none.} defaultAddress: UInt32; { Default address, affects relocations.} totalLength: UInt32; { Fully expanded size in bytes of the section contents.} unpackedLength: UInt32; { Size in bytes of the "initialized" part of the contents.} containerLength: UInt32; { Size in bytes of the raw data in the container.} containerOffset: UInt32; { Offset of section's raw data.} sectionKind: UInt8; { Kind of section contents/usage.} shareKind: UInt8; { Sharing level, if a writeable section.} alignment: UInt8; { Preferred alignment, expressed as log 2.} reservedA: UInt8; { Reserved, must be zero.} end; const { Values for the sectionKind field.} { Section kind values for instantiated sections.} kPEFCodeSection = 0; { Code, presumed pure & position independent.} kPEFUnpackedDataSection = 1; { Unpacked writeable data.} kPEFPackedDataSection = 2; { Packed writeable data.} kPEFConstantSection = 3; { Read-only data.} kPEFExecDataSection = 6; { Intermixed code and writeable data.} { Section kind values for non-instantiated sections.} kPEFLoaderSection = 4; { Loader tables.} kPEFDebugSection = 5; { Reserved for future use.} kPEFExceptionSection = 7; { Reserved for future use.} kPEFTracebackSection = 8; { Reserved for future use.} const { Values for the shareKind field.} kPEFProcessShare = 1; { Shared within a single process.} kPEFGlobalShare = 4; { Shared across the entire system.} kPEFProtectedShare = 5; { Readable across the entire system, writeable only to privileged code.} { =========================================================================================== } { Packed Data Contents } { ==================== } { -------------------------------------------------------------------------------------------- } { The raw contents of a packed data section are a sequence of byte codes. The basic format } { has a 3 bit opcode followed by a 5 bit count. Additional bytes might be used to contain } { counts larger than 31, and to contain a second or third count. Further additional bytes } { contain actual data values to transfer. } { All counts are represented in a variable length manner. A zero in the initial 5 bit count } { indicates the actual value follows. In this case, and for the second and third counts, the } { count is represented as a variable length sequence of bytes. The bytes are stored in big } { endian manner, most significant part first. The high order bit is set in all but the last } { byte. The value is accumulated by shifting the current value up 7 bits and adding in the } { low order 7 bits of the next byte. } const { The packed data opcodes.} kPEFPkDataZero = 0; { Zero fill "count" bytes.} kPEFPkDataBlock = 1; { Block copy "count" bytes.} kPEFPkDataRepeat = 2; { Repeat "count" bytes "count2"+1 times.} kPEFPkDataRepeatBlock = 3; { Interleaved repeated and unique data.} kPEFPkDataRepeatZero = 4; { Interleaved zero and unique data.} const kPEFPkDataOpcodeShift = 5; kPEFPkDataCount5Mask = $1F; kPEFPkDataMaxCount5 = 31; kPEFPkDataVCountShift = 7; kPEFPkDataVCountMask = $7F; kPEFPkDataVCountEndMask = $80; (* #define PEFPkDataOpcode(byte) ( ((UInt8)(byte)) >> kPEFPkDataOpcodeShift ) #define PEFPkDataCount5(byte) ( ((UInt8)(byte)) & kPEFPkDataCount5Mask ) #define PEFPkDataComposeInstr(opcode,count5) \ ( (((UInt8)(opcode)) << kPEFPkDataOpcodeShift) | ((UInt8)(count5)) ) *) { -------------------------------------------------------------------------------------------- } { The following code snippet can be used to input a variable length count. } { count = 0; } { do ( } { byte = *bytePtr++; } { count = (count << kPEFPkDataVCountShift) | (byte & kPEFPkDataVCountMask); } { ) while ( (byte & kPEFPkDataVCountEndMask) != 0 ); } { The following code snippet can be used to output a variable length count to a byte array. } { This is more complex than the input code because the chunks are output in big endian order. } { Think about handling values like 0 or 0x030000. } { count = 1;. } { tempValue = value >> kPEFPkDataCountShift; } { while ( tempValue != 0 ) ( } { count += 1; } { tempValue = tempValue >> kPEFPkDataCountShift; } { ) } { bytePtr += count; } { tempPtr = bytePtr - 1; } { *tempPtr-- = value; // ! No need to mask, only the low order byte is stored. } { for ( count -= 1; count != 0; count -= 1 ) ( } { value = value >> kPEFPkDataCountShift; } { *tempPtr-- = value | kPEFPkDataCountEndMask; } { ) } { =========================================================================================== } { Loader Section } { ============== } { -------------------------------------------------------------------------------------------- } { The loader section contains information needed to prepare the code fragment for execution. } { This includes this fragment's exports, the import libraries and the imported symbols from } { each library, and the relocations for the writeable sections. } { +-----------------------------------+ <-- containerOffset --------+ } { | Loader Info Header | 56 bytes | } { |-----------------------------------| | } { | Imported Library 0 | 24 bytes each | } { |...................................| | } { | - - - | | } { |...................................| | } { | Imported Library l-1 | | } { |-----------------------------------| | } { | Imported Symbol 0 | 4 bytes each | } { |...................................| | } { | - - - | | } { |...................................| | } { | Imported Symbol i-1 | | } { |-----------------------------------| | } { | Relocation Header 0 | 12 bytes each | } { |...................................| | } { | - - - | | } { |...................................| | } { | Relocation Header r-1 | | } { |-----------------------------------| <-- + relocInstrOffset -----| } { | Relocation Instructions | | } { |-----------------------------------| <-- + loaderStringsOffset --| } { | Loader String Table | | } { |-----------------------------------| <-- + exportHashOffset -----+ } { | Export Hash Slot 0 | 4 bytes each } { |...................................| } { | - - - | } { |...................................| } { | Export Hash Slot h-1 | } { |-----------------------------------| } { | Export Symbol Key 0 | 4 bytes each } { |...................................| } { | - - - | } { |...................................| } { | Export Symbol Key e-1 | } { |-----------------------------------| } { | Export Symbol 0 | 10 bytes each } { |...................................| } { | - - - | } { |...................................| } { | Export Symbol e-1 | } { +-----------------------------------+ } type PEFLoaderInfoHeaderPtr = ^PEFLoaderInfoHeader; PEFLoaderInfoHeader = record mainSection: SInt32; { Section containing the main symbol, -1 => none.} mainOffset: UInt32; { Offset of main symbol.} initSection: SInt32; { Section containing the init routine's TVector, -1 => none.} initOffset: UInt32; { Offset of the init routine's TVector.} termSection: SInt32; { Section containing the term routine's TVector, -1 => none.} termOffset: UInt32; { Offset of the term routine's TVector.} importedLibraryCount: UInt32; { Number of imported libraries. ('l')} totalImportedSymbolCount: UInt32; { Total number of imported symbols. ('i')} relocSectionCount: UInt32; { Number of sections with relocations. ('r')} relocInstrOffset: UInt32; { Offset of the relocation instructions.} loaderStringsOffset: UInt32; { Offset of the loader string table.} exportHashOffset: UInt32; { Offset of the export hash table.} exportHashTablePower: UInt32; { Export hash table size as log 2. (Log2('h'))} exportedSymbolCount: UInt32; { Number of exported symbols. ('e')} end; { =========================================================================================== } { Imported Libraries } { ------------------ } type PEFImportedLibraryPtr = ^PEFImportedLibrary; PEFImportedLibrary = record nameOffset: UInt32; { Loader string table offset of library's name.} oldImpVersion: UInt32; { Oldest compatible implementation version.} currentVersion: UInt32; { Current version at build time.} importedSymbolCount: UInt32; { Imported symbol count for this library.} firstImportedSymbol: UInt32; { Index of first imported symbol from this library.} options: UInt8; { Option bits for this library.} reservedA: UInt8; { Reserved, must be zero.} reservedB: UInt16; { Reserved, must be zero.} end; const { Bits for the PEFImportedLibrary options field.} kPEFWeakImportLibMask = $40; { The imported library is allowed to be missing.} kPEFInitLibBeforeMask = $80; { The imported library must be initialized first.} { =========================================================================================== } { Imported Symbols } { ---------------- } { -------------------------------------------------------------------------------------------- } { The PEFImportedSymbol type has the following bit field layout. } { 3 } { 0 7 8 1 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { | symbol class | offset of symbol name in loader string table | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 8 bits --->|<-- 24 bits ---------------------------------->| } type PEFImportedSymbolPtr = ^PEFImportedSymbol; PEFImportedSymbol = record classAndName: UInt32; end; const kPEFImpSymClassShift = 24; kPEFImpSymNameOffsetMask = $00FFFFFF; kPEFImpSymMaxNameOffset = $00FFFFFF; { 16,777,215} const { Imported and exported symbol classes.} kPEFCodeSymbol = $00; kPEFDataSymbol = $01; kPEFTVectorSymbol = $02; kPEFTOCSymbol = $03; kPEFGlueSymbol = $04; kPEFUndefinedSymbol = $0F; kPEFWeakImportSymMask = $80; { =========================================================================================== } { Exported Symbol Hash Table } { -------------------------- } { -------------------------------------------------------------------------------------------- } { Exported symbols are described in four parts, optimized for speed of lookup. These parts } { are the "export hash table", the "export key table", the "export symbol table", and the } { "export name table". Overall they contain a flattened representation of a fairly normal } { hashed symbol table. } { The export hash table is an array of small fixed size elements. The number of elements is } { a power of 2. A 32 bit hash word for a symbol is converted into an index into this array. } { Each hash slot contains a count of the number of exported symbols that map to this slot and } { the index of the first of those symbols in the key and symbol tables. Of course some hash } { slots will have a zero count. } { The key and symbol tables are also arrays of fixed size elements, one for each exported } { symbol. Their entries are grouped by hash slot, those elements mapping to the same hash } { slot are contiguous. The key table contains just the full 32 bit hash word for each } { exported symbol. The symbol table contains the offset of the symbol's name in the string } { table and other information about the exported symbol. } { To look up an export you take the hashword and compute the hash slot index. You then scan } { the indicated portion of the key table for matching hashwords. If a hashword matches, you } { look at the corresponding symbol table entry to find the full symbol name. If the names } { match the symbol is found. } { -------------------------------------------------------------------------------------------- } { The following function may be used to compute the hash table size. Signed values are used } { just to avoid potential code generation overhead for unsigned division. } { UInt8 PEFComputeHashTableExponent ( SInt32 exportCount ) } { ( } { SInt32 exponent; } { const SInt32 kExponentLimit = 16; // Arbitrary, but must not exceed 30. } { const SInt32 kAverageChainLimit = 10; // Arbitrary, for space/time tradeoff. } { for ( exponent = 0; exponent < kExponentLimit; exponent += 1 ) ( } { if ( (exportCount / (1 << exponent)) < kAverageChainLimit ) break; } { ) } { return exponent; } { ) // PEFComputeHashTableExponent () } { -------------------------------------------------------------------------------------------- } { The PEFExportedSymbolHashSlot type has the following bit field layout. } { 1 1 3 } { 0 3 4 1 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { | symbol count | index of first export key | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 14 bits -------------->|<-- 18 bits ---------------------->| } type PEFExportedSymbolHashSlotPtr = ^PEFExportedSymbolHashSlot; PEFExportedSymbolHashSlot = record countAndStart: UInt32; end; const kPEFHashSlotSymCountShift = 18; kPEFHashSlotFirstKeyMask = $0003FFFF; kPEFHashSlotMaxSymbolCount = $00003FFF; { 16,383} kPEFHashSlotMaxKeyIndex = $0003FFFF; { 262,143} { =========================================================================================== } { Exported Symbol Hash Key } { ------------------------ } type PEFSplitHashWordPtr = ^PEFSplitHashWord; PEFSplitHashWord = record nameLength: UInt16; hashValue: UInt16; end; type PEFExportedSymbolKeyPtr = ^PEFExportedSymbolKey; PEFExportedSymbolKey = record case SInt16 of 0: ( fullHashWord: UInt32; ); 1: ( splitHashWord: PEFSplitHashWord; ); end; const kPEFHashLengthShift = 16; kPEFHashValueMask = $0000FFFF; kPEFHashMaxLength = $0000FFFF; { 65,535} { ---------------------------------------------------------------------------------------------------- } { The following function computes the full 32 bit hash word. } { UInt32 PEFComputeHashWord ( BytePtr nameText, // ! First "letter", not length byte. } { UInt32 nameLength ) // ! The text may be zero terminated. } { ( } { BytePtr charPtr = nameText; } { SInt32 hashValue = 0; // ! Signed to match old published algorithm. } { UInt32 length = 0; } { UInt32 limit; } { UInt32 result; } { UInt8 currChar; } { #define PseudoRotate(x) ( ( (x) << 1 ) - ( (x) >> 16 ) ) } { for ( limit = nameLength; limit > 0; limit -= 1 ) ( } { currChar = *charPtr++; } { if ( currChar == NULL ) break; } { length += 1; } { hashValue = PseudoRotate ( hashValue ) ^ currChar; } { ) } { result = (length << kPEFHashLengthShift) | } { ((UInt16) ((hashValue ^ (hashValue >> 16)) & kPEFHashValueMask)); } { return result; } { ) // PEFComputeHashWord () } { =========================================================================================== } { Exported Symbols } { ---------------- } type PEFExportedSymbolPtr = ^PEFExportedSymbol; PEFExportedSymbol = record { ! This structure is 10 bytes long and arrays are packed.} classAndName: UInt32; { A combination of class and name offset.} symbolValue: UInt32; { Typically the symbol's offset within a section.} sectionIndex: SInt16; { The index of the section, or pseudo-section, for the symbol.} end; { -------------------------------------------------------------------------------------------- } { The classAndName field of the PEFExportedSymbol type has the following bit field layout. } { 3 } { 0 7 8 1 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { | symbol class | offset of symbol name in loader string table | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 8 bits --->|<-- 24 bits ---------------------------------->| } const kPEFExpSymClassShift = 24; kPEFExpSymNameOffsetMask = $00FFFFFF; kPEFExpSymMaxNameOffset = $00FFFFFF; { 16,777,215} (* #define PEFExportedSymbolClass(classAndName) ((UInt8) ((classAndName) >> kPEFExpSymClassShift)) #define PEFExportedSymbolNameOffset(classAndName) ((classAndName) & kPEFExpSymNameOffsetMask) #define PEFComposeExportedSymbol(class,nameOffset) \ ( ( ((UInt32)(class)) << kPEFExpSymClassShift ) | ( (UInt32)(nameOffset) ) ) *) const { Negative section indices indicate pseudo-sections.} kPEFAbsoluteExport = -2; { The symbol value is an absolute address.} kPEFReexportedImport = -3; { The symbol value is the index of a reexported import.} { =========================================================================================== } { Loader Relocations } { ================== } { -------------------------------------------------------------------------------------------- } { The relocations for a section are defined by a sequence of instructions for an abstract } { machine that is specifically geared to performing relocations commonly needed for the "CFM" } { code generation model. These instructions occur in 16 bit chunks. Most instructions have } { just a single chunk. Instructions that are larger than 16 bits have an opcode and some of } { the operands in the first chunk, with other operands in following chunks. } { ! Note that the multi-chunk relocations have separate "Compose" macros for each chunk. The } { ! macros have the same basic name with a positional suffix of "_1st", "_2nd", etc. } type PEFRelocChunk = UInt16; PEFLoaderRelocationHeaderPtr = ^PEFLoaderRelocationHeader; PEFLoaderRelocationHeader = record sectionIndex: UInt16; { Index of the section to be fixed up.} reservedA: UInt16; { Reserved, must be zero.} relocCount: UInt32; { Number of 16 bit relocation chunks.} firstRelocOffset: UInt32; { Offset of first relocation instruction.} end; { -------------------------------------------------------------------------------------------- } { ! Note that the relocCount field is the number of 16 bit relocation chunks, i.e. 1/2 the } { ! total number of bytes of relocation instructions. While most relocation instructions are } { ! 16 bits long, some are longer so the number of complete relocation instructions may be } { ! less than the relocCount value. } { ------------------------------------------------------------------------------------ } { The PEFRelocField macro is a utility for extracting relocation instruction fields. } (* #define PEFRFShift(offset,length) (16 - ((offset) + (length))) #define PEFRFMask(length) ((1 << (length)) - 1) #define PEFRelocField(chunk,offset,length) \ ( ( (chunk) >> (16 - ((offset) + (length))) ) & ((1 << (length)) - 1) ) *) { =========================================================================================== } { Basic Relocation Opcodes } { ------------------------ } { -------------------------------------------------------------------------------------------- } { The number of opcode bits varies from 2 to 7. The enumeration and switch table given here } { are defined in terms of the most significant 7 bits of the first instruction chunk. An } { instruction is decoded by using the most significant 7 bits as an index into the opcode } { table, which in turn contains appropriately masked forms of the most significant 7 bits. } { The macro PEFRelocBasicOpcode assumes a declaration of the form. } { UInt8 kPEFRelocBasicOpcodes [kPEFRelocBasicOpcodeRange] = ( PEFMaskedBasicOpcodes ); } const kPEFRelocBasicOpcodeRange = 128; (* #define PEFRelocBasicOpcode(firstChunk) (kPEFRelocBasicOpcodes[(firstChunk)>>9]) *) { -------------------------------------------------------------------------------------------- } { The relocation opcodes, clustered by major and minor groups. The instructions within a } { cluster all have the same bit field layout. The enumeration values use the high order 7 } { bits of the relocation instruction. Unused low order bits are set to zero. } const kPEFRelocBySectDWithSkip = $00; { Binary: 00x_xxxx} kPEFRelocBySectC = $20; { Binary: 010_0000, group is "RelocRun"} kPEFRelocBySectD = $21; { Binary: 010_0001} kPEFRelocTVector12 = $22; { Binary: 010_0010} kPEFRelocTVector8 = $23; { Binary: 010_0011} kPEFRelocVTable8 = $24; { Binary: 010_0100} kPEFRelocImportRun = $25; { Binary: 010_0101} kPEFRelocSmByImport = $30; { Binary: 011_0000, group is "RelocSmIndex"} kPEFRelocSmSetSectC = $31; { Binary: 011_0001} kPEFRelocSmSetSectD = $32; { Binary: 011_0010} kPEFRelocSmBySection = $33; { Binary: 011_0011} kPEFRelocIncrPosition = $40; { Binary: 100_0xxx} kPEFRelocSmRepeat = $48; { Binary: 100_1xxx} kPEFRelocSetPosition = $50; { Binary: 101_000x} kPEFRelocLgByImport = $52; { Binary: 101_001x} kPEFRelocLgRepeat = $58; { Binary: 101_100x} kPEFRelocLgSetOrBySection = $5A; { Binary: 101_101x} kPEFRelocUndefinedOpcode = $FF; { Used in masking table for all undefined values.} { ---------------------------------------------------------------------------- } { The RelocLgSetOrBySection instruction has an additional 4 bits of subopcode } { beyond the 7 used by the dispatch table. To be precise it has 6 plus 4 but } { the dispatch table ignores the 7th bit, so the subdispatch is on all 4 extra } { subopcode bits. } const kPEFRelocLgBySectionSubopcode = $00; { Binary: 0000} kPEFRelocLgSetSectCSubopcode = $01; { Binary: 0001} kPEFRelocLgSetSectDSubopcode = $02; { Binary: 0010} (* #define PEFRelocLgSetOrBySubopcode(chunk) (((chunk) >> 6) & 0x0F) *) { -------------------------------------------------------------------------------------------- } { The initial values for the opcode "masking" table. This has the enumeration values from } { above with appropriate replications for "don't care" bits. It is almost certainly shorter } { and faster to look up the masked value in a table than to use a branch tree. } (* #define PEFMaskedBasicOpcodes \ \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x00 .. 0x03 } \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x04 .. 0x07 } \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x08 .. 0x0B } \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x0C .. 0x0F } \ \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x10 .. 0x13 } \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x14 .. 0x17 } \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x18 .. 0x1B } \ kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, kPEFRelocBySectDWithSkip, { 0x1C .. 0x1F } \ \ kPEFRelocBySectC, kPEFRelocBySectD, kPEFRelocTVector12, kPEFRelocTVector8, { 0x20 .. 0x23 } \ kPEFRelocVTable8, kPEFRelocImportRun, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x24 .. 0x27 } \ \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x28 .. 0x2B } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x2C .. 0x2F } \ \ kPEFRelocSmByImport, kPEFRelocSmSetSectC, kPEFRelocSmSetSectD, kPEFRelocSmBySection, { 0x30 .. 0x33 } \ \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x34 .. 0x37 } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x38 .. 0x3B } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x3C .. 0x3F } \ \ kPEFRelocIncrPosition, kPEFRelocIncrPosition, kPEFRelocIncrPosition, kPEFRelocIncrPosition, { 0x40 .. 0x43 } \ kPEFRelocIncrPosition, kPEFRelocIncrPosition, kPEFRelocIncrPosition, kPEFRelocIncrPosition, { 0x44 .. 0x47 } \ \ kPEFRelocSmRepeat, kPEFRelocSmRepeat, kPEFRelocSmRepeat, kPEFRelocSmRepeat, { 0x48 .. 0x4B } \ kPEFRelocSmRepeat, kPEFRelocSmRepeat, kPEFRelocSmRepeat, kPEFRelocSmRepeat, { 0x4C .. 0x4F } \ \ kPEFRelocSetPosition, kPEFRelocSetPosition, kPEFRelocLgByImport, kPEFRelocLgByImport, { 0x50 .. 0x53 } \ \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x54 .. 0x57 } \ \ kPEFRelocLgRepeat, kPEFRelocLgRepeat, kPEFRelocLgSetOrBySection, kPEFRelocLgSetOrBySection, { 0x58 .. 0x5B } \ \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x5C .. 0x5F } \ \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x60 .. 0x63 } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x64 .. 0x67 } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x68 .. 0x6B } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x6C .. 0x6F } \ \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x70 .. 0x73 } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x74 .. 0x77 } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, { 0x78 .. 0x7B } \ kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode, kPEFRelocUndefinedOpcode { 0x7C .. 0x7F } *) { =========================================================================================== } { RelocBySectDWithSkip Instruction (DDAT) } { --------------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocBySectDWithSkip" (DDAT) instruction has the following bit field layout. } { 1 1 } { 0 1 2 9 0 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |0 0| skip count | rel count | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { | 2 |<-- 8 bits --->|<-- 6 --->| } { ! Note that the stored skip count and reloc count are the actual values! } const kPEFRelocWithSkipMaxSkipCount = 255; kPEFRelocWithSkipMaxRelocCount = 63; (* #define PEFRelocWithSkipSkipCount(chunk) PEFRelocField ( (chunk), 2, 8 ) #define PEFRelocWithSkipRelocCount(chunk) PEFRelocField ( (chunk), 10, 6 ) #define PEFRelocComposeWithSkip(skipCount,relocCount) \ ( 0x0000 | (((UInt16)(skipCount)) << 6) | ((UInt16)(relocCount)) ) *) { =========================================================================================== } { RelocRun Group (CODE, DATA, DESC, DSC2, VTBL, SYMR) } { --------------------------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocRun" group includes the "RelocBySectC" (CODE), "RelocBySectD" (DATA), } { "RelocTVector12" (DESC), "RelocTVector8" (DSC2), "RelocVTable8" (VTBL), and } { "RelocImportRun" (SYMR) instructions. This group has the following bit field layout. } { 1 } { 0 2 3 6 7 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |0 1 0| subop.| run length | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { | 3 |<- 4 ->|<-- 9 bits ----->| } { ! Note that the stored run length is the actual value minus 1, but the macros deal with the } { ! actual value! } const kPEFRelocRunMaxRunLength = 512; (* #define PEFRelocRunSubopcode(chunk) PEFRelocField ( (chunk), 3, 4 ) #define PEFRelocRunRunLength(chunk) (PEFRelocField ( (chunk), 7, 9 ) + 1) #define PEFRelocComposeRun(subopcode,runLength) \ ( 0x4000 | (((UInt16)(subopcode)) << 9) | ((UInt16)((runLength)-1)) ) #define PEFRelocComposeBySectC(runLength) PEFRelocComposeRun ( 0, (runLength) ) #define PEFRelocComposeBySectD(runLength) PEFRelocComposeRun ( 1, (runLength) ) #define PEFRelocComposeTVector12(runLength) PEFRelocComposeRun ( 2, (runLength) ) #define PEFRelocComposeTVector8(runLength) PEFRelocComposeRun ( 3, (runLength) ) #define PEFRelocComposeVTable8(runLength) PEFRelocComposeRun ( 4, (runLength) ) #define PEFRelocComposeImportRun(runLength) PEFRelocComposeRun ( 5, (runLength) ) *) { =========================================================================================== } { RelocSmIndex Group (SYMB, CDIS, DTIS, SECN) } { ------------------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocSmIndex" group includes the "RelocSmByImport" (SYMB), "RelocSmSetSectC" (CDIS), } { "RelocSmSetSectD" (DTIS) and "RelocSmBySection" (SECN) instructions. This group has the } { following bit field layout. } { 1 } { 0 2 3 6 7 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |0 1 1| subop.| index | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { | 3 |<- 4 ->|<-- 9 bits ----->| } { ! Note that the stored index is the actual value! } const kPEFRelocSmIndexMaxIndex = 511; (* #define PEFRelocSmIndexSubopcode(chunk) PEFRelocField ( (chunk), 3, 4 ) #define PEFRelocSmIndexIndex(chunk) PEFRelocField ( (chunk), 7, 9 ) #define PEFRelocComposeSmIndex(subopcode,index) \ ( 0x6000 | (((UInt16)(subopcode)) << 9) | ((UInt16)(index)) ) #define PEFRelocComposeSmByImport(index) PEFRelocComposeSmIndex ( 0, (index) ) #define PEFRelocComposeSmSetSectC(index) PEFRelocComposeSmIndex ( 1, (index) ) #define PEFRelocComposeSmSetSectD(index) PEFRelocComposeSmIndex ( 2, (index) ) #define PEFRelocComposeSmBySection(index) PEFRelocComposeSmIndex ( 3, (index) ) *) { =========================================================================================== } { RelocIncrPosition Instruction (DELT) } { ------------------------------------ } { -------------------------------------------------------------------------------------------- } { The "RelocIncrPosition" (DELT) instruction has the following bit field layout. } { 1 } { 0 3 4 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |1 0 0 0| offset | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<- 4 ->|<-- 12 bits ---------->| } { ! Note that the stored offset is the actual value minus 1, but the macros deal with the } { ! actual value! } const kPEFRelocIncrPositionMaxOffset = 4096; (* #define PEFRelocIncrPositionOffset(chunk) (PEFRelocField ( (chunk), 4, 12 ) + 1) #define PEFRelocComposeIncrPosition(offset) \ ( 0x8000 | ((UInt16)((offset)-1)) ) *) { =========================================================================================== } { RelocSmRepeat Instruction (RPT) } { ------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocSmRepeat" (RPT) instruction has the following bit field layout. } { 1 } { 0 3 4 7 8 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |1 0 0 1| chnks | repeat count | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<- 4 ->|<- 4 ->|<-- 8 bits --->| } { ! Note that the stored chunk count and repeat count are the actual values minus 1, but the } { ! macros deal with the actual values! } const kPEFRelocSmRepeatMaxChunkCount = 16; kPEFRelocSmRepeatMaxRepeatCount = 256; (* #define PEFRelocSmRepeatChunkCount(chunk) (PEFRelocField ( (chunk), 4, 4 ) + 1) #define PEFRelocSmRepeatRepeatCount(chunk) (PEFRelocField ( (chunk), 8, 8 ) + 1) #define PEFRelocComposeSmRepeat(chunkCount,repeatCount) \ ( 0x9000 | ((((UInt16)(chunkCount))-1) << 8) | (((UInt16)(repeatCount))-1) ) *) { =========================================================================================== } { RelocSetPosition Instruction (LABS) } { ----------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocSetPosition" (LABS) instruction has the following bit field layout. } { 1 1 } { 0 5 6 5 0 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |1 0 1 0 0 0| offset (high) | | offset (low) | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 6 ---->|<-- 10 bits ------>| |<-- 16 bits ------------------>| } { ! Note that the stored offset is the actual value! } const kPEFRelocSetPosMaxOffset = $03FFFFFF; { 67,108,863} (* #define PEFRelocSetPosOffsetHigh(chunk) PEFRelocField ( (chunk), 6, 10 ) #define PEFRelocSetPosFullOffset(firstChunk,secondChunk) \ ( ((((UInt32)(firstChunk)) & 0x03FF) << 16) | ((UInt32)(secondChunk)) ) #define PEFRelocComposeSetPosition_1st(fullOffset) \ ( 0xA000 | ((UInt16) (((UInt32)(fullOffset)) >> 16) ) ) #define PEFRelocComposeSetPosition_2nd(fullOffset) \ ( (UInt16) ((UInt32)(fullOffset) & 0xFFFF) ) *) { =========================================================================================== } { RelocLgByImport Instruction (LSYM) } { ---------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocLgByImport" (LSYM) instruction has the following bit field layout. } { 1 1 } { 0 5 6 5 0 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |1 0 1 0 0 1| index (high) | | index (low) | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 6 ---->|<-- 10 bits ------>| |<-- 16 bits ------------------>| } { ! Note that the stored offset is the actual value! } const kPEFRelocLgByImportMaxIndex = $03FFFFFF; { 67,108,863} (* #define PEFRelocLgByImportIndexHigh(chunk) PEFRelocField ( (chunk), 6, 10 ) #define PEFRelocLgByImportFullIndex(firstChunk,secondChunk) \ ( ((((UInt32)(firstChunk)) & 0x03FF) << 16) | ((UInt32)(secondChunk)) ) #define PEFRelocComposeLgByImport_1st(fullIndex) \ ( 0xA400 | ((UInt16) (((UInt32)(fullIndex)) >> 16) ) ) #define PEFRelocComposeLgByImport_2nd(fullIndex) \ ( (UInt16) ((UInt32)(fullIndex) & 0xFFFF) ) *) { =========================================================================================== } { RelocLgRepeat Instruction (LRPT) } { -------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocLgRepeat" (LRPT) instruction has the following bit field layout. } { 1 1 1 } { 0 5 6 9 0 5 0 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |1 0 1 1 0 0| chnks | rpt (high)| | repeat count (low) | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 6 --->|<- 4 ->|<-- 6 --->| |<-- 16 bits ------------------>| } { ! Note that the stored chunk count is the actual value minus 1, but the macros deal with } { ! the actual value! The stored repeat count is the actual value! } const kPEFRelocLgRepeatMaxChunkCount = 16; kPEFRelocLgRepeatMaxRepeatCount = $003FFFFF; { 4,194,303} (* #define PEFRelocLgRepeatChunkCount(chunk) (PEFRelocField ( (chunk), 6, 4 ) + 1) #define PEFRelocLgRepeatRepeatCountHigh(chunk) PEFRelocField ( (chunk), 10, 6 ) #define PEFRelocLgRepeatFullRepeatCount(firstChunk,secondChunk) \ ( ((((UInt32)(firstChunk)) & 0x003F) << 16) | ((UInt32)(secondChunk)) ) #define PEFRelocComposeLgRepeat_1st(chunkCount,fullRepeatCount) \ ( 0xB000 | ((((UInt16)(chunkCount))-1) << 6) | ((UInt16) (((UInt32)(fullRepeatCount)) >>16 ) ) ) #define PEFRelocComposeLgRepeat_2nd(chunkCount,fullRepeatCount) \ ( (UInt16) ((UInt32)(fullRepeatCount) & 0xFFFF) ) *) { =========================================================================================== } { RelocLgSetOrBySection Group (LSEC) } { ---------------------------------- } { -------------------------------------------------------------------------------------------- } { The "RelocLgSetOrBySection" (LSEC) instruction is a group including the "RelocLgBySection", } { "RelocLgSetSectC" and "RelocLgSetSectD" instructions. This group has the following bit } { field layout. } { 1 1 1 } { 0 5 6 9 0 5 0 5 } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |1 0 1 1 0 1| subop | idx (high)| | index (low) | } { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ } { |<-- 6 --->|<- 4 ->|<-- 6 --->| |<-- 16 bits ------------------>| } { ! Note that the stored index is the actual value! } const kPEFRelocLgSetOrBySectionMaxIndex = $003FFFFF; { 4,194,303} (* #define PEFRelocLgSetOrBySectionSubopcode(chunk) PEFRelocField ( (chunk), 6, 4 ) #define PEFRelocLgSetOrBySectionIndexHigh(chunk) PEFRelocField ( (chunk), 10, 6 ) #define PEFRelocLgSetOrBySectionFullIndex(firstChunk,secondChunk) \ ( ((((UInt32)(firstChunk)) & 0x003F) << 16) | ((UInt32)(secondChunk)) ) #define PEFRelocComposeLgSetOrBySection_1st(subopcode,fullIndex) \ ( 0xB400 | (((UInt16)(subopcode)) << 6) | ((UInt16) (((UInt32)(fullIndex)) >> 16) ) ) #define PEFRelocComposeLgSetOrBySection_2nd(subopcode,fullIndex) \ ( (UInt16) ((UInt32)(fullIndex) & 0xFFFF) ) #define PEFRelocComposeLgBySection(fullIndex) PEFRelocComposeLgSetOrBySection ( 0x00, (fullIndex) ) #define PEFRelocComposeLgSetSectC(fullIndex) PEFRelocComposeLgSetOrBySection ( 0x01, (fullIndex) ) #define PEFRelocComposeLgSetSectD(fullIndex) PEFRelocComposeLgSetOrBySection ( 0x02, (fullIndex) ) *) { ======================================================================================== } { ======================================================================================== } { ======================================================================================== } { Vector Library Declarations } { =========================== } { -------------------------------------------------------------------------------------------- } { Mac OS X has special "vector" and "bridge" libraries to allow CFM managed clients to import } { from the dyld managed implementation libraries. The vector libraries are typically embedded } { within their respective implementation libraries. Even if standalone, the vector libraries } { are themselves normal dyld managed libraries. The vector libraries contain an export symbol } { table and pointers to the actual implementations. For functions, these pointers serve as } { the PMacCG TVectors. Because the dyld libraries are not part of the CFM search, we need a } { separate library for CFM to find that then indicates where the vector library is. These are } { the bridge libraries. They are tiny, just the container header and container strings parts. } { Since the vector library is embedded in a Mach-O dylib, we use dyld services to obtain the } { base address for the main portion and the exported symbol portion. The binding pointers are } { found through offsets in the exported symbol records. } { +-----------------------------------+ <-- containerOrigin ------------+ } { | Container Header | 76 bytes | } { |-----------------------------------| <-- + containerStringsOffset ---| } { | Container Strings | | } { |-----------------------------------| <-- + exportHashOffset ---------+ } { | Export Hash Slot 0 | 4 bytes each | } { |...................................| | } { | - - - | | } { |...................................| | } { | Export Hash Slot h-1 | | } { |-----------------------------------| <-- + exportKeyOffset ----------+ } { | Export Symbol Key 0 | 4 bytes each | } { |...................................| Order must match the exported symbols | } { | - - - | | } { |...................................| | } { | Export Symbol Key e-1 | | } { |-----------------------------------| <-- + exportNamesOffset --------+ } { | Export Names | | } { |-----------------------------------| | } { (Disjoint parts) | } { |-----------------------------------| <-- + exportSymbolOffset -------+ } { | Export Symbol 0 | 8 bytes each } { |...................................| Order must match the export keys } { | - - - | } { |...................................| } { | Export Symbol e-1 | } { +-----------------------------------+ } { (Disjoint parts) } { |-----------------------------------| } { | Binding Pointer 0 | 4 bytes each } { |-----------------------------------| Possibly disjoint, order does not matter } { | - - - | } { |-----------------------------------| } { | Binding Pointer e-1 | } { +-----------------------------------+ } type XLibContainerHeaderPtr = ^XLibContainerHeader; XLibContainerHeader = record { Structural description fields:} tag1: OSType; { Must contain 'ğMac'.} tag2: OSType; { Must contain 'vLib' or 'bLib'.} currentFormat: UInt32; { The version of XLib types used to create this container.} containerStringsOffset: UInt32; { Container offset of the container string table.} exportHashOffset: UInt32; { Offset of the export hash table.} exportKeyOffset: UInt32; { Offset of the export key table.} exportSymbolOffset: UInt32; { Offset of the export symbol table.} exportNamesOffset: UInt32; { Offset of the export names.} exportHashTablePower: UInt32; { Export hash table size as log 2. (Log2('h'))} exportedSymbolCount: UInt32; { Number of exported symbols. ('e')} { Fragment description fields:} fragNameOffset: UInt32; { The offset of the fragment name in the container string table.} fragNameLength: UInt32; { The length of the fragment name in the container string table.} dylibPathOffset: UInt32; { The offset of the dyld "install name" in the container string table.} dylibPathLength: UInt32; { The length of the dyld "install name" in the container string table.} cpuFamily: OSType; { The ISA for code sections. Constants in CodeFragments.h.} cpuModel: OSType; { Specific CPU model if applicable.} dateTimeStamp: UInt32; { Mac format creation stamp.} currentVersion: UInt32; { Current version number for the code fragment.} oldDefVersion: UInt32; { Old definition version number for the code fragment.} oldImpVersion: UInt32; { Old implementation version number for the code fragment.} end; const kXLibTag1 = FourCharCode('ğMac'); { For non-Apple compilers: 0xF04D6163.} kVLibTag2 = FourCharCode('VLib'); { For non-Apple compilers: 0x564C6962.} kBLibTag2 = FourCharCode('BLib'); { For non-Apple compilers: 0x424C6962.} kXLibVersion = $00000001; type XLibExportedSymbolHashSlot = PEFExportedSymbolHashSlot; XLibExportedSymbolKey = PEFExportedSymbolKey; XLibExportedSymbolPtr = ^XLibExportedSymbol; XLibExportedSymbol = record classAndName: UInt32; { A combination of class and name offset.} bpOffset: UInt32; { Container offset of the export's dyld binding pointer.} end; { =========================================================================================== } {$ifc not undefined IncludePEF2Declarations and IncludePEF2Declarations} { ======================================================================================== } { ======================================================================================== } { ======================================================================================== } { PEF2 Declarations } { ================= } { -------------------------------------------------------------------------------------------- } { PEF2 is a follow-on to the original PEF, incorporating changes that would break backward } { compatibility. The primary motivations for PEF2 are to incorporate new features cleanly, to } { relax some physical limitations, and to provide a more explicit path for future growth. } { PEF2 is very similar to PEF, it is possible for any PEF container to be mechanically } { converted to PEF2. The converse is not necessarily true, containers that use new features } { of PEF2 might not be convertable to PEF. } { One difference from PEF is that PEF2 has no implicit ordering, e.g. the section headers do } { not necessarily immediately follow the container header. Explicit offsets and lengths are } { provided for all portions of the container so that tools can continue to parse PEF2 as new } { versions of it are produced in the future. The following overall layout is suggested for } { locality of reference in typical usage with a packed data image: } { +-----------------------------------+ } { | Container Header | } { +-----------------------------------+ } { | Section 0 header | } { |...................................| } { | - - - - | } { |...................................| } { | Section n-1 header | } { +-----------------------------------+ } { | Container String Table | } { +-----------------------------------+ } { | Loader section contents | } { +-----------------------------------+ } { | Packed data contents | } { +-----------------------------------+ } { | Code section contents | } { +-----------------------------------+ } { If unpacked data is used for prebinding with copy-on-write mapping, the unpacked data should } { follow the code section. } { Note that the rule regarding instantiated sections preceeding noninstantiated sections only } { applies to the section headers, not the section contents. Thus it is perfectly fine for the } { loader section contents to be first. } { The container string table holds the name of the fragment and the names of the sections. } { The first 4 bytes of the container string table must be zero and always present. An offset } { of zero into the container string table is considered a null name. Actual names are stored } { as a PEF-style 32 bit hashword followed by the text of the name. The encoding of the text } { is given by the stringEncoding field of the container header. The hashword is computed from } { the encoded name as a string of bytes. The length in the hashword is the number of bytes in } { the encoded name, not the number of logical characters. } { =========================================================================================== } { Container Header } { ================ } type PEF2ContainerHeaderPtr = ^PEF2ContainerHeader; PEF2ContainerHeader = record { Structural fields:} tag1: OSType; { Must contain 'Joy!'.} tag2: OSType; { Must contain 'PEF '.} currentFormat: UInt32; { The version of PEF2 used to create this container.} oldestFormat: UInt32; { Oldest compatible container handler.} containerHeaderSize: UInt32; { The size of this header in bytes.} containerLength: UInt32; { The total length of the container in bytes.} checksum: UInt32; { A checksum for the entire container.} sectionHeadersOffset: UInt32; { Container offset of the first section header.} sectionHeaderSize: UInt32; { The size in bytes of each section header.} totalSectionCount: UInt32; { Total number of section headers.} instSectionCount: UInt32; { Number of instantiated sections.} loaderSectionIndex: UInt32; { Index of the section containing runtime loader tables.} containerStringsOffset: UInt32; { Container offset of the container string table.} containerStringsLength: UInt32; { Length in bytes of the container string table.} options: UInt32; { Array of 32 option bits.} preferredAddress: UInt32; { Preferred container address, 0xFFFFFFFF indicates no preference.} alignment: UInt8; { Required container alignment as LOG 2.} stringEncoding: UInt8; { The encoding for all strings in the container.} reservedA: UInt16; { Reserved, must be written as zero.} reservedB: UInt32; { Reserved, must be written as zero.} reservedC: UInt32; { Reserved, must be written as zero.} { Fragment description fields:} nameOffset: UInt32; { The offset of the name in the container string table.} architecture: OSType; { The ISA for code sections. Constants in CodeFragments.h.} dateTimeStamp: UInt32; { Macintosh format creation/modification stamp.} currentVersion: UInt32; { Current version number for the code fragment.} oldDefVersion: UInt32; { Old definition version number for the code fragment.} oldImpVersion: UInt32; { Old implementation version number for the code fragment.} reservedD: UInt32; { Reserved, must be written as zero.} reservedE: UInt32; { Reserved, must be written as zero.} end; const kPEF2Tag1 = kPEFTag1; kPEF2Tag2 = FourCharCode('PEF '); { For non-Apple compilers: 0x50656620.} kPEF2CurrentFormat = $00000002; { ! There is no version 0 or 1.} kPEF2OldestHandler = $00000002; const { Values for the options field.} kPEF2IsReexportLibraryMask = $00000001; { This fragment does nothing but reexport imports.} kPEF2IsGlueLibraryMask = $00000002; { A special form of import library that provides a glue layer.} const { Values for the stringEncoding field.} kPEF2StringsAreASCII = 0; kPEF2StringsAreUnicode = 1; { =========================================================================================== } { Section Headers } { =============== } type PEF2SectionHeaderPtr = ^PEF2SectionHeader; PEF2SectionHeader = record nameOffset: UInt32; { Offset of the name within the container string table.} presumedAddress: UInt32; { Presumed address, affects relocations.} totalLength: UInt32; { Fully expanded size in bytes of the section contents.} unpackedLength: UInt32; { Size in bytes of the "initialized" part of the contents.} containerLength: UInt32; { Size in bytes of the raw data in the container.} containerOffset: UInt32; { Offset of section's raw data within the container.} options: UInt32; { Array of 32 option bits.} shareKind: UInt8; { Sharing level, if a writeable section.} alignment: UInt8; { Required alignment, expressed as log 2.} reservedA: UInt16; { Reserved, must be written as zero.} reservedB: UInt32; { Reserved, must be written as zero.} reservedC: UInt32; { Reserved, must be written as zero.} end; const { Masks for instantiated section options.} { Bits that define the preparation and usage of the section's contents.} kPEF2SectionHasCodeMask = $00000001; { Affects cache flushing operations.} kPEF2SectionIsWriteableMask = $00000002; { Affects MMU access.} kPEF2SectionHasRelocationsMask = $00000004; { The section has runtime relocations.} kPEF2SectionContentsArePackedMask = $00000100; { The raw data is compressed.} kPEF2SectionNoZeroFillMask = $00000200; { "Uninit" part is not zero filled.} kPEF2SectionResidentMask = $00000400; { The section should be RAM resident.} { Bits that describe higher level semantics.} kPEF2SectionFollowsPriorMask = $00010000; { Raw data is related to prior section.} kPEF2SectionPrecedesNextMask = $00020000; { Raw data is related to next section.} kPEF2SectionHasLoaderTablesMask = $01000000; kPEF2SectionHasDebugTablesMask = $02000000; kPEF2SectionHasExceptionTablesMask = $04000000; kPEF2SectionHasTracebackTablesMask = $08000000; const { Values for the shareKind field.} kPEF2PrivateShare = 0; { Shared only within a "private" closure.} kPEF2ProcessShare = 1; { Shared within a single process.} kPEF2GlobalShare = 4; { Shared across the entire system.} kPEF2ProtectedShare = 5; { Readable across the entire system, writeable only to privileged code.} { =========================================================================================== } { Loader Section } { ============== } { -------------------------------------------------------------------------------------------- } { The PEF2 loader section is very similar to that of PEF. The following overall layout is } { not required, but suggested for typical locality of reference. The loader header contains } { explicit offsets and sizes for each of the subsections. } { +-----------------------------------+ } { | Loader Info Header | } { |-----------------------------------| } { | Imported Library 0 | } { |...................................| } { | - - - | } { |...................................| } { | Imported Library l-1 | } { |-----------------------------------| } { | Imported Symbol 0 | } { |...................................| } { | - - - | } { |...................................| } { | Imported Symbol i-1 | } { |-----------------------------------| } { | Loader Name Table | } { |-----------------------------------| } { | Export Hash Slot 0 | } { |...................................| } { | - - - | } { |...................................| } { | Export Hash Slot h-1 | } { |-----------------------------------| } { | Exported Symbol Key 0 | } { |...................................| } { | - - - | } { |...................................| } { | Exported Symbol Key e-1 | } { |-----------------------------------| } { | Exported Symbol 0 | } { |...................................| } { | - - - | } { |...................................| } { | Exported Symbol e-1 | } { |-----------------------------------| } { | Relocation Header 0 | } { |...................................| } { | - - - | } { |...................................| } { | Relocation Header r-1 | } { |-----------------------------------| } { | Relocation Instructions | } { +-----------------------------------+ } type PEF2LoaderInfoHeaderPtr = ^PEF2LoaderInfoHeader; PEF2LoaderInfoHeader = record headerSize: UInt32; { Size in bytes of the loader info header.} options: UInt32; { An array of 32 option bits.} mainSection: SInt32; { Section containing the main symbol, -1 => none.} mainOffset: UInt32; { Offset of main symbol.} initSection: SInt32; { Section containing the init routine's TVector, -1 => none.} initOffset: UInt32; { Offset of the init routine's TVector.} termSection: SInt32; { Section containing the term routine's TVector, -1 => none.} termOffset: UInt32; { Offset of the term routine's TVector.} notifySection: SInt32; { Section containing the notification routine's TVector, -1 => none.} notifyOffset: UInt32; { Offset of the notification routine's TVector.} importedLibrariesOffset: UInt32; { Offset of the imported library table.} importedLibrarySize: UInt32; { The size in bytes of an imported library entry.} importedLibraryCount: UInt32; { Number of imported libraries. ('l')} importedSymbolsOffset: UInt32; { Offset of the imported symbol table.} importedSymbolSize: UInt32; { The size in bytes of an imported symbol entry.} totalImportedSymbolCount: UInt32; { Total number of imported symbols. ('s')} loaderNamesOffset: UInt32; { Offset of the loader name table.} loaderNamesLength: UInt32; { Total number of bytes in the loader name table.} exportHashTableOffset: UInt32; { Offset of the export hash slot table.} exportHashTablePower: UInt8; { Hash slot count as log 2.} reservedA: UInt8; { Reserved, must be zero.} reservedB: UInt16; { Reserved, must be zero.} exportedKeysOffset: UInt32; { Offset of the exported symbol key table.} exportedSymbolsOffset: UInt32; { Offset of the exported symbol table.} exportedSymbolSize: UInt32; { The size in bytes of an exported symbol entry.} exportedSymbolCount: UInt32; { Number of exported symbols. ('e')} relocHeadersOffset: UInt32; { Offset of the relocation headers.} relocHeaderCount: UInt32; { Number of sections with relocations.} relocInstrOffset: UInt32; { Offset of the relocation instructions.} relocInstrLength: UInt32; { Total number of bytes of relocation instructions.} reservedC: UInt32; { Reserved, must be zero.} reservedD: UInt32; { Reserved, must be zero.} end; const { Masks for the option bits.} kPEF2LdrInfoLargeImpSymMask = $00000001; { Selects large imported symbol entries.} kPEF2LdrInfoLargeExpSymMask = $00000002; { Selects large exported symbol entries.} kPEF2LdrInfoLargeExpHashMask = $00000004; { Selects large export hash table entries.} { =========================================================================================== } { Imports and Exports } { ------------------- } { -------------------------------------------------------------------------------------------- } { Imports and exports in PEF2 have both small and large representations. The small form is } { identical to original PEF. The large form removes count limitations by having full 32 bit } { offsets. The import and export name tables have the same representation as the container } { string table, four bytes of zero at the start followed by pairs of 32 bit hashwords and } { the names in the appropriate encoding. } type PEF2ImportedLibraryPtr = ^PEF2ImportedLibrary; PEF2ImportedLibrary = record nameOffset: UInt32; { Imported name table offset of library's name.} oldImpVersion: UInt32; { Oldest compatible implementation version.} currentVersion: UInt32; { Current version at build time.} importedSymbolCount: UInt32; { Imported symbol count for this library.} firstImportedSymbol: UInt32; { Index of first imported symbol from this library.} options: UInt32; { Option bits for this library.} reservedA: UInt32; { Reserved, must be zero.} end; const { Bits for the PEF2ImportedLibrary options field.} kPEF2WeakImportLibMask = kPEFWeakImportLibMask; { The imported library is allowed to be missing.} kPEF2InitLibBeforeMask = kPEFInitLibBeforeMask; { The imported library must be initialized first.} type PEF2SmImportedSymbol = PEFImportedSymbol; // PEF2ComposeSmImportedSymbol = PEFComposeImportedSymbol; type PEF2LgImportedSymbolPtr = ^PEF2LgImportedSymbol; PEF2LgImportedSymbol = record symClass: UInt8; flags: UInt8; reservedA: UInt16; nameOffset: UInt32; versionPair: UInt32; reservedB: UInt32; end; PEF2SmExportedSymbolHashSlot = PEFExportedSymbolHashSlot; PEF2ExportedSymbolKey = PEFExportedSymbolKey; PEF2SmExportedSymbol = PEFExportedSymbol; // PEF2ComposeSmExportedSymbol = PEFComposeExportedSymbol; type PEF2LgExportedSymbolHashSlotPtr = ^PEF2LgExportedSymbolHashSlot; PEF2LgExportedSymbolHashSlot = record chainCount: UInt32; chainOffset: UInt32; end; type PEF2LgExportedSymbolPtr = ^PEF2LgExportedSymbol; PEF2LgExportedSymbol = record symClass: UInt8; flags: UInt8; reservedA: UInt16; nameOffset: UInt32; versionPair: UInt32; sectionIndex: SInt32; sectionOffset: UInt32; reservedB: UInt32; end; { =========================================================================================== } { Loader Relocations } { ================== } { -------------------------------------------------------------------------------------------- } { The relocation header differs slightly in PEF2. The relocation instructions identical. } type PEF2LoaderRelocationHeaderPtr = ^PEF2LoaderRelocationHeader; PEF2LoaderRelocationHeader = record sectionIndex: UInt32; { Index of the section to be fixed up.} relocLength: UInt32; { Number of bytes of relocation items.} firstRelocOffset: UInt32; { Byte offset of first relocation instruction.} reservedA: UInt32; { Reserved, must be zero.} end; { =========================================================================================== } {$endc} {IncludePEF2Declarations} {$endc} {TARGET_OS_MAC} {$ifc not defined MACOSALLINCLUDE or not MACOSALLINCLUDE} end. {$endc} {not MACOSALLINCLUDE}