2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
31 #include <uuid/uuid.h>
32 #include <mach/mach.h>
33 #include <mach-o/loader.h>
35 #include "Diagnostics.h"
37 #include "MachOLoaded.h"
38 #include "SupportedArchs.h"
49 // bump this number each time binary format changes
50 enum { kFormatVersion
= 10 };
53 typedef uint32_t ImageNum
;
55 const ImageNum kFirstDyldCacheImageNum
= 0x00000001;
56 const ImageNum kLastDyldCacheImageNum
= 0x00000FFF;
57 const ImageNum kFirstOtherOSImageNum
= 0x00001001;
58 const ImageNum kLastOtherOSImageNum
= 0x00001FFF;
59 const ImageNum kFirstLaunchClosureImageNum
= 0x00002000;
60 const ImageNum kMissingWeakLinkedImage
= 0x0FFFFFFF;
62 class ObjCSelectorOpt
;
64 class ObjCClassDuplicatesOpt
;
67 // Generic typed range of bytes (similar to load commands)
68 // Must be 4-byte aligned
70 struct VIS_HIDDEN TypedBytes
72 enum class Type
: uint32_t {
73 // containers which have an overall length and TypedBytes inside their content
74 launchClosure
= 1, // contains TypedBytes of closure attributes including imageArray
75 imageArray
= 2, // sizeof(ImageArray) + sizeof(uint32_t)*count + size of all images
76 image
= 3, // contains TypedBytes of image attributes
77 dlopenClosure
= 4, // contains TypedBytes of closure attributes including imageArray
79 // attributes for Images
80 imageFlags
= 7, // sizeof(Image::Flags)
81 pathWithHash
= 8, // len = uint32_t + length path + 1, use multiple entries for aliases
82 fileInodeAndTime
= 9, // sizeof(FileInfo)
83 cdHash
= 10, // 20, use multiple entries on watchOS for all hashes
85 mappingInfo
= 12, // sizeof(MappingInfo)
86 diskSegment
= 13, // sizeof(DiskSegment) * count
87 cacheSegment
= 14, // sizeof(DyldCacheSegment) * count
88 dependents
= 15, // sizeof(LinkedImage) * count
89 initOffsets
= 16, // sizeof(uint32_t) * count
90 dofOffsets
= 17, // sizeof(uint32_t) * count
91 codeSignLoc
= 18, // sizeof(CodeSignatureLocation)
92 fairPlayLoc
= 19, // sizeof(FairPlayRange)
93 rebaseFixups
= 20, // sizeof(RebasePattern) * count
94 bindFixups
= 21, // sizeof(BindPattern) * count
95 cachePatchInfo
= 22, // deprecated
96 textFixups
= 23, // sizeof(TextFixupPattern) * count
97 imageOverride
= 24, // sizeof(ImageNum)
98 initBefores
= 25, // sizeof(ImageNum) * count
99 initsSection
= 26, // sizeof(InitializerSectionRange)
100 chainedFixupsTargets
= 27, // sizeof(ResolvedSymbolTarget) * count
101 termOffsets
= 28, // sizeof(uint32_t) * count
102 chainedStartsOffset
= 29, // sizeof(uint64_t)
103 objcFixups
= 30, // sizeof(ResolvedSymbolTarget) + (sizeof(uint32_t) * 2) + (sizeof(ProtocolISAFixup) * count) + (sizeof(SelectorReferenceFixup) * count)
105 // attributes for Closures (launch or dlopen)
106 closureFlags
= 32, // sizeof(Closure::Flags)
107 dyldCacheUUID
= 33, // 16
109 envVar
= 35, // "DYLD_BLAH=stuff"
110 topImage
= 36, // sizeof(ImageNum)
111 libDyldEntry
= 37, // sizeof(ResolvedSymbolTarget)
112 libSystemNum
= 38, // sizeof(ImageNum)
113 bootUUID
= 39, // c-string 40
114 mainEntry
= 40, // sizeof(ResolvedSymbolTarget)
115 startEntry
= 41, // sizeof(ResolvedSymbolTarget) // used by programs built with crt1.o
116 cacheOverrides
= 42, // sizeof(PatchEntry) * count // used if process uses interposing or roots (cached dylib overrides)
117 interposeTuples
= 43, // sizeof(InterposingTuple) * count
118 existingFiles
= 44, // uint64_t + (SkippedFiles * count)
119 selectorTable
= 45, // uint32_t + (sizeof(ObjCSelectorImage) * count) + hashTable size
120 classTable
= 46, // (3 * uint32_t) + (sizeof(ObjCClassImage) * count) + classHashTable size + protocolHashTable size
121 warning
= 47, // len = uint32_t + length path + 1, use one entry per warning
122 duplicateClassesTable
= 48, // duplicateClassesHashTable
123 progVars
= 49, // sizeof(uint32_t)
127 uint32_t payloadLength
: 24;
129 const void* payload() const;
133 static_assert(sizeof(TypedBytes
) == 4, "Wrong size for TypedBytes");
137 // A TypedBytes which is a bag of other TypedBytes
139 struct VIS_HIDDEN ContainerTypedBytes
: TypedBytes
141 void forEachAttribute(void (^callback
)(const TypedBytes
* typedBytes
, bool& stop
)) const;
142 void forEachAttributePayload(Type requestedType
, void (^handler
)(const void* payload
, uint32_t size
, bool& stop
)) const;
143 const void* findAttributePayload(Type requestedType
, uint32_t* payloadSize
=nullptr) const;
145 const TypedBytes
* first() const;
146 const TypedBytes
* next(const TypedBytes
*) const;
151 // Information about a mach-o file
153 struct VIS_HIDDEN Image
: ContainerTypedBytes
155 enum class LinkKind
{ regular
=0, weak
=1, upward
=2, reExport
=3 };
158 ImageNum
imageNum() const;
159 bool representsImageNum(ImageNum num
) const; // imageNum() or isOverrideOfDyldCacheImage()
160 uint32_t maxLoadCount() const;
161 const char* path() const;
162 const char* leafName() const;
163 bool getUuid(uuid_t
) const;
164 bool isInvalid() const;
165 bool inDyldCache() const;
166 bool hasObjC() const;
167 bool hasInitializers() const;
168 bool hasPrecomputedObjC() const;
169 bool hasTerminators() const;
170 bool hasReadOnlyData() const;
171 bool hasChainedFixups() const;
172 bool isBundle() const;
173 bool isDylib() const;
174 bool isExecutable() const;
175 bool hasWeakDefs() const;
176 bool mayHavePlusLoads() const;
178 bool neverUnload() const;
179 bool cwdMustBeThisDir() const;
180 bool isPlatformBinary() const;
181 bool overridableDylib() const;
182 bool hasFileModTimeAndInode(uint64_t& inode
, uint64_t& mTime
) const;
183 void forEachCDHash(void (^handler
)(const uint8_t cdHash
[20], bool& stop
)) const;
184 void forEachAlias(void (^handler
)(const char* aliasPath
, bool& stop
)) const;
185 void forEachDependentImage(void (^handler
)(uint32_t dependentIndex
, LinkKind kind
, ImageNum imageNum
, bool& stop
)) const;
186 ImageNum
dependentImageNum(uint32_t depIndex
) const;
187 bool containsAddress(const void* addr
, const void* imageLoadAddress
, uint8_t* permissions
=nullptr) const;
188 bool forEachInitializerSection(void (^handler
)(uint32_t sectionOffset
, uint32_t sectionSize
)) const;
189 void forEachInitializer(const void* imageLoadAddress
, void (^handler
)(const void* initializer
)) const;
190 void forEachTerminator(const void* imageLoadAddress
, void (^handler
)(const void* terminator
)) const;
191 void forEachImageToInitBefore(void (^handler
)(ImageNum imageToInit
, bool& stop
)) const;
192 void forEachDOF(const void* imageLoadAddress
, void (^handler
)(const void* initializer
)) const;
193 bool hasPathWithHash(const char* path
, uint32_t hash
) const;
194 bool isOverrideOfDyldCacheImage(ImageNum
& cacheImageNum
) const;
195 uint64_t textSize() const;
197 union ResolvedSymbolTarget
199 enum Kinds
{ kindRebase
, kindSharedCache
, kindImage
, kindAbsolute
};
202 uint64_t kind
: 2, // kindRebase
203 unused
: 62; // all zeros
206 uint64_t kind
: 2; // kindSharedCache
210 uint64_t kind
: 2, // kindImage
211 imageNum
: 22; // ImageNum
215 uint64_t kind
: 2, // kindAbsolute
216 value
: 62; // sign extended
219 SharedCache sharedCache
;
224 bool operator==(const ResolvedSymbolTarget
& rhs
) const {
225 return (raw
== rhs
.raw
);
227 bool operator!=(const ResolvedSymbolTarget
& rhs
) const {
228 return (raw
!= rhs
.raw
);
231 static_assert(sizeof(ResolvedSymbolTarget
) == 8, "Invalid size");
234 // ObjC optimisations
235 struct ObjCImageOffset
{
239 uint32_t imageIndex
: 8;
240 uint32_t imageOffset
: 24;
245 // The unused value so that we have a sentinel in our hash table
246 sentinelValue
= 0xFFFFFFFF,
248 // The maximum image index
249 maximumImageIndex
= (1U << 8) - 1,
251 // The maximum offset from the start of the strings section
252 maximumOffset
= (1U << 24) - 1
256 struct ObjCClassNameImageOffset
{
260 uint32_t classNameImageIndex
: 8;
261 uint32_t classNameImageOffset
: 24;
266 // The unused value so that we have a sentinel in our hash table
267 sentinelValue
= 0xFFFFFFFF,
269 // The maximum image index
270 maximumImageIndex
= (1U << 8) - 1,
272 // The maximum offset from the start of the strings section
273 maximumOffset
= (1U << 24) - 1
277 struct ObjCClassImageOffset
{
281 uint32_t imageIndex
: 8;
282 uint32_t imageOffset
: 23;
283 uint32_t isDuplicate
: 1; // == 0
288 uint32_t isDuplicate
: 1; // == 1
293 // The unused value so that we have a sentinel in our hash table
294 sentinelValue
= 0xFFFFFFFF,
296 // The maximum image index
297 maximumImageIndex
= (1U << 8) - 1,
299 // The maximum offset from the start of the class data section
300 maximumOffset
= (1U << 23) - 1
304 static_assert(sizeof(ObjCClassImageOffset
) == 4, "Invalid size");
306 static_assert(ObjCClassNameImageOffset
::maximumImageIndex
== ObjCClassImageOffset
::maximumImageIndex
, "Invalid indices");
308 struct ObjCDuplicateClass
{
312 uint32_t sharedCacheClassOptIndex
: 20;
313 uint32_t sharedCacheClassDuplicateIndex
: 12;
318 // The unused value so that we have a sentinel in our hash table
319 sentinelValue
= 0xFFFFFFFF
323 static_assert(sizeof(ObjCDuplicateClass
) == 4, "Invalid size");
325 struct ObjCSelectorImage
{
330 struct ObjCClassImage
{
332 uint32_t offsetOfClassNames
;
333 uint32_t offsetOfClasses
;
336 typedef MachOLoaded
::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk
;
338 // the following are only valid if inDyldCache() returns true
339 uint32_t cacheOffset() const;
340 uint32_t patchStartIndex() const;
341 uint32_t patchCount() const;
342 void forEachCacheSegment(void (^handler
)(uint32_t segIndex
, uint64_t vmOffset
, uint64_t vmSize
, uint8_t permissions
, bool& stop
)) const;
345 // the following are only valid if inDyldCache() returns false
346 uint64_t vmSizeToMap() const;
347 uint64_t sliceOffsetInFile() const;
348 bool hasCodeSignature(uint32_t& fileOffset
, uint32_t& size
) const;
349 bool isFairPlayEncrypted(uint32_t& textOffset
, uint32_t& size
) const;
350 void forEachDiskSegment(void (^handler
)(uint32_t segIndex
, uint32_t fileOffset
, uint32_t fileSize
, int64_t vmOffset
, uint64_t vmSize
,
351 uint8_t permissions
, bool laterReadOnly
, bool& stop
)) const;
352 void forEachFixup(void (^rebase
)(uint64_t imageOffsetToRebase
, bool& stop
),
353 void (^bind
)(uint64_t imageOffsetToBind
, ResolvedSymbolTarget bindTarget
, bool& stop
),
354 void (^chainedFixups
)(uint64_t imageOffsetToStarts
, const Array
<ResolvedSymbolTarget
>& targets
, bool& stop
),
355 void (^fixupObjCImageInfo
)(uint64_t imageOffsetToFixup
),
356 void (^fixupObjCProtocol
)(uint64_t imageOffsetToBind
, ResolvedSymbolTarget bindTarget
, bool& stop
),
357 void (^fixupObjCSelRef
)(uint64_t imageOffsetToFixup
, uint32_t selectorIndex
, bool inSharedCache
, bool& stop
),
358 void (^fixupObjCStableSwift
)(uint64_t imageOffsetToFixup
, bool& stop
),
359 void (^fixupObjCMethodList
)(uint64_t imageOffsetToFixup
, bool& stop
)) const;
360 void forEachTextReloc(void (^rebase
)(uint32_t imageOffsetToRebase
, bool& stop
),
361 void (^bind
)(uint32_t imageOffsetToBind
, ResolvedSymbolTarget bindTarget
, bool& stop
)) const;
363 static_assert(sizeof(ResolvedSymbolTarget
) == 8, "Overflow in size of SymbolTargetLocation");
365 static uint32_t hashFunction(const char*);
368 friend struct Closure
;
369 friend class ImageWriter
;
370 friend class ClosureBuilder
;
371 friend class ClosureWriter
;
372 friend class LaunchClosureWriter
;
374 uint32_t pageSize() const;
378 uint64_t imageNum
: 16,
380 isInvalid
: 1, // an error occurred creating the info for this image
384 mayHavePlusLoads
: 1,
385 isEncrypted
: 1, // image is DSMOS or FairPlay encrypted
388 cwdSameAsThis
: 1, // dylibs use file system relative paths, cwd must be main's dir
389 isPlatformBinary
: 1, // part of OS - can be loaded into LV process
393 overridableDylib
: 1, // only applicable to cached dylibs
397 hasChainedFixups
: 1,
398 hasPrecomputedObjC
: 1,
402 static_assert(sizeof(Flags
) == sizeof(uint64_t), "Flags overflow");
404 const Flags
& getFlags() const;
412 // In disk based images, all segments are multiples of page size
413 // This struct just tracks the size (disk and vm) of each segment.
414 // This is compact for most every image which have contiguous segments.
415 // If the image does not have contiguous segments (rare), an extra
416 // DiskSegment is inserted with the paddingNotSeg bit set.
419 uint64_t filePageCount
: 30,
424 // We only have three bits for permissions, and need a way to
425 // encode segments that are initially r/w then made read-only
426 // after fixups are done. Previously, the only valid patterns
427 // were: ---, r--, rw-, r-x. We now add -w- to mean r/w -> r/o.
428 enum { kReadOnlyDataPermissions
= VM_PROT_WRITE
};
432 // In cache DATA_DIRTY is not page aligned or sized
433 // This struct allows segments with any alignment and up to 256MB in size
434 struct DyldCacheSegment
436 uint64_t cacheOffset
: 32,
441 struct CodeSignatureLocation
455 uint32_t rangeStart
; // The byte offset of the start of the range.
456 uint32_t rangeLength
; // How long is the fairplay range in bytes
461 uint32_t totalVmPages
;
462 uint32_t sliceOffsetIn4K
;
465 struct InitializerSectionRange
467 uint32_t sectionOffset
;
468 uint32_t sectionSize
;
473 LinkedImage() : imgNum(0), linkKind(0) {
475 LinkedImage(LinkKind k
, ImageNum num
) : imgNum(num
), linkKind((uint32_t)k
) {
476 assert((num
& 0xC0000000) == 0);
479 LinkKind
kind() const { return (LinkKind
)linkKind
; }
480 ImageNum
imageNum() const { return imgNum
; }
481 void clearKind() { linkKind
= 0; }
483 bool operator==(const LinkedImage
& rhs
) const {
484 return (linkKind
== rhs
.linkKind
) && (imgNum
== rhs
.imgNum
);
486 bool operator!=(const LinkedImage
& rhs
) const {
487 return (linkKind
!= rhs
.linkKind
) || (imgNum
!= rhs
.imgNum
);
490 uint32_t imgNum
: 30,
491 linkKind
: 2; // LinkKind
494 const Array
<LinkedImage
> dependentsArray() const;
498 uint32_t repeatCount
: 20,
499 contigCount
: 8, // how many contiguous pointers neeed rebasing
500 skipCount
: 4; // how many pointers to skip between contig groups
501 // If contigCount == 0, then there are no rebases for this entry,
502 // instead it advances the rebase location by repeatCount*skipCount.
503 // If all fields are zero, then the rebase position is reset to the start.
504 // This is to support old binaries with some non-monotonically-increasing rebases.
506 const Array
<RebasePattern
> rebaseFixups() const;
510 Image
::ResolvedSymbolTarget target
;
511 uint64_t startVmOffset
: 40, // max 1TB offset
515 const Array
<BindPattern
> bindFixups() const;
517 // An optimzied selector reference bind will either point to the shared cache
518 // or a binary optimized in our launch closure. We can use the index in to each
519 // of their respective selector hash tables as the target or the bind.
520 union SelectorReferenceFixup
522 uint32_t chainStartVMOffset
;
524 uint32_t index
: 24, // max 16m entries in the table
525 next
: 7, // (next * 4) -> offset to next fixup
526 inSharedCache
: 1; // 0 -> in the closure. 1 -> in the cache
530 struct ProtocolISAFixup
532 uint64_t startVmOffset
: 40, // max 1TB offset
537 struct ClassStableSwiftFixup
539 uint64_t startVmOffset
: 40, // max 1TB offset
544 struct MethodListFixup
546 uint64_t startVmOffset
: 40, // max 1TB offset
551 void objcFixups(ResolvedSymbolTarget
& objcProtocolClassTarget
,
552 uint64_t& objcImageInfoVMOffset
,
553 Array
<ProtocolISAFixup
>& protocolISAFixups
,
554 Array
<SelectorReferenceFixup
>& selRefFixups
,
555 Array
<ClassStableSwiftFixup
>& classStableSwiftFixups
,
556 Array
<MethodListFixup
>& methodListFixups
) const;
558 struct TextFixupPattern
560 Image
::ResolvedSymbolTarget target
;
561 uint32_t startVmOffset
;
562 uint16_t repeatCount
;
565 const Array
<TextFixupPattern
> textFixups() const;
567 // for use with chained fixups
568 uint64_t chainedStartsOffset() const;
569 const Array
<Image
::ResolvedSymbolTarget
> chainedTargets() const;
574 Dyld cache patching notes:
576 The dyld cache needs to be patched to support interposing and dylib "roots".
578 For cached dylibs overrides:
580 1) LoadedImages will contain the new dylib, so all symbol look ups
581 will naturally find new impl. Only dyld cache needs special help.
582 2) LoadedImages entry will have flag for images that override cache.
583 3) When setting Closure attributes, if flag is set, builder will
584 iterate PatchableExport entries in Image* from cache and create
585 a PatchEntry for each.
587 1) [lib]dyld will iterate PatchEntry in closure and patch cache
591 1) After Images built, if __interpose section(s) exist, builder will
592 build InterposingTuple entries for closure
593 2) For being-built closure and launch closure, apply any InterposingTuple
594 to modify Image fixups before Image finalized.
595 3) Builder will find PatchableExport entry that matchs stock Impl
596 and add PatchEntry to closure for it.
598 1) When closure is loaded (launch or dlopen) PatchEntries are
599 applied (exactly once) to whole cache.
600 2) For each DlopenClosure loaded, any InterposeTuples in *launch* closure
601 are applied to all new images in new DlopenClosure.
603 For weak-def coalesing:
605 1) weak_bind entries are turned into -3 ordinal lookup which search through images
606 in load order for first def (like flat). This fixups up all images not in cache.
607 2) When processing -3 ordinals, it continues past first found and if any images
608 past it are in dyld cache and export that same symbol, a PatchEntry is added to
609 closure to fix up all cached uses of that symbol.
610 3) If a weak_bind has strong bit set (no fixup, just def), all images from the dyld
611 cache are checked to see if the export that symbol, if so, a PatchEntry is added
614 1) When closure is loaded (launch or dlopen) PatchEntries are
615 applied (exactly once) to whole cache.
621 // An array (accessible by index) list of Images
623 struct VIS_HIDDEN ImageArray
: public TypedBytes
626 size_t startImageNum() const;
627 uint32_t imageCount() const;
628 void forEachImage(void (^callback
)(const Image
* image
, bool& stop
)) const;
629 bool hasPath(const char* path
, ImageNum
& num
) const;
630 const Image
* imageForNum(ImageNum
) const;
631 void deallocate() const;
633 static const Image
* findImage(const Array
<const ImageArray
*> imagesArrays
, ImageNum imageNum
);
636 friend class ImageArrayWriter
;
638 uint32_t firstImageNum
;
640 uint32_t hasRoots
: 1; // True if this ImageArray contains roots with imageNum's below firstImageNum
646 struct InterposingTuple
648 Image
::ResolvedSymbolTarget stockImplementation
;
649 Image
::ResolvedSymbolTarget newImplementation
;
654 // Describes how dyld should load a set of mach-o files
656 struct VIS_HIDDEN Closure
: public ContainerTypedBytes
659 const ImageArray
* images() const;
660 ImageNum
topImage() const;
661 void deallocate() const;
663 friend class ClosureWriter
;
667 ImageNum overriddenDylibInCache
;
668 uint32_t exportCacheOffset
;
669 Image
::ResolvedSymbolTarget replacement
;
674 enum Type
: uint32_t {
675 duplicateObjCClass
= 0
682 void forEachPatchEntry(void (^handler
)(const PatchEntry
& entry
)) const;
683 void forEachWarning(Warning
::Type type
, void (^handler
)(const char* warning
, bool& stop
)) const;
688 // Describes how dyld should launch a main executable
690 struct VIS_HIDDEN LaunchClosure
: public Closure
692 // Represents a file on disk we tried to load but skipped as it wasn't valid for our use
700 bool builtAgainstDyldCache(uuid_t cacheUUID
) const;
701 const char* bootUUID() const;
702 void forEachMustBeMissingFile(void (^handler
)(const char* path
, bool& stop
)) const;
703 void forEachSkipIfExistsFile(void (^handler
)(const SkippedFile
& file
, bool& stop
)) const;
704 void forEachEnvVar(void (^handler
)(const char* keyEqualValue
, bool& stop
)) const;
705 ImageNum
libSystemImageNum() const;
706 void libDyldEntry(Image
::ResolvedSymbolTarget
& loc
) const;
707 bool mainEntry(Image
::ResolvedSymbolTarget
& mainLoc
) const;
708 bool startEntry(Image
::ResolvedSymbolTarget
& startLoc
) const;
709 uint32_t initialLoadCount() const;
710 void forEachInterposingTuple(void (^handler
)(const InterposingTuple
& tuple
, bool& stop
)) const;
711 bool usedAtPaths() const;
712 bool usedFallbackPaths() const;
713 bool usedInterposing() const;
714 bool selectorHashTable(Array
<Image
::ObjCSelectorImage
>& imageNums
,
715 const ObjCSelectorOpt
*& hashTable
) const;
716 bool classAndProtocolHashTables(Array
<Image
::ObjCClassImage
>& imageNums
,
717 const ObjCClassOpt
*& classHashTable
,
718 const ObjCClassOpt
*& protocolHashTable
) const;
719 void duplicateClassesHashTable(const ObjCClassDuplicatesOpt
*& duplicateClassesHashTable
) const;
720 bool hasInsertedLibraries() const;
721 bool hasInterposings() const;
722 bool hasProgramVars(uint32_t& runtimeOffset
) const;
724 static bool buildClosureCachePath(const char* mainExecutablePath
, char closurePath
[], const char* tempDir
,
725 bool makeDirsIfMissing
);
728 friend class LaunchClosureWriter
;
732 uint32_t usedAtPaths
: 1,
733 usedFallbackPaths
: 1,
735 hasInsertedLibraries
: 1,
740 const Flags
& getFlags() const;
746 // Describes how dyld should dlopen() a mach-o file
748 struct VIS_HIDDEN DlopenClosure
: public Closure
753 // Precomputed perfect hash table of strings.
754 // Base class for closure precomputed selector table and class table.
755 class VIS_HIDDEN ObjCStringTable
{
757 typedef uint32_t StringTarget
;
760 typedef uint8_t StringHashCheckByte
;
768 StringTarget sentinelTarget
;
769 uint32_t roundedTabSize
;
772 uint32_t scramble
[256];
773 uint8_t tab
[0]; /* tab[mask+1] (always power-of-2). Rounded up to roundedTabSize */
774 // uint8_t checkbytes[capacity]; /* check byte for each string */
775 // int32_t offsets[capacity]; /* offsets from &capacity to cstrings */
777 StringHashCheckByte
* checkBytesOffset() {
778 return &tab
[roundedTabSize
];
781 const StringHashCheckByte
* checkBytesOffset() const {
782 return &tab
[roundedTabSize
];
785 StringTarget
* targetsOffset() {
786 return (StringTarget
*)(checkBytesOffset() + capacity
);
789 const StringTarget
* targetsOffset() const {
790 return (StringTarget
*)(checkBytesOffset() + capacity
);
793 dyld3
::Array
<StringHashCheckByte
> checkBytes() {
794 return dyld3
::Array
<StringHashCheckByte
>((StringHashCheckByte
*)checkBytesOffset(), capacity
, capacity
);
796 const dyld3
::Array
<StringHashCheckByte
> checkBytes() const {
797 return dyld3
::Array
<StringHashCheckByte
>((StringHashCheckByte
*)checkBytesOffset(), capacity
, capacity
);
800 dyld3
::Array
<StringTarget
> targets() {
801 return dyld3
::Array
<StringTarget
>((StringTarget
*)targetsOffset(), capacity
, capacity
);
803 const dyld3
::Array
<StringTarget
> targets() const {
804 return dyld3
::Array
<StringTarget
>((StringTarget
*)targetsOffset(), capacity
, capacity
);
807 uint32_t hash(const char *key
, size_t keylen
) const;
809 uint32_t hash(const char *key
) const
811 return hash(key
, strlen(key
));
814 // The check bytes areused to reject strings that aren't in the table
815 // without paging in the table's cstring data. This checkbyte calculation
816 // catches 4785/4815 rejects when launching Safari; a perfect checkbyte
817 // would catch 4796/4815.
818 StringHashCheckByte
checkbyte(const char *key
, size_t keylen
) const
820 return ((key
[0] & 0x7) << 5) | ((uint8_t)keylen
& 0x1f);
823 StringHashCheckByte
checkbyte(const char *key
) const
825 return checkbyte(key
, strlen(key
));
828 StringTarget
getPotentialTarget(const char *key
) const
830 uint32_t index
= getIndex(key
);
831 if (index
== indexNotFound
)
832 return sentinelTarget
;
833 return targets()[index
];
843 uint32_t getIndex(const char *key
) const
845 size_t keylen
= strlen(key
);
846 uint32_t h
= hash(key
, keylen
);
848 // Use check byte to reject without paging in the table's cstrings
849 StringHashCheckByte h_check
= checkBytes()[h
];
850 StringHashCheckByte key_check
= checkbyte(key
, keylen
);
851 if (h_check
!= key_check
)
852 return indexNotFound
;
856 template<typename PerfectHashT
>
857 static size_t size(const PerfectHashT
& phash
) {
858 // Round tab[] to at least 4 in length to ensure the uint32_t's after are aligned
859 uint32_t roundedTabSize
= std
::max(phash
.mask
+1, 4U);
860 size_t tableSize
= 0;
861 tableSize
+= sizeof(ObjCStringTable
);
862 tableSize
+= roundedTabSize
;
863 tableSize
+= phash
.capacity
* sizeof(StringHashCheckByte
);
864 tableSize
+= phash
.capacity
* sizeof(StringTarget
);
868 // Get a string if it has an entry in the table
869 const char* getString(const char* selName
, const Array
<uintptr_t>& baseAddresses
) const;
871 void forEachString(const Array
<Image
::ObjCSelectorImage
>& selectorImages
,
872 void (^callback
)(uint64_t selVMOffset
, ImageNum imageNum
)) const;
874 template<typename PerfectHashT
, typename ImageOffsetT
>
875 void write(const PerfectHashT
& phash
, const Array
<std
::pair
<const char*, ImageOffsetT
>>& strings
);
878 class VIS_HIDDEN ObjCSelectorOpt
: public ObjCStringTable
{
880 // Get a string if it has an entry in the table
881 // Returns true if an entry is found and sets the imageNum and vmOffset.
882 bool getStringLocation(uint32_t index
, const Array
<closure
::Image
::ObjCSelectorImage
>& selImages
,
883 ImageNum
& imageNum
, uint64_t& vmOffset
) const;
885 void forEachString(const Array
<Image
::ObjCSelectorImage
>& selectorImages
,
886 void (^callback
)(uint64_t selVMOffset
, ImageNum imageNum
)) const;
889 class VIS_HIDDEN ObjCClassOpt
: public ObjCStringTable
{
891 // ...ObjCStringTable fields...
892 // ClassTarget classOffsets[capacity]; /* offsets from &capacity to class_t and header_info */
893 // DuplicateCount duplicateCount;
894 // ClassTarget duplicateOffsets[duplicatedClasses];
896 typedef uint32_t DuplicateCount
;
897 typedef Image
::ObjCClassImageOffset ClassTarget
;
899 ClassTarget
*classOffsetsStart() { return (ClassTarget
*)&targetsOffset()[capacity
]; }
900 const ClassTarget
*classOffsetsStart() const { return (const ClassTarget
*)&targetsOffset()[capacity
]; }
902 dyld3
::Array
<ClassTarget
> classOffsets() {
903 return dyld3
::Array
<ClassTarget
>((ClassTarget
*)classOffsetsStart(), capacity
, capacity
);
905 const dyld3
::Array
<ClassTarget
> classOffsets() const {
906 return dyld3
::Array
<ClassTarget
>((ClassTarget
*)classOffsetsStart(), capacity
, capacity
);
909 DuplicateCount
& duplicateCount() { return *(DuplicateCount
*)&classOffsetsStart()[capacity
]; }
910 const DuplicateCount
& duplicateCount() const { return *(const DuplicateCount
*)&classOffsetsStart()[capacity
]; }
912 ClassTarget
*duplicateOffsetsStart() { return (ClassTarget
*)(&duplicateCount()+1); }
913 const ClassTarget
*duplicateOffsetsStart() const { return (const ClassTarget
*)(&duplicateCount()+1); }
915 dyld3
::Array
<ClassTarget
> duplicateOffsets(uint32_t preCalculatedDuplicateCount
) {
916 return dyld3
::Array
<ClassTarget
>((ClassTarget
*)duplicateOffsetsStart(), preCalculatedDuplicateCount
, duplicateCount());
918 const dyld3
::Array
<ClassTarget
> duplicateOffsets(uint32_t preCalculatedDuplicateCount
) const {
919 return dyld3
::Array
<ClassTarget
>((ClassTarget
*)duplicateOffsetsStart(), preCalculatedDuplicateCount
, duplicateCount());
924 template<typename PerfectHashT
>
925 static size_t size(PerfectHashT
& phash
, uint32_t duplicateCount
)
927 size_t tableSize
= 0;
928 tableSize
+= ObjCStringTable
::size(phash
);
929 tableSize
+= phash
.capacity
* sizeof(ClassTarget
);
930 tableSize
+= sizeof(DuplicateCount
);
931 tableSize
+= duplicateCount
* sizeof(ClassTarget
);
935 void forEachClass(const char* className
,
936 const Array
<std
::pair
<uintptr_t, uintptr_t>>& nameAndDataBaseAddresses
,
937 void (^callback
)(void* classPtr
, bool isLoaded
, bool* stop
)) const;
939 void forEachClass(const Array
<Image
::ObjCClassImage
>& classImages
,
940 void (^nameCallback
)(uint64_t classNameVMOffset
, ImageNum imageNum
),
941 void (^implCallback
)(uint64_t classVMOffset
, ImageNum imageNum
)) const;
943 template<typename PerfectHashT
, typename ImageOffsetT
, typename ClassesMapT
>
944 void write(const PerfectHashT
& phash
, const Array
<std
::pair
<const char*, ImageOffsetT
>>& strings
,
945 const ClassesMapT
& classes
, uint32_t preCalculatedDuplicateCount
);
948 class VIS_HIDDEN ObjCClassDuplicatesOpt
: public ObjCStringTable
{
950 // Get a class if it has an entry in the table
951 bool getClassLocation(const char* className
, const objc_opt
::objc_opt_t
* objCOpt
, void*& classImpl
) const;
953 void forEachClass(void (^callback
)(Image
::ObjCDuplicateClass duplicateClass
)) const;
956 } // namespace closure