dyld-655.1.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 <stdio.h>
31 #include <assert.h>
32 #include <uuid/uuid.h>
33 #include <mach/mach.h>
34 #include <mach-o/loader.h>
35
36 #include "Diagnostics.h"
37 #include "Array.h"
38 #include "MachOLoaded.h"
39 #include "SupportedArchs.h"
40
41 namespace dyld3 {
42 namespace closure {
43
44
45
46 // bump this number each time binary format changes
47 enum { kFormatVersion = 10 };
48
49
50 typedef uint32_t ImageNum;
51
52 const ImageNum kFirstDyldCacheImageNum = 0x00000001;
53 const ImageNum kLastDyldCacheImageNum = 0x00000FFF;
54 const ImageNum kFirstOtherOSImageNum = 0x00001001;
55 const ImageNum kLastOtherOSImageNum = 0x00001FFF;
56 const ImageNum kFirstLaunchClosureImageNum = 0x00002000;
57 const ImageNum kMissingWeakLinkedImage = 0x0FFFFFFF;
58
59
60 //
61 // Generic typed range of bytes (similar to load commands)
62 // Must be 4-byte aligned
63 //
64 struct VIS_HIDDEN TypedBytes
65 {
66 uint32_t type : 8,
67 payloadLength : 24;
68
69 enum class Type {
70 // containers which have an overall length and TypedBytes inside their content
71 launchClosure = 1, // contains TypedBytes of closure attributes including imageArray
72 imageArray = 2, // sizeof(ImageArray) + sizeof(uint32_t)*count + size of all images
73 image = 3, // contains TypedBytes of image attributes
74 dlopenClosure = 4, // contains TypedBytes of closure attributes including imageArray
75
76 // attributes for Images
77 imageFlags = 7, // sizeof(Image::Flags)
78 pathWithHash = 8, // len = uint32_t + length path + 1, use multiple entries for aliases
79 fileInodeAndTime = 9, // sizeof(FileInfo)
80 cdHash = 10, // 20
81 uuid = 11, // 16
82 mappingInfo = 12, // sizeof(MappingInfo)
83 diskSegment = 13, // sizeof(DiskSegment) * count
84 cacheSegment = 14, // sizeof(DyldCacheSegment) * count
85 dependents = 15, // sizeof(LinkedImage) * count
86 initOffsets = 16, // sizeof(uint32_t) * count
87 dofOffsets = 17, // sizeof(uint32_t) * count
88 codeSignLoc = 18, // sizeof(CodeSignatureLocation)
89 fairPlayLoc = 19, // sizeof(FairPlayRange)
90 rebaseFixups = 20, // sizeof(RebasePattern) * count
91 bindFixups = 21, // sizeof(BindPattern) * count
92 cachePatchInfo = 22, // sizeof(PatchableExport) + count*sizeof(PatchLocation) + strlen(name) // only in dyld cache Images
93 textFixups = 23, // sizeof(TextFixupPattern) * count
94 imageOverride = 24, // sizeof(ImageNum)
95 initBefores = 25, // sizeof(ImageNum) * count
96 chainedFixupsStarts = 26, // sizeof(uint64_t) * count
97 chainedFixupsTargets = 27, // sizeof(ResolvedSymbolTarget) * count
98
99 // attributes for Closures (launch or dlopen)
100 closureFlags = 32, // sizeof(Closure::Flags)
101 dyldCacheUUID = 33, // 16
102 missingFiles = 34,
103 envVar = 35, // "DYLD_BLAH=stuff"
104 topImage = 36, // sizeof(ImageNum)
105 libDyldEntry = 37, // sizeof(ResolvedSymbolTarget)
106 libSystemNum = 38, // sizeof(ImageNum)
107 bootUUID = 39, // c-string 40
108 mainEntry = 40, // sizeof(ResolvedSymbolTarget)
109 startEntry = 41, // sizeof(ResolvedSymbolTarget) // used by programs built with crt1.o
110 cacheOverrides = 42, // sizeof(PatchEntry) * count // used if process uses interposing or roots (cached dylib overrides)
111 interposeTuples = 43, // sizeof(InterposingTuple) * count
112 };
113
114 const void* payload() const;
115 void* payload();
116 };
117
118
119 //
120 // A TypedBytes which is a bag of other TypedBytes
121 //
122 struct VIS_HIDDEN ContainerTypedBytes : TypedBytes
123 {
124 void forEachAttribute(void (^callback)(const TypedBytes* typedBytes, bool& stop)) const;
125 void forEachAttributePayload(Type requestedType, void (^handler)(const void* payload, uint32_t size, bool& stop)) const;
126 const void* findAttributePayload(Type requestedType, uint32_t* payloadSize=nullptr) const;
127 private:
128 const TypedBytes* first() const;
129 const TypedBytes* next(const TypedBytes*) const;
130 };
131
132
133 //
134 // Information about a mach-o file
135 //
136 struct VIS_HIDDEN Image : ContainerTypedBytes
137 {
138 enum class LinkKind { regular=0, weak=1, upward=2, reExport=3 };
139
140 size_t size() const;
141 ImageNum imageNum() const;
142 bool representsImageNum(ImageNum num) const; // imageNum() or isOverrideOfDyldCacheImage()
143 uint32_t maxLoadCount() const;
144 const char* path() const;
145 const char* leafName() const;
146 bool getUuid(uuid_t) const;
147 bool isInvalid() const;
148 bool inDyldCache() const;
149 bool hasObjC() const;
150 bool hasInitializers() const;
151 bool isBundle() const;
152 bool isDylib() const;
153 bool isExecutable() const;
154 bool hasWeakDefs() const;
155 bool mayHavePlusLoads() const;
156 bool is64() const;
157 bool neverUnload() const;
158 bool cwdMustBeThisDir() const;
159 bool isPlatformBinary() const;
160 bool overridableDylib() const;
161 bool hasFileModTimeAndInode(uint64_t& inode, uint64_t& mTime) const;
162 bool hasCdHash(uint8_t cdHash[20]) const;
163 void forEachAlias(void (^handler)(const char* aliasPath, bool& stop)) const;
164 void forEachDependentImage(void (^handler)(uint32_t dependentIndex, LinkKind kind, ImageNum imageNum, bool& stop)) const;
165 ImageNum dependentImageNum(uint32_t depIndex) const;
166 bool containsAddress(const void* addr, const void* imageLoadAddress, uint8_t* permissions=nullptr) const;
167 void forEachInitializer(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
168 void forEachImageToInitBefore(void (^handler)(ImageNum imageToInit, bool& stop)) const;
169 void forEachDOF(const void* imageLoadAddress, void (^handler)(const void* initializer)) const;
170 bool hasPathWithHash(const char* path, uint32_t hash) const;
171 bool isOverrideOfDyldCacheImage(ImageNum& cacheImageNum) const;
172 uint64_t textSize() const;
173
174 union ResolvedSymbolTarget
175 {
176 enum Kinds { kindRebase, kindSharedCache, kindImage, kindAbsolute };
177
178 struct Rebase {
179 uint64_t kind : 2, // kindRebase
180 unused : 62; // all zeros
181 };
182 struct SharedCache {
183 uint64_t kind : 2, // kindSharedCache
184 offset : 62;
185 };
186 struct Image {
187 uint64_t kind : 2, // kindImage
188 imageNum : 22, // ImageNum
189 offset : 40;
190 };
191 struct Absolute {
192 uint64_t kind : 2, // kindAbsolute
193 value : 62; // sign extended
194 };
195 Rebase rebase;
196 SharedCache sharedCache;
197 Image image;
198 Absolute absolute;
199 uint64_t raw;
200
201 bool operator==(const ResolvedSymbolTarget& rhs) const {
202 return (raw == rhs.raw);
203 }
204 bool operator!=(const ResolvedSymbolTarget& rhs) const {
205 return (raw != rhs.raw);
206 }
207 };
208
209 typedef MachOLoaded::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
210
211 // the following are only valid if inDyldCache() returns true
212 uint32_t cacheOffset() const;
213 uint32_t patchStartIndex() const;
214 uint32_t patchCount() const;
215 void forEachCacheSegment(void (^handler)(uint32_t segIndex, uint64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
216
217
218 // the following are only valid if inDyldCache() returns false
219 uint64_t vmSizeToMap() const;
220 uint64_t sliceOffsetInFile() const;
221 bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
222 bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const;
223 void forEachDiskSegment(void (^handler)(uint32_t segIndex, uint32_t fileOffset, uint32_t fileSize, int64_t vmOffset, uint64_t vmSize, uint8_t permissions, bool& stop)) const;
224 void forEachFixup(void (^rebase)(uint64_t imageOffsetToRebase, bool& stop),
225 void (^bind)(uint64_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop),
226 void (^chainedFixupStart)(uint64_t imageOffsetStart, const Array<ResolvedSymbolTarget>& targets, bool& stop)) const;
227 void forEachTextReloc(void (^rebase)(uint32_t imageOffsetToRebase, bool& stop),
228 void (^bind)(uint32_t imageOffsetToBind, ResolvedSymbolTarget bindTarget, bool& stop)) const;
229 static void forEachChainedFixup(void* imageLoadAddress, uint64_t imageOffsetChainStart,
230 void (^chainedFixupStart)(uint64_t* fixupLoc, ChainedFixupPointerOnDisk fixupInfo, bool& stop));
231
232 static_assert(sizeof(ResolvedSymbolTarget) == 8, "Overflow in size of SymbolTargetLocation");
233
234 static uint32_t hashFunction(const char*);
235
236
237 // only in Image for cached dylibs
238 struct PatchableExport
239 {
240 struct PatchLocation
241 {
242 uint64_t cacheOffset : 32,
243 addend : 12, // +/- 2048
244 authenticated : 1,
245 usesAddressDiversity : 1,
246 key : 2,
247 discriminator : 16;
248
249 PatchLocation(size_t cacheOffset, uint64_t addend);
250 PatchLocation(size_t cacheOffset, uint64_t addend, dyld3::MachOLoaded::ChainedFixupPointerOnDisk authInfo);
251
252 uint64_t getAddend() const {
253 uint64_t unsingedAddend = addend;
254 int64_t signedAddend = (int64_t)unsingedAddend;
255 signedAddend = (signedAddend << 52) >> 52;
256 return (uint64_t)signedAddend;
257 }
258
259 const char* keyName() const;
260 bool operator==(const PatchLocation& other) const {
261 return this->cacheOffset == other.cacheOffset;
262 }
263 };
264
265 uint32_t cacheOffsetOfImpl;
266 uint32_t patchLocationsCount;
267 PatchLocation patchLocations[];
268 // export name
269 };
270 uint32_t patchableExportCount() const;
271 void forEachPatchableExport(void (^handler)(uint32_t cacheOffsetOfImpl, const char* exportName)) const;
272 void forEachPatchableUseOfExport(uint32_t cacheOffsetOfImpl, void (^handler)(PatchableExport::PatchLocation patchLocation)) const;
273
274 private:
275 friend struct Closure;
276 friend class ImageWriter;
277 friend class ClosureBuilder;
278 friend class LaunchClosureWriter;
279
280 uint32_t pageSize() const;
281
282 struct Flags
283 {
284 uint64_t imageNum : 16,
285 maxLoadCount : 12,
286 isInvalid : 1, // an error occurred creating the info for this image
287 has16KBpages : 1,
288 is64 : 1,
289 hasObjC : 1,
290 mayHavePlusLoads : 1,
291 isEncrypted : 1, // image is DSMOS or FairPlay encrypted
292 hasWeakDefs : 1,
293 neverUnload : 1,
294 cwdSameAsThis : 1, // dylibs use file system relative paths, cwd must be main's dir
295 isPlatformBinary : 1, // part of OS - can be loaded into LV process
296 isBundle : 1,
297 isDylib : 1,
298 isExecutable : 1,
299 overridableDylib : 1, // only applicable to cached dylibs
300 inDyldCache : 1,
301 padding : 21;
302 };
303
304 const Flags& getFlags() const;
305
306 struct PathAndHash
307 {
308 uint32_t hash;
309 char path[];
310 };
311
312 // In disk based images, all segments are multiples of page size
313 // This struct just tracks the size (disk and vm) of each segment.
314 // This is compact for most every image which have contiguous segments.
315 // If the image does not have contiguous segments (rare), an extra
316 // DiskSegment is inserted with the paddingNotSeg bit set.
317 struct DiskSegment
318 {
319 uint64_t filePageCount : 30,
320 vmPageCount : 30,
321 permissions : 3,
322 paddingNotSeg : 1;
323 };
324
325
326 // In cache DATA_DIRTY is not page aligned or sized
327 // This struct allows segments with any alignment and up to 256MB in size
328 struct DyldCacheSegment
329 {
330 uint64_t cacheOffset : 32,
331 size : 28,
332 permissions : 4;
333 };
334
335 struct CodeSignatureLocation
336 {
337 uint32_t fileOffset;
338 uint32_t fileSize;
339 };
340
341 struct FileInfo
342 {
343 uint64_t inode;
344 uint64_t modTime;
345 };
346
347 struct FairPlayRange
348 {
349 uint32_t textPageCount : 28,
350 textStartPage : 4;
351 };
352
353 struct MappingInfo
354 {
355 uint32_t totalVmPages;
356 uint32_t sliceOffsetIn4K;
357 };
358
359 struct LinkedImage {
360
361 LinkedImage() : imgNum(0), linkKind(0) {
362 }
363 LinkedImage(LinkKind k, ImageNum num) : imgNum(num), linkKind((uint32_t)k) {
364 assert((num & 0xC0000000) == 0);
365 }
366
367 LinkKind kind() const { return (LinkKind)linkKind; }
368 ImageNum imageNum() const { return imgNum; }
369 void clearKind() { linkKind = 0; }
370
371 bool operator==(const LinkedImage& rhs) const {
372 return (linkKind == rhs.linkKind) && (imgNum == rhs.imgNum);
373 }
374 bool operator!=(const LinkedImage& rhs) const {
375 return (linkKind != rhs.linkKind) || (imgNum != rhs.imgNum);
376 }
377 private:
378 uint32_t imgNum : 30,
379 linkKind : 2; // LinkKind
380 };
381
382 const Array<LinkedImage> dependentsArray() const;
383
384 struct RebasePattern
385 {
386 uint32_t repeatCount : 20,
387 contigCount : 8, // how many contiguous pointers neeed rebasing
388 skipCount : 4; // how many pointers to skip between contig groups
389 // If contigCount == 0, then there are no rebases for this entry,
390 // instead it advances the rebase location by repeatCount*skipCount.
391 // If all fields are zero, then the rebase position is reset to the start.
392 // This is to support old binaries with some non-monotonically-increasing rebases.
393 };
394 const Array<RebasePattern> rebaseFixups() const;
395
396 struct BindPattern
397 {
398 Image::ResolvedSymbolTarget target;
399 uint64_t startVmOffset : 40, // max 1TB offset
400 skipCount : 8,
401 repeatCount : 16;
402 };
403 const Array<BindPattern> bindFixups() const;
404
405 struct TextFixupPattern
406 {
407 Image::ResolvedSymbolTarget target;
408 uint32_t startVmOffset;
409 uint16_t repeatCount;
410 uint16_t skipCount;
411 };
412 const Array<TextFixupPattern> textFixups() const;
413
414 // for use with chained fixups
415 const Array<uint64_t> chainedStarts() const;
416 const Array<Image::ResolvedSymbolTarget> chainedTargets() const;
417
418 };
419
420 /*
421 Dyld cache patching notes:
422
423 The dyld cache needs to be patched to support interposing and dylib "roots".
424
425 For cached dylibs overrides:
426 Closure build time:
427 1) LoadedImages will contain the new dylib, so all symbol look ups
428 will naturally find new impl. Only dyld cache needs special help.
429 2) LoadedImages entry will have flag for images that override cache.
430 3) When setting Closure attributes, if flag is set, builder will
431 iterate PatchableExport entries in Image* from cache and create
432 a PatchEntry for each.
433 Runtime:
434 1) [lib]dyld will iterate PatchEntry in closure and patch cache
435
436 For interposing:
437 Closure build time:
438 1) After Images built, if __interpose section(s) exist, builder will
439 build InterposingTuple entries for closure
440 2) For being-built closure and launch closure, apply any InterposingTuple
441 to modify Image fixups before Image finalized.
442 3) Builder will find PatchableExport entry that matchs stock Impl
443 and add PatchEntry to closure for it.
444 Runtime:
445 1) When closure is loaded (launch or dlopen) PatchEntries are
446 applied (exactly once) to whole cache.
447 2) For each DlopenClosure loaded, any InterposeTuples in *launch* closure
448 are applied to all new images in new DlopenClosure.
449
450 For weak-def coalesing:
451 Closure build time:
452 1) weak_bind entries are turned into -3 ordinal lookup which search through images
453 in load order for first def (like flat). This fixups up all images not in cache.
454 2) When processing -3 ordinals, it continues past first found and if any images
455 past it are in dyld cache and export that same symbol, a PatchEntry is added to
456 closure to fix up all cached uses of that symbol.
457 3) If a weak_bind has strong bit set (no fixup, just def), all images from the dyld
458 cache are checked to see if the export that symbol, if so, a PatchEntry is added
459 to the closure.
460 Runtime:
461 1) When closure is loaded (launch or dlopen) PatchEntries are
462 applied (exactly once) to whole cache.
463
464 */
465
466
467 //
468 // An array (accessible by index) list of Images
469 //
470 struct VIS_HIDDEN ImageArray : public TypedBytes
471 {
472 size_t size() const;
473 size_t startImageNum() const;
474 uint32_t imageCount() const;
475 void forEachImage(void (^callback)(const Image* image, bool& stop)) const;
476 bool hasPath(const char* path, ImageNum& num) const;
477 const Image* imageForNum(ImageNum) const;
478
479 static const Image* findImage(const Array<const ImageArray*> imagesArrays, ImageNum imageNum);
480
481 private:
482 friend class ImageArrayWriter;
483
484 uint32_t firstImageNum;
485 uint32_t count;
486 uint32_t offsets[];
487 // Image data
488 };
489
490
491 struct InterposingTuple
492 {
493 Image::ResolvedSymbolTarget stockImplementation;
494 Image::ResolvedSymbolTarget newImplementation;
495 };
496
497
498 //
499 // Describes how dyld should load a set of mach-o files
500 //
501 struct VIS_HIDDEN Closure : public ContainerTypedBytes
502 {
503 size_t size() const;
504 const ImageArray* images() const;
505 ImageNum topImage() const;
506 void deallocate() const;
507
508 friend class ClosureWriter;
509
510 struct PatchEntry
511 {
512 ImageNum overriddenDylibInCache;
513 uint32_t exportCacheOffset;
514 Image::ResolvedSymbolTarget replacement;
515 };
516 void forEachPatchEntry(void (^handler)(const PatchEntry& entry)) const;
517 };
518
519
520 //
521 // Describes how dyld should launch a main executable
522 //
523 struct VIS_HIDDEN LaunchClosure : public Closure
524 {
525 bool builtAgainstDyldCache(uuid_t cacheUUID) const;
526 const char* bootUUID() const;
527 void forEachMustBeMissingFile(void (^handler)(const char* path, bool& stop)) const;
528 void forEachEnvVar(void (^handler)(const char* keyEqualValue, bool& stop)) const;
529 ImageNum libSystemImageNum() const;
530 void libDyldEntry(Image::ResolvedSymbolTarget& loc) const;
531 bool mainEntry(Image::ResolvedSymbolTarget& mainLoc) const;
532 bool startEntry(Image::ResolvedSymbolTarget& startLoc) const;
533 uint32_t initialLoadCount() const;
534 void forEachInterposingTuple(void (^handler)(const InterposingTuple& tuple, bool& stop)) const;
535 bool usedAtPaths() const;
536 bool usedFallbackPaths() const;
537
538
539 private:
540 friend class LaunchClosureWriter;
541
542 struct Flags
543 {
544 uint32_t usedAtPaths : 1,
545 usedFallbackPaths : 1,
546 initImageCount : 16,
547 padding : 14;
548 };
549 const Flags& getFlags() const;
550 };
551
552
553
554 //
555 // Describes how dyld should dlopen() a mach-o file
556 //
557 struct VIS_HIDDEN DlopenClosure : public Closure
558 {
559
560 };
561
562
563
564 } // namespace closure
565 } // namespace dyld3
566
567
568 #endif // Closures_h
569
570