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@
27 #include <uuid/uuid.h>
30 #include <mach/vm_page_size.h>
32 #include "ClosureWriter.h"
33 #include "MachOFile.h"
40 //////////////////////////// ContainerTypedBytesWriter ////////////////////////////////////////
43 void ContainerTypedBytesWriter::setContainerType(TypedBytes::Type containerType
)
45 assert(_vmAllocationStart
== 0);
46 _vmAllocationSize
= 1024 * 1024;
47 vm_address_t allocationAddr
;
48 ::vm_allocate(mach_task_self(), &allocationAddr
, _vmAllocationSize
, VM_FLAGS_ANYWHERE
);
49 assert(allocationAddr
!= 0);
50 _vmAllocationStart
= (void*)allocationAddr
;
51 _containerTypedBytes
= (TypedBytes
*)_vmAllocationStart
;
52 _containerTypedBytes
->type
= containerType
;
53 _containerTypedBytes
->payloadLength
= 0;
54 _end
= (uint8_t*)_vmAllocationStart
+ sizeof(TypedBytes
);
57 void* ContainerTypedBytesWriter::append(TypedBytes::Type t
, const void* payload
, uint32_t payloadSize
)
59 assert((payloadSize
& 0x3) == 0);
60 if ( (uint8_t*)_end
+ payloadSize
>= (uint8_t*)_vmAllocationStart
+ _vmAllocationSize
) {
61 // if current buffer too small, grow it
62 size_t growth
= _vmAllocationSize
;
63 if ( growth
< payloadSize
)
64 growth
= _vmAllocationSize
*((payloadSize
/_vmAllocationSize
)+1);
65 vm_address_t newAllocationAddr
;
66 size_t newAllocationSize
= _vmAllocationSize
+growth
;
67 ::vm_allocate(mach_task_self(), &newAllocationAddr
, newAllocationSize
, VM_FLAGS_ANYWHERE
);
68 assert(newAllocationAddr
!= 0);
69 size_t currentInUse
= (char*)_end
- (char*)_vmAllocationStart
;
70 memcpy((void*)newAllocationAddr
, _vmAllocationStart
, currentInUse
);
71 ::vm_deallocate(mach_task_self(), (vm_address_t
)_vmAllocationStart
, _vmAllocationSize
);
72 _end
= (void*)(newAllocationAddr
+ currentInUse
);
73 _vmAllocationStart
= (void*)newAllocationAddr
;
74 _containerTypedBytes
= (TypedBytes
*)_vmAllocationStart
;
75 _vmAllocationSize
= newAllocationSize
;
77 assert( (uint8_t*)_end
+ payloadSize
< (uint8_t*)_vmAllocationStart
+ _vmAllocationSize
);
78 TypedBytes
* tb
= (TypedBytes
*)_end
;
80 tb
->payloadLength
= payloadSize
;
81 if ( payload
!= nullptr )
82 ::memcpy(tb
->payload(), payload
, payloadSize
);
83 _end
= (uint8_t*)_end
+ sizeof(TypedBytes
) + payloadSize
;
84 assert((_containerTypedBytes
->payloadLength
+ sizeof(TypedBytes
) + payloadSize
) < (16 * 1024 * 1024));
85 _containerTypedBytes
->payloadLength
+= sizeof(TypedBytes
) + payloadSize
;
89 const void* ContainerTypedBytesWriter::finalizeContainer()
91 // trim vm allocation down to just what is needed
92 uintptr_t bufferStart
= (uintptr_t)_vmAllocationStart
;
93 uintptr_t used
= round_page((uintptr_t)_end
- bufferStart
);
94 if ( used
< _vmAllocationSize
) {
95 uintptr_t deallocStart
= bufferStart
+ used
;
96 ::vm_deallocate(mach_task_self(), deallocStart
, _vmAllocationSize
- used
);
98 _vmAllocationSize
= used
;
100 // mark vm region read-only
101 ::vm_protect(mach_task_self(), bufferStart
, used
, false, VM_PROT_READ
);
102 return (void*)_vmAllocationStart
;
105 const void* ContainerTypedBytesWriter::currentTypedBytes()
107 return (void*)_vmAllocationStart
;
110 void ContainerTypedBytesWriter::deallocate()
112 ::vm_deallocate(mach_task_self(), (long)_vmAllocationStart
, _vmAllocationSize
);
115 //////////////////////////// ImageWriter ////////////////////////////////////////
118 const Image
* ImageWriter::finalize()
120 return (Image
*)finalizeContainer();
123 const Image
* ImageWriter::currentImage()
125 return (Image
*)currentTypedBytes();
128 void ImageWriter::addPath(const char* path
)
130 uint32_t roundedPathLen
= ((uint32_t)strlen(path
) + 1 + 3) & (-4);
131 Image::PathAndHash
* ph
= (Image::PathAndHash
*)append(TypedBytes::Type::pathWithHash
, nullptr, sizeof(Image::PathAndHash
)+roundedPathLen
);
132 ph
->hash
= Image::hashFunction(path
);
133 strcpy(ph
->path
, path
);
136 Image::Flags
& ImageWriter::getFlags()
138 if ( _flagsOffset
== -1 ) {
139 setContainerType(TypedBytes::Type::image
);
141 ::bzero(&flags
, sizeof(flags
));
142 uint8_t* p
= (uint8_t*)append(TypedBytes::Type::imageFlags
, &flags
, sizeof(flags
));
143 _flagsOffset
= (int)(p
- (uint8_t*)currentTypedBytes());
145 return *((Image::Flags
*)((uint8_t*)currentTypedBytes() + _flagsOffset
));
148 void ImageWriter::setImageNum(ImageNum num
)
150 getFlags().imageNum
= num
;
153 void ImageWriter::setHasObjC(bool value
)
155 getFlags().hasObjC
= value
;
158 void ImageWriter::setIs64(bool value
)
160 getFlags().is64
= value
;
163 void ImageWriter::setHasPlusLoads(bool value
)
165 getFlags().mayHavePlusLoads
= value
;
168 void ImageWriter::setIsBundle(bool value
)
170 getFlags().isBundle
= value
;
173 void ImageWriter::setIsDylib(bool value
)
175 getFlags().isDylib
= value
;
178 void ImageWriter::setIsExecutable(bool value
)
180 getFlags().isExecutable
= value
;
183 void ImageWriter::setHasWeakDefs(bool value
)
185 getFlags().hasWeakDefs
= value
;
188 void ImageWriter::setUses16KPages(bool value
)
190 getFlags().has16KBpages
= value
;
193 void ImageWriter::setOverridableDylib(bool value
)
195 getFlags().overridableDylib
= value
;
198 void ImageWriter::setInvalid()
200 getFlags().isInvalid
= true;
203 void ImageWriter::setInDyldCache(bool value
)
205 getFlags().inDyldCache
= value
;
208 void ImageWriter::setHasPrecomputedObjC(bool value
)
210 getFlags().hasPrecomputedObjC
= value
;
213 void ImageWriter::setNeverUnload(bool value
)
215 getFlags().neverUnload
= value
;
218 void ImageWriter::setUUID(const uuid_t uuid
)
220 append(TypedBytes::Type::uuid
, uuid
, sizeof(uuid_t
));
223 void ImageWriter::addCDHash(const uint8_t cdHash
[20])
225 append(TypedBytes::Type::cdHash
, cdHash
, 20);
228 void ImageWriter::setDependents(const Array
<Image::LinkedImage
>& deps
)
230 append(TypedBytes::Type::dependents
, deps
.begin(), (uint32_t)deps
.count()*sizeof(Image::LinkedImage
));
233 void ImageWriter::setDofOffsets(const Array
<uint32_t>& dofSectionOffsets
)
235 append(TypedBytes::Type::dofOffsets
, &dofSectionOffsets
[0], (uint32_t)dofSectionOffsets
.count()*sizeof(uint32_t));
238 void ImageWriter::setInitOffsets(const uint32_t initOffsets
[], uint32_t count
)
240 append(TypedBytes::Type::initOffsets
, initOffsets
, count
*sizeof(uint32_t));
243 void ImageWriter::setTermOffsets(const uint32_t termOffsets
[], uint32_t count
)
245 getFlags().hasTerminators
= true;
246 append(TypedBytes::Type::termOffsets
, termOffsets
, count
*sizeof(uint32_t));
249 void ImageWriter::setInitSectRange(uint32_t sectionOffset
, uint32_t sectionSize
)
251 Image::InitializerSectionRange range
= { sectionOffset
, sectionSize
};
252 append(TypedBytes::Type::initsSection
, &range
, sizeof(Image::InitializerSectionRange
));
255 void ImageWriter::setDiskSegments(const Image::DiskSegment segs
[], uint32_t count
)
257 append(TypedBytes::Type::diskSegment
, segs
, count
*sizeof(Image::DiskSegment
));
258 for (uint32_t i
=0; i
< count
; ++i
) {
259 if ( segs
[i
].permissions
== Image::DiskSegment::kReadOnlyDataPermissions
)
260 getFlags().hasReadOnlyData
= true;
264 void ImageWriter::setCachedSegments(const Image::DyldCacheSegment segs
[], uint32_t count
)
266 append(TypedBytes::Type::cacheSegment
, segs
, count
*sizeof(Image::DyldCacheSegment
));
269 void ImageWriter::setCodeSignatureLocation(uint32_t fileOffset
, uint32_t size
)
271 Image::CodeSignatureLocation loc
;
272 loc
.fileOffset
= fileOffset
;
274 append(TypedBytes::Type::codeSignLoc
, &loc
, sizeof(loc
));
277 void ImageWriter::setFairPlayEncryptionRange(uint32_t fileOffset
, uint32_t size
)
279 Image::FairPlayRange loc
;
280 loc
.rangeStart
= fileOffset
;
281 loc
.rangeLength
= size
;
282 append(TypedBytes::Type::fairPlayLoc
, &loc
, sizeof(loc
));
285 void ImageWriter::setMappingInfo(uint64_t sliceOffset
, uint64_t vmSize
)
287 const uint32_t pageSize
= getFlags().has16KBpages
? 0x4000 : 0x1000;
288 Image::MappingInfo info
;
289 info
.sliceOffsetIn4K
= (uint32_t)(sliceOffset
/ 0x1000);
290 info
.totalVmPages
= (uint32_t)(vmSize
/ pageSize
);
291 append(TypedBytes::Type::mappingInfo
, &info
, sizeof(info
));
294 void ImageWriter::setFileInfo(uint64_t inode
, uint64_t mTime
)
296 Image::FileInfo info
= { inode
, mTime
};
297 append(TypedBytes::Type::fileInodeAndTime
, &info
, sizeof(info
));
300 void ImageWriter::setRebaseInfo(const Array
<Image::RebasePattern
>& fixups
)
302 append(TypedBytes::Type::rebaseFixups
, fixups
.begin(), (uint32_t)fixups
.count()*sizeof(Image::RebasePattern
));
305 void ImageWriter::setTextRebaseInfo(const Array
<Image::TextFixupPattern
>& fixups
)
307 append(TypedBytes::Type::textFixups
, fixups
.begin(), (uint32_t)fixups
.count()*sizeof(Image::TextFixupPattern
));
310 void ImageWriter::setBindInfo(const Array
<Image::BindPattern
>& fixups
)
312 append(TypedBytes::Type::bindFixups
, fixups
.begin(), (uint32_t)fixups
.count()*sizeof(Image::BindPattern
));
315 void ImageWriter::setFixupsNotEncoded()
317 getFlags().fixupsNotEncoded
= true;
320 void ImageWriter::setRebasesNotEncoded()
322 getFlags().rebasesNotEncoded
= true;
325 void ImageWriter::setChainedFixups(uint64_t runtimeStartsStructOffset
, const Array
<Image::ResolvedSymbolTarget
>& targets
)
327 getFlags().hasChainedFixups
= true;
328 append(TypedBytes::Type::chainedStartsOffset
, &runtimeStartsStructOffset
, sizeof(uint64_t));
329 append(TypedBytes::Type::chainedFixupsTargets
, targets
.begin(), (uint32_t)targets
.count()*sizeof(Image::ResolvedSymbolTarget
));
332 void ImageWriter::setObjCFixupInfo(const Image::ResolvedSymbolTarget
& objcProtocolClassTarget
,
333 uint64_t objcImageInfoVMOffset
,
334 const Array
<Image::ProtocolISAFixup
>& protocolISAFixups
,
335 const Array
<Image::SelectorReferenceFixup
>& selRefFixups
,
336 const Array
<Image::ClassStableSwiftFixup
>& classStableSwiftFixups
,
337 const Array
<Image::MethodListFixup
>& methodListFixups
)
339 // The layout here is:
340 // ResolvedSymbolTarget
341 // uint64_t vmOffset to objc_imageinfo
342 // uint32_t protocol count
343 // uint32_t selector reference count
344 // array of ProtocolISAFixup
345 // array of SelectorReferenceFixup
346 // optional uint32_t stable swift fixup count
347 // optional uint32_t method list fixup count
348 // optional array of ClassStableSwiftFixup
349 // optional array of MethodListFixup
351 uint64_t headerSize
= sizeof(Image::ResolvedSymbolTarget
) + sizeof(uint64_t) + (sizeof(uint32_t) * 4);
352 uint64_t protocolsSize
= (sizeof(Image::ProtocolISAFixup
) * protocolISAFixups
.count());
353 uint64_t selRefsSize
= (sizeof(Image::SelectorReferenceFixup
) * selRefFixups
.count());
354 uint64_t stableSwiftSize
= (sizeof(Image::ClassStableSwiftFixup
) * classStableSwiftFixups
.count());
355 uint64_t methodListSize
= (sizeof(Image::MethodListFixup
) * methodListFixups
.count());
357 uint64_t totalSize
= headerSize
+ protocolsSize
+ selRefsSize
+ stableSwiftSize
+ methodListSize
;
358 assert( (totalSize
& 3) == 0);
359 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::objcFixups
, nullptr, (uint32_t)totalSize
);
361 // Set the statically sized data
362 uint32_t protocolFixupCount
= (uint32_t)protocolISAFixups
.count();
363 uint32_t selRefFixupCount
= (uint32_t)selRefFixups
.count();
364 memcpy(buffer
, &objcProtocolClassTarget
, sizeof(Image::ResolvedSymbolTarget
));
365 buffer
+= sizeof(Image::ResolvedSymbolTarget
);
366 memcpy(buffer
, &objcImageInfoVMOffset
, sizeof(uint64_t));
367 buffer
+= sizeof(uint64_t);
368 memcpy(buffer
, &protocolFixupCount
, sizeof(uint32_t));
369 buffer
+= sizeof(uint32_t);
370 memcpy(buffer
, &selRefFixupCount
, sizeof(uint32_t));
371 buffer
+= sizeof(uint32_t);
373 // Set the protocol fixups
374 if ( protocolFixupCount
!= 0 ) {
375 memcpy(buffer
, protocolISAFixups
.begin(), (size_t)protocolsSize
);
376 buffer
+= protocolsSize
;
379 // Set the selector reference fixups
380 if ( selRefFixupCount
!= 0 ) {
381 memcpy(buffer
, selRefFixups
.begin(), (size_t)selRefsSize
);
382 buffer
+= selRefsSize
;
385 // New closures get additional fixups. These are ignored by old dyld's
386 uint32_t stableSwiftFixupCount
= (uint32_t)classStableSwiftFixups
.count();
387 uint32_t methodListFixupCount
= (uint32_t)methodListFixups
.count();
388 memcpy(buffer
, &stableSwiftFixupCount
, sizeof(uint32_t));
389 buffer
+= sizeof(uint32_t);
390 memcpy(buffer
, &methodListFixupCount
, sizeof(uint32_t));
391 buffer
+= sizeof(uint32_t);
393 // Set the stable swift fixups
394 if ( stableSwiftFixupCount
!= 0 ) {
395 memcpy(buffer
, classStableSwiftFixups
.begin(), (size_t)stableSwiftSize
);
396 buffer
+= stableSwiftSize
;
399 // Set the method list fixups
400 if ( methodListFixupCount
!= 0 ) {
401 memcpy(buffer
, methodListFixups
.begin(), (size_t)methodListSize
);
402 buffer
+= methodListSize
;
406 void ImageWriter::setAsOverrideOf(ImageNum imageNum
)
408 uint32_t temp
= imageNum
;
409 append(TypedBytes::Type::imageOverride
, &temp
, sizeof(temp
));
410 getFlags().hasOverrideImageNum
= true;
413 void ImageWriter::setInitsOrder(const ImageNum images
[], uint32_t count
)
415 append(TypedBytes::Type::initBefores
, images
, count
*sizeof(ImageNum
));
419 //////////////////////////// ImageArrayWriter ////////////////////////////////////////
422 ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum
, unsigned count
, bool hasRoots
) : _index(0)
424 setContainerType(TypedBytes::Type::imageArray
);
425 _end
= (void*)((uint8_t*)_end
+ sizeof(ImageArray
) - sizeof(TypedBytes
) + sizeof(uint32_t)*count
);
426 _containerTypedBytes
->payloadLength
= sizeof(ImageArray
) - sizeof(TypedBytes
) + sizeof(uint32_t)*count
;
427 ImageArray
* ia
= (ImageArray
*)_containerTypedBytes
;
428 ia
->firstImageNum
= startImageNum
;
430 ia
->hasRoots
= hasRoots
;
433 void ImageArrayWriter::appendImage(const Image
* image
)
435 ImageArray
* ia
= (ImageArray
*)_containerTypedBytes
;
436 ia
->offsets
[_index
++] = _containerTypedBytes
->payloadLength
;
437 append(TypedBytes::Type::image
, image
->payload(), image
->payloadLength
);
440 const ImageArray
* ImageArrayWriter::finalize()
442 return (ImageArray
*)finalizeContainer();
446 //////////////////////////// ClosureWriter ////////////////////////////////////////
448 void ClosureWriter::setTopImageNum(ImageNum imageNum
)
450 append(TypedBytes::Type::topImage
, &imageNum
, sizeof(ImageNum
));
453 void ClosureWriter::addCachePatches(const Array
<Closure::PatchEntry
>& patches
)
455 append(TypedBytes::Type::cacheOverrides
, patches
.begin(), (uint32_t)patches
.count()*sizeof(Closure::PatchEntry
));
458 void ClosureWriter::applyInterposing(const LaunchClosure
* launchClosure
)
460 const Closure
* currentClosure
= (Closure
*)currentTypedBytes();
461 const ImageArray
* images
= currentClosure
->images();
462 launchClosure
->forEachInterposingTuple(^(const InterposingTuple
& tuple
, bool&) {
463 images
->forEachImage(^(const dyld3::closure::Image
* image
, bool&) {
464 for (const Image::BindPattern
& bindPat
: image
->bindFixups()) {
465 if ( (bindPat
.target
== tuple
.stockImplementation
) && (tuple
.newImplementation
.image
.imageNum
!= image
->imageNum()) ) {
466 Image::BindPattern
* writePat
= const_cast<Image::BindPattern
*>(&bindPat
);
467 writePat
->target
= tuple
.newImplementation
;
471 // Chained fixups may also be interposed. We can't change elements in the chain, but we can change
473 for (const Image::ResolvedSymbolTarget
& symbolTarget
: image
->chainedTargets()) {
474 if ( (symbolTarget
== tuple
.stockImplementation
) && (tuple
.newImplementation
.image
.imageNum
!= image
->imageNum()) ) {
475 Image::ResolvedSymbolTarget
* writeTarget
= const_cast<Image::ResolvedSymbolTarget
*>(&symbolTarget
);
476 *writeTarget
= tuple
.newImplementation
;
483 void ClosureWriter::addWarning(Closure::Warning::Type warningType
, const char* warning
)
485 uint32_t roundedMessageLen
= ((uint32_t)strlen(warning
) + 1 + 3) & (-4);
486 Closure::Warning
* ph
= (Closure::Warning
*)append(TypedBytes::Type::warning
, nullptr, sizeof(Closure::Warning
)+roundedMessageLen
);
487 ph
->type
= warningType
;
488 strcpy(ph
->message
, warning
);
492 //////////////////////////// LaunchClosureWriter ////////////////////////////////////////
494 LaunchClosureWriter::LaunchClosureWriter(const ImageArray
* images
)
496 setContainerType(TypedBytes::Type::launchClosure
);
497 append(TypedBytes::Type::imageArray
, images
->payload(), images
->payloadLength
);
500 const LaunchClosure
* LaunchClosureWriter::finalize()
502 return (LaunchClosure
*)finalizeContainer();
505 void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum
)
507 append(TypedBytes::Type::libSystemNum
, &imageNum
, sizeof(ImageNum
));
510 void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry
)
512 append(TypedBytes::Type::libDyldEntry
, &entry
, sizeof(entry
));
515 void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main
)
517 append(TypedBytes::Type::mainEntry
, &main
, sizeof(main
));
520 void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start
)
522 append(TypedBytes::Type::startEntry
, &start
, sizeof(start
));
525 void LaunchClosureWriter::setUsedFallbackPaths(bool value
)
527 getFlags().usedFallbackPaths
= value
;
530 void LaunchClosureWriter::setUsedAtPaths(bool value
)
532 getFlags().usedAtPaths
= value
;
535 void LaunchClosureWriter::setUsedInterposing(bool value
)
537 getFlags().usedInterposing
= value
;
540 void LaunchClosureWriter::setHasInsertedLibraries(bool value
)
542 getFlags().hasInsertedLibraries
= value
;
545 void LaunchClosureWriter::setInitImageCount(uint32_t count
)
547 getFlags().initImageCount
= count
;
550 LaunchClosure::Flags
& LaunchClosureWriter::getFlags()
552 if ( _flagsOffset
== -1 ) {
553 LaunchClosure::Flags flags
;
554 ::bzero(&flags
, sizeof(flags
));
555 uint8_t* p
= (uint8_t*)append(TypedBytes::Type::closureFlags
, &flags
, sizeof(flags
));
556 _flagsOffset
= (int)(p
- (uint8_t*)currentTypedBytes());
558 return *((LaunchClosure::Flags
*)((uint8_t*)currentTypedBytes() + _flagsOffset
));
561 void LaunchClosureWriter::setMustBeMissingFiles(const Array
<const char*>& paths
)
563 uint32_t totalSize
= 0;
564 for (const char* s
: paths
)
565 totalSize
+= (strlen(s
) +1);
566 totalSize
= (totalSize
+ 3) & (-4); // align
568 char* buffer
= (char*)append(TypedBytes::Type::missingFiles
, nullptr, totalSize
);
570 for (const char* path
: paths
) {
571 for (const char* s
=path
; *s
!= '\0'; ++s
)
575 while (t
< &buffer
[totalSize
])
579 void LaunchClosureWriter::setMustExistFiles(const Array
<LaunchClosure::SkippedFile
>& files
)
581 // Start the structure with a count
582 uint32_t totalSize
= sizeof(uint64_t);
584 // Then make space for the array of mod times and inode numbers
585 totalSize
+= files
.count() * sizeof(uint64_t) * 2;
587 // Then the array of paths on the end
588 for (const LaunchClosure::SkippedFile
& file
: files
)
589 totalSize
+= (strlen(file
.path
) + 1);
590 totalSize
= (totalSize
+ 3) & (-4); // align
592 char* buffer
= (char*)append(TypedBytes::Type::existingFiles
, nullptr, totalSize
);
595 uint64_t* bufferPtr
= (uint64_t*)buffer
;
596 *bufferPtr
++ = (uint64_t)files
.count();
598 // And the array of mod times and inode numbers
599 for (const LaunchClosure::SkippedFile
& file
: files
) {
600 *bufferPtr
++ = file
.inode
;
601 *bufferPtr
++ = file
.mtime
;
604 char* t
= (char*)bufferPtr
;
605 for (const LaunchClosure::SkippedFile
& file
: files
) {
606 for (const char* s
=file
.path
; *s
!= '\0'; ++s
)
610 while (t
< &buffer
[totalSize
])
614 void LaunchClosureWriter::addEnvVar(const char* envVar
)
616 unsigned len
= (unsigned)strlen(envVar
);
618 strcpy(temp
, envVar
);
619 unsigned paddedSize
= len
+1;
620 while ( (paddedSize
% 4) != 0 )
621 temp
[paddedSize
++] = '\0';
622 append(TypedBytes::Type::envVar
, temp
, paddedSize
);
625 void LaunchClosureWriter::addInterposingTuples(const Array
<InterposingTuple
>& tuples
)
627 append(TypedBytes::Type::interposeTuples
, tuples
.begin(), (uint32_t)tuples
.count()*sizeof(InterposingTuple
));
630 void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid
)
632 append(TypedBytes::Type::dyldCacheUUID
, uuid
, sizeof(uuid_t
));
635 void LaunchClosureWriter::setHasProgramVars(uint32_t offset
)
637 getFlags().hasProgVars
= true;
638 append(TypedBytes::Type::progVars
, &offset
, sizeof(uint32_t));
641 void LaunchClosureWriter::setObjCSelectorInfo(const Array
<uint8_t>& hashTable
, const Array
<Image::ObjCSelectorImage
>& hashTableImages
) {
642 uint32_t count
= (uint32_t)hashTableImages
.count();
643 uint32_t totalSize
= (uint32_t)(sizeof(count
) + (sizeof(Image::ObjCSelectorImage
) * count
) + hashTable
.count());
644 totalSize
= (totalSize
+ 3) & (-4); // align
645 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::selectorTable
, nullptr, totalSize
);
647 // Write out out the image count
648 memcpy(buffer
, &count
, sizeof(count
));
649 buffer
+= sizeof(count
);
651 // Write out out the image nums
652 memcpy(buffer
, hashTableImages
.begin(), sizeof(Image::ObjCSelectorImage
) * count
);
653 buffer
+= sizeof(Image::ObjCSelectorImage
) * count
;
655 // Write out out the image count
656 memcpy(buffer
, hashTable
.begin(), hashTable
.count());
659 void LaunchClosureWriter::setObjCClassAndProtocolInfo(const Array
<uint8_t>& classHashTable
, const Array
<uint8_t>& protocolHashTable
,
660 const Array
<Image::ObjCClassImage
>& hashTableImages
) {
661 // The layout here is:
662 // uint32_t offset to class table (note this is 0 if there are no classes)
663 // uint32_t offset to protocol table (note this is 0 if there are no protocols)
664 // uint32_t num images
665 // ObjCClassImage[num images]
667 // [ padding to 4-byte alignment if needed
668 // protocol hash table
669 // [ padding to 4-byte alignment if needed
671 uint32_t numImages
= (uint32_t)hashTableImages
.count();
673 uint32_t headerSize
= sizeof(uint32_t) * 3;
674 uint32_t imagesSize
= (sizeof(Image::ObjCClassImage
) * numImages
);
675 uint32_t classTableSize
= ((uint32_t)classHashTable
.count() + 3) & (-4); // pad to 4-byte multiple
676 uint32_t protocolTableSize
= ((uint32_t)protocolHashTable
.count() + 3) & (-4); // pad to 4-byte multiple
677 uint32_t offsetToClassTable
= (classTableSize
== 0) ? 0 : (headerSize
+ imagesSize
);
678 uint32_t offsetToProtocolTable
= (protocolTableSize
== 0) ? 0 : (headerSize
+ imagesSize
+ classTableSize
);
680 uint32_t totalSize
= headerSize
+ imagesSize
+ classTableSize
+ protocolTableSize
;
681 assert( (totalSize
& 3) == 0);
682 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::classTable
, nullptr, totalSize
);
684 // Write out out the header
685 memcpy(buffer
+ 0, &offsetToClassTable
, sizeof(uint32_t));
686 memcpy(buffer
+ 4, &offsetToProtocolTable
, sizeof(uint32_t));
687 memcpy(buffer
+ 8, &numImages
, sizeof(uint32_t));
689 // Write out out the image nums
690 memcpy(buffer
+ headerSize
, hashTableImages
.begin(), imagesSize
);
692 // Write out out the class hash table
693 if ( offsetToClassTable
!= 0 )
694 memcpy(buffer
+ offsetToClassTable
, classHashTable
.begin(), classHashTable
.count());
696 // Write out out the protocol hash table
697 if ( offsetToProtocolTable
!= 0 )
698 memcpy(buffer
+ offsetToProtocolTable
, protocolHashTable
.begin(), protocolHashTable
.count());
701 void LaunchClosureWriter::setObjCDuplicateClassesInfo(const Array
<uint8_t>& hashTable
) {
702 uint32_t totalSize
= (uint32_t)hashTable
.count();
703 totalSize
= (totalSize
+ 3) & (-4); // align
704 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::duplicateClassesTable
, nullptr, totalSize
);
706 // Write out out the hash table
707 memcpy(buffer
, hashTable
.begin(), hashTable
.count());
710 //////////////////////////// DlopenClosureWriter ////////////////////////////////////////
712 DlopenClosureWriter::DlopenClosureWriter(const ImageArray
* images
)
714 setContainerType(TypedBytes::Type::dlopenClosure
);
715 append(TypedBytes::Type::imageArray
, images
->payload(), images
->payloadLength
);
718 const DlopenClosure
* DlopenClosureWriter::finalize()
720 return (DlopenClosure
*)finalizeContainer();
724 } // namespace closure