]> git.saurik.com Git - apple/dyld.git/blob - dyld3/Closure.h
dyld-832.7.1.tar.gz
[apple/dyld.git] / dyld3 / Closure.h
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifndef Closures_h
26 #define Closures_h
27
28
29 #include <stdint.h>
30 #include <assert.h>
31 #include <uuid/uuid.h>
32 #include <mach/mach.h>
33 #include <mach-o/loader.h>
34
35 #include "Diagnostics.h"
36 #include "Array.h"
37 #include "MachOLoaded.h"
38 #include "SupportedArchs.h"
39
40 namespace objc_opt {
41 struct objc_opt_t;
42 }
43
44 namespace dyld3 {
45 namespace closure {
46
47
48
49 // bump this number each time binary format changes
50 enum { kFormatVersion = 10 };
51
52
53 typedef uint32_t ImageNum;
54
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;
61
62 class ObjCSelectorOpt;
63 class ObjCClassOpt;
64 class ObjCClassDuplicatesOpt;
65
66 //
67 // Generic typed range of bytes (similar to load commands)
68 // Must be 4-byte aligned
69 //
70 struct VIS_HIDDEN TypedBytes
71 {
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
78
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
84 uuid = 11, // 16
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)
104
105 // attributes for Closures (launch or dlopen)
106 closureFlags = 32, // sizeof(Closure::Flags)
107 dyldCacheUUID = 33, // 16
108 missingFiles = 34,
109 envVar = 35, // "DYLD_BLAH=stuff"
110 topImage = 36, // sizeof(ImageNum)
111 libDyldEntry = 37, // sizeof(ResolvedSymbolTarget)
112 libSystemNum = 38, // sizeof(ImageNum)
113 mainEntry = 40, // sizeof(ResolvedSymbolTarget)
114 startEntry = 41, // sizeof(ResolvedSymbolTarget) // used by programs built with crt1.o
115 cacheOverrides = 42, // sizeof(PatchEntry) * count // used if process uses interposing or roots (cached dylib overrides)
116 interposeTuples = 43, // sizeof(InterposingTuple) * count
117 existingFiles = 44, // uint64_t + (SkippedFiles * count)
118 selectorTable = 45, // uint32_t + (sizeof(ObjCSelectorImage) * count) + hashTable size
119 classTable = 46, // (3 * uint32_t) + (sizeof(ObjCClassImage) * count) + classHashTable size + protocolHashTable size
120 warning = 47, // len = uint32_t + length path + 1, use one entry per warning
121 duplicateClassesTable = 48, // duplicateClassesHashTable
122 progVars = 49, // sizeof(uint32_t)
123 };
124
125 Type type : 8;
126 uint32_t payloadLength : 24;
127
128 const void* payload() const;
129 void* payload();
130 };
131
132 static_assert(sizeof(TypedBytes) == 4, "Wrong size for TypedBytes");
133
134
135 //
136 // A TypedBytes which is a bag of other TypedBytes
137 //
138 struct VIS_HIDDEN ContainerTypedBytes : TypedBytes
139 {
140 void forEachAttribute(void (^callback)(const TypedBytes* typedBytes, bool& stop)) const;
141 void forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const;
142 const void* findAttributePayload(Type requestedType, uint32_t* payloadSize=nullptr) const;
143 private:
144 const TypedBytes* first() const;
145 const TypedBytes* next(const TypedBytes*) const;
146 };
147
148
149 //
150 // Information about a mach-o file
151 //
152 struct VIS_HIDDEN Image : ContainerTypedBytes
153 {
154 enum class LinkKind { regular=0, weak=1, upward=2, reExport=3 };
155
156 size_t size() const;
157 ImageNum imageNum() const;
158 bool representsImageNum(ImageNum num) const; // imageNum() or isOverrideOfDyldCacheImage()
159 uint32_t maxLoadCount() const;
160 const char* path() const;
161 const char* leafName() const;
162 bool getUuid(uuid_t) const;
163 bool isInvalid() const;
164 bool inDyldCache() const;
165 bool hasObjC() const;
166 bool hasInitializers() const;
167 bool hasPrecomputedObjC() const;
168 bool fixupsNotEncoded() const; // minimal closure, dyld must parse and apply fixups
169 bool rebasesNotEncoded() const;
170 bool hasTerminators() const;
171 bool hasReadOnlyData() const;
172 bool hasChainedFixups() const;
173 bool isBundle() const;
174 bool isDylib() const;
175 bool isExecutable() const;
176 bool hasWeakDefs() const;
177 bool mayHavePlusLoads() const;
178 bool is64() const;
179 bool neverUnload() const;
180 bool cwdMustBeThisDir() 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;
196 const char* variantString() const; // "minimal" or "full" closure
197
198 union ResolvedSymbolTarget
199 {
200 enum Kinds { kindRebase, kindSharedCache, kindImage, kindAbsolute };
201
202 struct Rebase {
203 uint64_t kind : 2, // kindRebase
204 unused : 62; // all zeros
205 };
206 struct SharedCache {
207 uint64_t kind : 2; // kindSharedCache
208 int64_t offset : 62;
209 };
210 struct Image {
211 uint64_t kind : 2, // kindImage
212 imageNum : 22; // ImageNum
213 int64_t offset : 40;
214 };
215 struct Absolute {
216 uint64_t kind : 2, // kindAbsolute
217 value : 62; // sign extended
218 };
219 Rebase rebase;
220 SharedCache sharedCache;
221 Image image;
222 Absolute absolute;
223 uint64_t raw;
224
225 bool operator==(const ResolvedSymbolTarget& rhs) const {
226 return (raw == rhs.raw);
227 }
228 bool operator!=(const ResolvedSymbolTarget& rhs) const {
229 return (raw != rhs.raw);
230 }
231 };
232 static_assert(sizeof(ResolvedSymbolTarget) == 8, "Invalid size");
233
234
235 // ObjC optimisations
236 struct ObjCImageOffset {
237 union {
238 uint32_t raw = 0;
239 struct {
240 uint32_t imageIndex : 8;
241 uint32_t imageOffset : 24;
242 };
243 };
244
245 enum : uint32_t {
246 // The unused value so that we have a sentinel in our hash table
247 sentinelValue = 0xFFFFFFFF,
248
249 // The maximum image index
250 maximumImageIndex = (1U << 8) - 1,
251
252 // The maximum offset from the start of the strings section
253 maximumOffset = (1U << 24) - 1
254 };
255 };
256
257 struct ObjCClassNameImageOffset {
258 union {
259 uint32_t raw = 0;
260 struct {
261 uint32_t classNameImageIndex : 8;
262 uint32_t classNameImageOffset : 24;
263 };
264 };
265
266 enum : uint32_t {
267 // The unused value so that we have a sentinel in our hash table
268 sentinelValue = 0xFFFFFFFF,
269
270 // The maximum image index
271 maximumImageIndex = (1U << 8) - 1,
272
273 // The maximum offset from the start of the strings section
274 maximumOffset = (1U << 24) - 1
275 };
276 };
277
278 struct ObjCClassImageOffset {
279 union {
280 uint32_t raw = 0;
281 struct {
282 uint32_t imageIndex : 8;
283 uint32_t imageOffset : 23;
284 uint32_t isDuplicate : 1; // == 0
285 } classData;
286 struct {
287 uint32_t count : 8;
288 uint32_t index : 23;
289 uint32_t isDuplicate : 1; // == 1
290 } duplicateData;
291 };
292
293 enum : uint32_t {
294 // The unused value so that we have a sentinel in our hash table
295 sentinelValue = 0xFFFFFFFF,
296
297 // The maximum image index
298 maximumImageIndex = (1U << 8) - 1,
299
300 // The maximum offset from the start of the class data section
301 maximumOffset = (1U << 23) - 1
302 };
303 };
304
305 static_assert(sizeof(ObjCClassImageOffset) == 4, "Invalid size");
306
307 static_assert(ObjCClassNameImageOffset::maximumImageIndex == ObjCClassImageOffset::maximumImageIndex , "Invalid indices");
308
309 struct ObjCDuplicateClass {
310 union {
311 uint32_t raw = 0;
312 struct {
313 uint32_t sharedCacheClassOptIndex : 20;
314 uint32_t sharedCacheClassDuplicateIndex : 12;
315 };
316 };
317
318 enum : uint32_t {
319 // The unused value so that we have a sentinel in our hash table
320 sentinelValue = 0xFFFFFFFF
321 };
322 };
323
324 static_assert(sizeof(ObjCDuplicateClass) == 4, "Invalid size");
325
326 struct ObjCSelectorImage {
327 ImageNum imageNum;
328 uint32_t offset;
329 };
330
331 struct ObjCClassImage {
332 ImageNum imageNum;
333 uint32_t offsetOfClassNames;
334 uint32_t offsetOfClasses;
335 };
336
337 typedef MachOLoaded::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
338
339 // the following are only valid if inDyldCache() returns true
340 uint32_t cacheOffset() const;
341 uint32_t patchStartIndex() const;
342 uint32_t patchCount() const;
343 void forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
344
345
346 // the following are only valid if inDyldCache() returns false
347 uint64_t vmSizeToMap() const;
348 uint64_t sliceOffsetInFile() const;
349 bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
350 bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
351 void forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize,
352 uint8_t permissions, bool laterReadOnly, bool& stop)) const;
353 void forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
354 void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
355 void (^chainedFixups)(uint64_t imageOffsetToStarts, const Array<ResolvedSymbolTarget>& targets, bool& stop),
356 void (^fixupObjCImageInfo)(uint64_t imageOffsetToFixup),
357 void (^fixupObjCProtocol)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
358 void (^fixupObjCSelRef)(uint64_t imageOffsetToFixup, uint32_t selectorIndex, bool inSharedCache, bool& stop),
359 void (^fixupObjCStableSwift)(uint64_t imageOffsetToFixup, bool& stop),
360 void (^fixupObjCMethodList)(uint64_t imageOffsetToFixup, bool& stop)) const;
361 void forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
362 void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const;
363
364 bool forEachBind(void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const;
365
366 static_assert(sizeof(ResolvedSymbolTarget) == 8, "Overflow in size of SymbolTargetLocation");
367
368 static uint32_t hashFunction(const char*);
369
370 private:
371 friend struct Closure;
372 friend class ImageWriter;
373 friend class ClosureBuilder;
374 friend class ClosureWriter;
375 friend class LaunchClosureWriter;
376 friend class RebasePatternBuilder;
377 friend class BindPatternBuilder;
378
379 uint32_t pageSize() const;
380
381 struct Flags
382 {
383 uint64_t imageNum : 16,
384 maxLoadCount : 12,
385 isInvalid : 1, // an error occurred creating the info for this image
386 has16KBpages : 1,
387 is64 : 1,
388 hasObjC : 1,
389 mayHavePlusLoads : 1,
390 isEncrypted : 1, // image is DSMOS or FairPlay encrypted
391 hasWeakDefs : 1,
392 neverUnload : 1,
393 cwdSameAsThis : 1, // dylibs use file system relative paths, cwd must be main's dir
394 isPlatformBinary : 1, // part of OS - can be loaded into LV process
395 isBundle : 1,
396 isDylib : 1,
397 isExecutable : 1,
398 overridableDylib : 1, // only applicable to cached dylibs
399 inDyldCache : 1,
400 hasTerminators : 1,
401 hasReadOnlyData : 1,
402 hasChainedFixups : 1,
403 hasPrecomputedObjC : 1,
404 fixupsNotEncoded : 1,
405 rebasesNotEncoded : 1,
406 hasOverrideImageNum : 1,
407 padding : 14;
408 };
409
410 static_assert(sizeof(Flags) == sizeof(uint64_t), "Flags overflow");
411
412 const Flags& getFlags() const;
413
414 struct PathAndHash
415 {
416 uint32_t hash;
417 char path[];
418 };
419
420 // In disk based images, all segments are multiples of page size
421 // This struct just tracks the size (disk and vm) of each segment.
422 // This is compact for most every image which have contiguous segments.
423 // If the image does not have contiguous segments (rare), an extra
424 // DiskSegment is inserted with the paddingNotSeg bit set.
425 struct DiskSegment
426 {
427 uint64_t filePageCount : 30,
428 vmPageCount : 30,
429 permissions : 3,
430 paddingNotSeg : 1;
431
432 // We only have three bits for permissions, and need a way to
433 // encode segments that are initially r/w then made read-only
434 // after fixups are done. Previously, the only valid patterns
435 // were: ---, r--, rw-, r-x. We now add -w- to mean r/w -> r/o.
436 enum { kReadOnlyDataPermissions = VM_PROT_WRITE };
437 };
438
439
440 // In cache DATA_DIRTY is not page aligned or sized
441 // This struct allows segments with any alignment and up to 256MB in size
442 struct DyldCacheSegment
443 {
444 uint64_t cacheOffset : 32,
445 size : 28,
446 permissions : 4;
447 };
448
449 struct CodeSignatureLocation
450 {
451 uint32_t fileOffset;
452 uint32_t fileSize;
453 };
454
455 struct FileInfo
456 {
457 uint64_t inode;
458 uint64_t modTime;
459 };
460
461 struct FairPlayRange
462 {
463 uint32_t rangeStart; // The byte offset of the start of the range.
464 uint32_t rangeLength; // How long is the fairplay range in bytes
465 };
466
467 struct MappingInfo
468 {
469 uint32_t totalVmPages;
470 uint32_t sliceOffsetIn4K;
471 };
472
473 struct InitializerSectionRange
474 {
475 uint32_t sectionOffset;
476 uint32_t sectionSize;
477 };
478
479 struct LinkedImage {
480
481 LinkedImage() : imgNum(0), linkKind(0) {
482 }
483 LinkedImage(LinkKind k, ImageNum num) : imgNum(num), linkKind((uint32_t)k) {
484 assert((num & 0xC0000000) == 0);
485 }
486
487 LinkKind kind() const { return (LinkKind)linkKind; }
488 ImageNum imageNum() const { return imgNum; }
489 void clearKind() { linkKind = 0; }
490
491 bool operator==(const LinkedImage& rhs) const {
492 return (linkKind == rhs.linkKind) && (imgNum == rhs.imgNum);
493 }
494 bool operator!=(const LinkedImage& rhs) const {
495 return (linkKind != rhs.linkKind) || (imgNum != rhs.imgNum);
496 }
497 private:
498 uint32_t imgNum : 30,
499 linkKind : 2; // LinkKind
500 };
501
502 const Array<LinkedImage> dependentsArray() const;
503
504 struct RebasePattern
505 {
506 uint32_t repeatCount : 20,
507 contigCount : 8, // how many contiguous pointers neeed rebasing
508 skipCount : 4; // how many pointers to skip between contig groups
509 // If contigCount == 0, then there are no rebases for this entry,
510 // instead it advances the rebase location by repeatCount*skipCount.
511 // If all fields are zero, then the rebase position is reset to the start.
512 // This is to support old binaries with some non-monotonically-increasing rebases.
513 };
514 const Array<RebasePattern> rebaseFixups() const;
515
516 struct BindPattern
517 {
518 Image::ResolvedSymbolTarget target;
519 uint64_t startVmOffset : 40, // max 1TB offset
520 skipCount : 8,
521 repeatCount : 16;
522 };
523 const Array<BindPattern> bindFixups() const;
524
525 // An optimzied selector reference bind will either point to the shared cache
526 // or a binary optimized in our launch closure. We can use the index in to each
527 // of their respective selector hash tables as the target or the bind.
528 union SelectorReferenceFixup
529 {
530 uint32_t chainStartVMOffset;
531 struct {
532 uint32_t index : 24, // max 16m entries in the table
533 next : 7, // (next * 4) -> offset to next fixup
534 inSharedCache : 1; // 0 -> in the closure. 1 -> in the cache
535 } chainEntry;
536 };
537
538 struct ProtocolISAFixup
539 {
540 uint64_t startVmOffset : 40, // max 1TB offset
541 skipCount : 8,
542 repeatCount : 16;
543 };
544
545 struct ClassStableSwiftFixup
546 {
547 uint64_t startVmOffset : 40, // max 1TB offset
548 skipCount : 8,
549 repeatCount : 16;
550 };
551
552 struct MethodListFixup
553 {
554 uint64_t startVmOffset : 40, // max 1TB offset
555 skipCount : 8,
556 repeatCount : 16;
557 };
558
559 void objcFixups(ResolvedSymbolTarget& objcProtocolClassTarget,
560 uint64_t& objcImageInfoVMOffset,
561 Array<ProtocolISAFixup>& protocolISAFixups,
562 Array<SelectorReferenceFixup>& selRefFixups,
563 Array<ClassStableSwiftFixup>& classStableSwiftFixups,
564 Array<MethodListFixup>& methodListFixups) const;
565
566 struct TextFixupPattern
567 {
568 Image::ResolvedSymbolTarget target;
569 uint32_t startVmOffset;
570 uint16_t repeatCount;
571 uint16_t skipCount;
572 };
573 const Array<TextFixupPattern> textFixups() const;
574
575 // for use with chained fixups
576 uint64_t chainedStartsOffset() const;
577 const Array<Image::ResolvedSymbolTarget> chainedTargets() const;
578
579 };
580
581 /*
582 Dyld cache patching notes:
583
584 The dyld cache needs to be patched to support interposing and dylib "roots".
585
586 For cached dylibs overrides:
587 Closure build time:
588 1) LoadedImages will contain the new dylib, so all symbol look ups
589 will naturally find new impl. Only dyld cache needs special help.
590 2) LoadedImages entry will have flag for images that override cache.
591 3) When setting Closure attributes, if flag is set, builder will
592 iterate PatchableExport entries in Image* from cache and create
593 a PatchEntry for each.
594 Runtime:
595 1) [lib]dyld will iterate PatchEntry in closure and patch cache
596
597 For interposing:
598 Closure build time:
599 1) After Images built, if __interpose section(s) exist, builder will
600 build InterposingTuple entries for closure
601 2) For being-built closure and launch closure, apply any InterposingTuple
602 to modify Image fixups before Image finalized.
603 3) Builder will find PatchableExport entry that matchs stock Impl
604 and add PatchEntry to closure for it.
605 Runtime:
606 1) When closure is loaded (launch or dlopen) PatchEntries are
607 applied (exactly once) to whole cache.
608 2) For each DlopenClosure loaded, any InterposeTuples in *launch* closure
609 are applied to all new images in new DlopenClosure.
610
611 For weak-def coalesing:
612 Closure build time:
613 1) weak_bind entries are turned into -3 ordinal lookup which search through images
614 in load order for first def (like flat). This fixups up all images not in cache.
615 2) When processing -3 ordinals, it continues past first found and if any images
616 past it are in dyld cache and export that same symbol, a PatchEntry is added to
617 closure to fix up all cached uses of that symbol.
618 3) If a weak_bind has strong bit set (no fixup, just def), all images from the dyld
619 cache are checked to see if the export that symbol, if so, a PatchEntry is added
620 to the closure.
621 Runtime:
622 1) When closure is loaded (launch or dlopen) PatchEntries are
623 applied (exactly once) to whole cache.
624
625 */
626
627
628 //
629 // An array (accessible by index) list of Images
630 //
631 struct VIS_HIDDEN ImageArray : public TypedBytes
632 {
633 size_t size() const;
634 size_t startImageNum() const;
635 uint32_t imageCount() const;
636 void forEachImage(void (^callback)(const Image* image, bool& stop)) const;
637 bool hasPath(const char* path, ImageNum& num) const;
638 const Image* imageForNum(ImageNum) const;
639 void deallocate() const;
640
641 static const Image* findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum);
642
643 private:
644 friend class ImageArrayWriter;
645
646 uint32_t firstImageNum;
647 uint32_t count : 31;
648 uint32_t hasRoots : 1; // True if this ImageArray contains roots with imageNum's below firstImageNum
649 uint32_t offsets[];
650 // Image data
651 };
652
653
654 struct InterposingTuple
655 {
656 Image::ResolvedSymbolTarget stockImplementation;
657 Image::ResolvedSymbolTarget newImplementation;
658 };
659
660
661 //
662 // Describes how dyld should load a set of mach-o files
663 //
664 struct VIS_HIDDEN Closure : public ContainerTypedBytes
665 {
666 size_t size() const;
667 const ImageArray* images() const;
668 ImageNum topImageNum() const;
669 const Image* topImage() const;
670 void deallocate() const;
671
672 friend class ClosureWriter;
673
674 struct PatchEntry
675 {
676 ImageNum overriddenDylibInCache;
677 uint32_t exportCacheOffset;
678 Image::ResolvedSymbolTarget replacement;
679 };
680
681 struct Warning
682 {
683 enum Type : uint32_t {
684 duplicateObjCClass = 0
685 };
686
687 Type type;
688 char message[];
689 };
690
691 void forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const;
692 void forEachWarning(Warning::Type type, void (^handler)(const char* warning, bool& stop)) const;
693 };
694
695
696 //
697 // Describes how dyld should launch a main executable
698 //
699 struct VIS_HIDDEN LaunchClosure : public Closure
700 {
701 // Represents a file on disk we tried to load but skipped as it wasn't valid for our use
702 struct SkippedFile
703 {
704 const char* path;
705 uint64_t inode;
706 uint64_t mtime;
707 };
708
709 bool builtAgainstDyldCache(uuid_t cacheUUID) const;
710 void forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const;
711 void forEachSkipIfExistsFile(void (^handler)(const SkippedFile& file, bool& stop)) const;
712 void forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const;
713 ImageNum libSystemImageNum() const;
714 void libDyldEntry(Image::ResolvedSymbolTarget& loc) const;
715 bool mainEntry(Image::ResolvedSymbolTarget& mainLoc) const;
716 bool startEntry(Image::ResolvedSymbolTarget& startLoc) const;
717 uint32_t initialLoadCount() const;
718 void forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const;
719 bool usedAtPaths() const;
720 bool usedFallbackPaths() const;
721 bool usedInterposing() const;
722 bool selectorHashTable(Array<Image::ObjCSelectorImage>& imageNums,
723 const ObjCSelectorOpt*& hashTable) const;
724 bool classAndProtocolHashTables(Array<Image::ObjCClassImage>& imageNums,
725 const ObjCClassOpt*& classHashTable,
726 const ObjCClassOpt*& protocolHashTable) const;
727 void duplicateClassesHashTable(const ObjCClassDuplicatesOpt*& duplicateClassesHashTable) const;
728 bool hasInsertedLibraries() const;
729 bool hasInterposings() const;
730 bool hasProgramVars(uint32_t& runtimeOffset) const;
731
732 static bool buildClosureCachePath(const char* mainExecutablePath, const char* envp[],
733 bool makeDirsIfMissing, char closurePath[]);
734
735 private:
736 friend class LaunchClosureWriter;
737
738 struct Flags
739 {
740 uint32_t usedAtPaths : 1,
741 usedFallbackPaths : 1,
742 initImageCount : 16,
743 hasInsertedLibraries : 1,
744 hasProgVars : 1,
745 usedInterposing : 1,
746 padding : 11;
747 };
748 const Flags& getFlags() const;
749 };
750
751
752
753 //
754 // Describes how dyld should dlopen() a mach-o file
755 //
756 struct VIS_HIDDEN DlopenClosure : public Closure
757 {
758
759 };
760
761 // Precomputed perfect hash table of strings.
762 // Base class for closure precomputed selector table and class table.
763 class VIS_HIDDEN ObjCStringTable {
764 public:
765 typedef uint32_t StringTarget;
766
767 private:
768 typedef uint8_t StringHashCheckByte;
769
770 protected:
771
772 uint32_t capacity;
773 uint32_t occupied;
774 uint32_t shift;
775 uint32_t mask;
776 StringTarget sentinelTarget;
777 uint32_t roundedTabSize;
778 uint64_t salt;
779
780 uint32_t scramble[256];
781 uint8_t tab[0]; /* tab[mask+1] (always power-of-2). Rounded up to roundedTabSize */
782 // uint8_t checkbytes[capacity]; /* check byte for each string */
783 // int32_t offsets[capacity]; /* offsets from &capacity to cstrings */
784
785 StringHashCheckByte* checkBytesOffset() {
786 return &tab[roundedTabSize];
787 }
788
789 const StringHashCheckByte* checkBytesOffset() const {
790 return &tab[roundedTabSize];
791 }
792
793 StringTarget* targetsOffset() {
794 return (StringTarget*)(checkBytesOffset() + capacity);
795 }
796
797 const StringTarget* targetsOffset() const {
798 return (StringTarget*)(checkBytesOffset() + capacity);
799 }
800
801 dyld3::Array<StringHashCheckByte> checkBytes() {
802 return dyld3::Array<StringHashCheckByte>((StringHashCheckByte *)checkBytesOffset(), capacity, capacity);
803 }
804 const dyld3::Array<StringHashCheckByte> checkBytes() const {
805 return dyld3::Array<StringHashCheckByte>((StringHashCheckByte *)checkBytesOffset(), capacity, capacity);
806 }
807
808 dyld3::Array<StringTarget> targets() {
809 return dyld3::Array<StringTarget>((StringTarget *)targetsOffset(), capacity, capacity);
810 }
811 const dyld3::Array<StringTarget> targets() const {
812 return dyld3::Array<StringTarget>((StringTarget *)targetsOffset(), capacity, capacity);
813 }
814
815 uint32_t hash(const char *key, size_t keylen) const;
816
817 uint32_t hash(const char *key) const
818 {
819 return hash(key, strlen(key));
820 }
821
822 // The check bytes areused to reject strings that aren't in the table
823 // without paging in the table's cstring data. This checkbyte calculation
824 // catches 4785/4815 rejects when launching Safari; a perfect checkbyte
825 // would catch 4796/4815.
826 StringHashCheckByte checkbyte(const char *key, size_t keylen) const
827 {
828 return ((key[0] & 0x7) << 5) | ((uint8_t)keylen & 0x1f);
829 }
830
831 StringHashCheckByte checkbyte(const char *key) const
832 {
833 return checkbyte(key, strlen(key));
834 }
835
836 StringTarget getPotentialTarget(const char *key) const
837 {
838 uint32_t index = getIndex(key);
839 if (index == indexNotFound)
840 return sentinelTarget;
841 return targets()[index];
842
843 }
844
845 public:
846
847 enum : uint32_t {
848 indexNotFound = ~0U
849 };
850
851 uint32_t getIndex(const char *key) const
852 {
853 size_t keylen = strlen(key);
854 uint32_t h = hash(key, keylen);
855
856 // Use check byte to reject without paging in the table's cstrings
857 StringHashCheckByte h_check = checkBytes()[h];
858 StringHashCheckByte key_check = checkbyte(key, keylen);
859 if (h_check != key_check)
860 return indexNotFound;
861 return h;
862 }
863
864 template<typename PerfectHashT>
865 static size_t size(const PerfectHashT& phash) {
866 // Round tab[] to at least 4 in length to ensure the uint32_t's after are aligned
867 uint32_t roundedTabSize = std::max(phash.mask+1, 4U);
868 size_t tableSize = 0;
869 tableSize += sizeof(ObjCStringTable);
870 tableSize += roundedTabSize;
871 tableSize += phash.capacity * sizeof(StringHashCheckByte);
872 tableSize += phash.capacity * sizeof(StringTarget);
873 return tableSize;
874 }
875
876 // Get a string if it has an entry in the table
877 const char* getString(const char* selName, const Array<uintptr_t>& baseAddresses) const;
878
879 void forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
880 void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const;
881
882 template<typename PerfectHashT, typename ImageOffsetT>
883 void write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings);
884 };
885
886 class VIS_HIDDEN ObjCSelectorOpt : public ObjCStringTable {
887 public:
888 // Get a string if it has an entry in the table
889 // Returns true if an entry is found and sets the imageNum and vmOffset.
890 bool getStringLocation(uint32_t index, const Array<closure::Image::ObjCSelectorImage>& selImages,
891 ImageNum& imageNum, uint64_t& vmOffset) const;
892
893 void forEachString(const Array<Image::ObjCSelectorImage>& selectorImages,
894 void (^callback)(uint64_t selVMOffset, ImageNum imageNum)) const;
895 };
896
897 class VIS_HIDDEN ObjCClassOpt : public ObjCStringTable {
898 private:
899 // ...ObjCStringTable fields...
900 // ClassTarget classOffsets[capacity]; /* offsets from &capacity to class_t and header_info */
901 // DuplicateCount duplicateCount;
902 // ClassTarget duplicateOffsets[duplicatedClasses];
903
904 typedef uint32_t DuplicateCount;
905 typedef Image::ObjCClassImageOffset ClassTarget;
906
907 ClassTarget *classOffsetsStart() { return (ClassTarget *)&targetsOffset()[capacity]; }
908 const ClassTarget *classOffsetsStart() const { return (const ClassTarget *)&targetsOffset()[capacity]; }
909
910 dyld3::Array<ClassTarget> classOffsets() {
911 return dyld3::Array<ClassTarget>((ClassTarget *)classOffsetsStart(), capacity, capacity);
912 }
913 const dyld3::Array<ClassTarget> classOffsets() const {
914 return dyld3::Array<ClassTarget>((ClassTarget *)classOffsetsStart(), capacity, capacity);
915 }
916
917 DuplicateCount& duplicateCount() { return *(DuplicateCount *)&classOffsetsStart()[capacity]; }
918 const DuplicateCount& duplicateCount() const { return *(const DuplicateCount *)&classOffsetsStart()[capacity]; }
919
920 ClassTarget *duplicateOffsetsStart() { return (ClassTarget *)(&duplicateCount()+1); }
921 const ClassTarget *duplicateOffsetsStart() const { return (const ClassTarget *)(&duplicateCount()+1); }
922
923 dyld3::Array<ClassTarget> duplicateOffsets(uint32_t preCalculatedDuplicateCount) {
924 return dyld3::Array<ClassTarget>((ClassTarget *)duplicateOffsetsStart(), preCalculatedDuplicateCount, duplicateCount());
925 }
926 const dyld3::Array<ClassTarget> duplicateOffsets(uint32_t preCalculatedDuplicateCount) const {
927 return dyld3::Array<ClassTarget>((ClassTarget *)duplicateOffsetsStart(), preCalculatedDuplicateCount, duplicateCount());
928 }
929
930 public:
931
932 template<typename PerfectHashT>
933 static size_t size(PerfectHashT& phash, uint32_t duplicateCount)
934 {
935 size_t tableSize = 0;
936 tableSize += ObjCStringTable::size(phash);
937 tableSize += phash.capacity * sizeof(ClassTarget);
938 tableSize += sizeof(DuplicateCount);
939 tableSize += duplicateCount * sizeof(ClassTarget);
940 return tableSize;
941 }
942
943 void forEachClass(const char* className,
944 const Array<std::pair<uintptr_t, uintptr_t>>& nameAndDataBaseAddresses,
945 void (^callback)(void* classPtr, bool isLoaded, bool* stop)) const;
946
947 void forEachClass(const Array<Image::ObjCClassImage>& classImages,
948 void (^nameCallback)(uint64_t classNameVMOffset, ImageNum imageNum),
949 void (^implCallback)(uint64_t classVMOffset, ImageNum imageNum)) const;
950
951 template<typename PerfectHashT, typename ImageOffsetT, typename ClassesMapT>
952 void write(const PerfectHashT& phash, const Array<std::pair<const char*, ImageOffsetT>>& strings,
953 const ClassesMapT& classes, uint32_t preCalculatedDuplicateCount);
954 };
955
956 class VIS_HIDDEN ObjCClassDuplicatesOpt : public ObjCStringTable {
957 public:
958 // Get a class if it has an entry in the table
959 bool getClassLocation(const char* className, const objc_opt::objc_opt_t* objCOpt, void*& classImpl) const;
960
961 void forEachClass(void (^callback)(Image::ObjCDuplicateClass duplicateClass)) const;
962 };
963
964 } // namespace closure
965 } // namespace dyld3
966
967
968 #endif // Closures_h
969
970