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::setChainedFixups(uint64_t runtimeStartsStructOffset
, const Array
<Image::ResolvedSymbolTarget
>& targets
)
317 getFlags().hasChainedFixups
= true;
318 append(TypedBytes::Type::chainedStartsOffset
, &runtimeStartsStructOffset
, sizeof(uint64_t));
319 append(TypedBytes::Type::chainedFixupsTargets
, targets
.begin(), (uint32_t)targets
.count()*sizeof(Image::ResolvedSymbolTarget
));
322 void ImageWriter::setObjCFixupInfo(const Image::ResolvedSymbolTarget
& objcProtocolClassTarget
,
323 uint64_t objcImageInfoVMOffset
,
324 const Array
<Image::ProtocolISAFixup
>& protocolISAFixups
,
325 const Array
<Image::SelectorReferenceFixup
>& selRefFixups
,
326 const Array
<Image::ClassStableSwiftFixup
>& classStableSwiftFixups
,
327 const Array
<Image::MethodListFixup
>& methodListFixups
)
329 // The layout here is:
330 // ResolvedSymbolTarget
331 // uint64_t vmOffset to objc_imageinfo
332 // uint32_t protocol count
333 // uint32_t selector reference count
334 // array of ProtocolISAFixup
335 // array of SelectorReferenceFixup
336 // optional uint32_t stable swift fixup count
337 // optional uint32_t method list fixup count
338 // optional array of ClassStableSwiftFixup
339 // optional array of MethodListFixup
341 uint64_t headerSize
= sizeof(Image::ResolvedSymbolTarget
) + sizeof(uint64_t) + (sizeof(uint32_t) * 4);
342 uint64_t protocolsSize
= (sizeof(Image::ProtocolISAFixup
) * protocolISAFixups
.count());
343 uint64_t selRefsSize
= (sizeof(Image::SelectorReferenceFixup
) * selRefFixups
.count());
344 uint64_t stableSwiftSize
= (sizeof(Image::ClassStableSwiftFixup
) * classStableSwiftFixups
.count());
345 uint64_t methodListSize
= (sizeof(Image::MethodListFixup
) * methodListFixups
.count());
347 uint64_t totalSize
= headerSize
+ protocolsSize
+ selRefsSize
+ stableSwiftSize
+ methodListSize
;
348 assert( (totalSize
& 3) == 0);
349 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::objcFixups
, nullptr, (uint32_t)totalSize
);
351 // Set the statically sized data
352 uint32_t protocolFixupCount
= (uint32_t)protocolISAFixups
.count();
353 uint32_t selRefFixupCount
= (uint32_t)selRefFixups
.count();
354 memcpy(buffer
, &objcProtocolClassTarget
, sizeof(Image::ResolvedSymbolTarget
));
355 buffer
+= sizeof(Image::ResolvedSymbolTarget
);
356 memcpy(buffer
, &objcImageInfoVMOffset
, sizeof(uint64_t));
357 buffer
+= sizeof(uint64_t);
358 memcpy(buffer
, &protocolFixupCount
, sizeof(uint32_t));
359 buffer
+= sizeof(uint32_t);
360 memcpy(buffer
, &selRefFixupCount
, sizeof(uint32_t));
361 buffer
+= sizeof(uint32_t);
363 // Set the protocol fixups
364 if ( protocolFixupCount
!= 0 ) {
365 memcpy(buffer
, protocolISAFixups
.begin(), (size_t)protocolsSize
);
366 buffer
+= protocolsSize
;
369 // Set the selector reference fixups
370 if ( selRefFixupCount
!= 0 ) {
371 memcpy(buffer
, selRefFixups
.begin(), (size_t)selRefsSize
);
372 buffer
+= selRefsSize
;
375 // New closures get additional fixups. These are ignored by old dyld's
376 uint32_t stableSwiftFixupCount
= (uint32_t)classStableSwiftFixups
.count();
377 uint32_t methodListFixupCount
= (uint32_t)methodListFixups
.count();
378 memcpy(buffer
, &stableSwiftFixupCount
, sizeof(uint32_t));
379 buffer
+= sizeof(uint32_t);
380 memcpy(buffer
, &methodListFixupCount
, sizeof(uint32_t));
381 buffer
+= sizeof(uint32_t);
383 // Set the stable swift fixups
384 if ( stableSwiftFixupCount
!= 0 ) {
385 memcpy(buffer
, classStableSwiftFixups
.begin(), (size_t)stableSwiftSize
);
386 buffer
+= stableSwiftSize
;
389 // Set the method list fixups
390 if ( methodListFixupCount
!= 0 ) {
391 memcpy(buffer
, methodListFixups
.begin(), (size_t)methodListSize
);
392 buffer
+= methodListSize
;
396 void ImageWriter::setAsOverrideOf(ImageNum imageNum
)
398 uint32_t temp
= imageNum
;
399 append(TypedBytes::Type::imageOverride
, &temp
, sizeof(temp
));
402 void ImageWriter::setInitsOrder(const ImageNum images
[], uint32_t count
)
404 append(TypedBytes::Type::initBefores
, images
, count
*sizeof(ImageNum
));
408 //////////////////////////// ImageArrayWriter ////////////////////////////////////////
411 ImageArrayWriter::ImageArrayWriter(ImageNum startImageNum
, unsigned count
, bool hasRoots
) : _index(0)
413 setContainerType(TypedBytes::Type::imageArray
);
414 _end
= (void*)((uint8_t*)_end
+ sizeof(ImageArray
) - sizeof(TypedBytes
) + sizeof(uint32_t)*count
);
415 _containerTypedBytes
->payloadLength
= sizeof(ImageArray
) - sizeof(TypedBytes
) + sizeof(uint32_t)*count
;
416 ImageArray
* ia
= (ImageArray
*)_containerTypedBytes
;
417 ia
->firstImageNum
= startImageNum
;
419 ia
->hasRoots
= hasRoots
;
422 void ImageArrayWriter::appendImage(const Image
* image
)
424 ImageArray
* ia
= (ImageArray
*)_containerTypedBytes
;
425 ia
->offsets
[_index
++] = _containerTypedBytes
->payloadLength
;
426 append(TypedBytes::Type::image
, image
->payload(), image
->payloadLength
);
429 const ImageArray
* ImageArrayWriter::finalize()
431 return (ImageArray
*)finalizeContainer();
435 //////////////////////////// ClosureWriter ////////////////////////////////////////
437 void ClosureWriter::setTopImageNum(ImageNum imageNum
)
439 append(TypedBytes::Type::topImage
, &imageNum
, sizeof(ImageNum
));
442 void ClosureWriter::addCachePatches(const Array
<Closure::PatchEntry
>& patches
)
444 append(TypedBytes::Type::cacheOverrides
, patches
.begin(), (uint32_t)patches
.count()*sizeof(Closure::PatchEntry
));
447 void ClosureWriter::applyInterposing(const LaunchClosure
* launchClosure
)
449 const Closure
* currentClosure
= (Closure
*)currentTypedBytes();
450 const ImageArray
* images
= currentClosure
->images();
451 launchClosure
->forEachInterposingTuple(^(const InterposingTuple
& tuple
, bool&) {
452 images
->forEachImage(^(const dyld3::closure::Image
* image
, bool&) {
453 for (const Image::BindPattern
& bindPat
: image
->bindFixups()) {
454 if ( (bindPat
.target
== tuple
.stockImplementation
) && (tuple
.newImplementation
.image
.imageNum
!= image
->imageNum()) ) {
455 Image::BindPattern
* writePat
= const_cast<Image::BindPattern
*>(&bindPat
);
456 writePat
->target
= tuple
.newImplementation
;
460 // Chained fixups may also be interposed. We can't change elements in the chain, but we can change
462 for (const Image::ResolvedSymbolTarget
& symbolTarget
: image
->chainedTargets()) {
463 if ( (symbolTarget
== tuple
.stockImplementation
) && (tuple
.newImplementation
.image
.imageNum
!= image
->imageNum()) ) {
464 Image::ResolvedSymbolTarget
* writeTarget
= const_cast<Image::ResolvedSymbolTarget
*>(&symbolTarget
);
465 *writeTarget
= tuple
.newImplementation
;
472 void ClosureWriter::addWarning(Closure::Warning::Type warningType
, const char* warning
)
474 uint32_t roundedMessageLen
= ((uint32_t)strlen(warning
) + 1 + 3) & (-4);
475 Closure::Warning
* ph
= (Closure::Warning
*)append(TypedBytes::Type::warning
, nullptr, sizeof(Closure::Warning
)+roundedMessageLen
);
476 ph
->type
= warningType
;
477 strcpy(ph
->message
, warning
);
481 //////////////////////////// LaunchClosureWriter ////////////////////////////////////////
483 LaunchClosureWriter::LaunchClosureWriter(const ImageArray
* images
)
485 setContainerType(TypedBytes::Type::launchClosure
);
486 append(TypedBytes::Type::imageArray
, images
->payload(), images
->payloadLength
);
489 const LaunchClosure
* LaunchClosureWriter::finalize()
491 return (LaunchClosure
*)finalizeContainer();
494 void LaunchClosureWriter::setLibSystemImageNum(ImageNum imageNum
)
496 append(TypedBytes::Type::libSystemNum
, &imageNum
, sizeof(ImageNum
));
499 void LaunchClosureWriter::setLibDyldEntry(Image::ResolvedSymbolTarget entry
)
501 append(TypedBytes::Type::libDyldEntry
, &entry
, sizeof(entry
));
504 void LaunchClosureWriter::setMainEntry(Image::ResolvedSymbolTarget main
)
506 append(TypedBytes::Type::mainEntry
, &main
, sizeof(main
));
509 void LaunchClosureWriter::setStartEntry(Image::ResolvedSymbolTarget start
)
511 append(TypedBytes::Type::startEntry
, &start
, sizeof(start
));
514 void LaunchClosureWriter::setUsedFallbackPaths(bool value
)
516 getFlags().usedFallbackPaths
= value
;
519 void LaunchClosureWriter::setUsedAtPaths(bool value
)
521 getFlags().usedAtPaths
= value
;
524 void LaunchClosureWriter::setHasInsertedLibraries(bool value
)
526 getFlags().hasInsertedLibraries
= value
;
529 void LaunchClosureWriter::setInitImageCount(uint32_t count
)
531 getFlags().initImageCount
= count
;
534 LaunchClosure::Flags
& LaunchClosureWriter::getFlags()
536 if ( _flagsOffset
== -1 ) {
537 LaunchClosure::Flags flags
;
538 ::bzero(&flags
, sizeof(flags
));
539 uint8_t* p
= (uint8_t*)append(TypedBytes::Type::closureFlags
, &flags
, sizeof(flags
));
540 _flagsOffset
= (int)(p
- (uint8_t*)currentTypedBytes());
542 return *((LaunchClosure::Flags
*)((uint8_t*)currentTypedBytes() + _flagsOffset
));
545 void LaunchClosureWriter::setMustBeMissingFiles(const Array
<const char*>& paths
)
547 uint32_t totalSize
= 0;
548 for (const char* s
: paths
)
549 totalSize
+= (strlen(s
) +1);
550 totalSize
= (totalSize
+ 3) & (-4); // align
552 char* buffer
= (char*)append(TypedBytes::Type::missingFiles
, nullptr, totalSize
);
554 for (const char* path
: paths
) {
555 for (const char* s
=path
; *s
!= '\0'; ++s
)
559 while (t
< &buffer
[totalSize
])
563 void LaunchClosureWriter::setMustExistFiles(const Array
<LaunchClosure::SkippedFile
>& files
)
565 // Start the structure with a count
566 uint32_t totalSize
= sizeof(uint64_t);
568 // Then make space for the array of mod times and inode numbers
569 totalSize
+= files
.count() * sizeof(uint64_t) * 2;
571 // Then the array of paths on the end
572 for (const LaunchClosure::SkippedFile
& file
: files
)
573 totalSize
+= (strlen(file
.path
) + 1);
574 totalSize
= (totalSize
+ 3) & (-4); // align
576 char* buffer
= (char*)append(TypedBytes::Type::existingFiles
, nullptr, totalSize
);
579 uint64_t* bufferPtr
= (uint64_t*)buffer
;
580 *bufferPtr
++ = (uint64_t)files
.count();
582 // And the array of mod times and inode numbers
583 for (const LaunchClosure::SkippedFile
& file
: files
) {
584 *bufferPtr
++ = file
.inode
;
585 *bufferPtr
++ = file
.mtime
;
588 char* t
= (char*)bufferPtr
;
589 for (const LaunchClosure::SkippedFile
& file
: files
) {
590 for (const char* s
=file
.path
; *s
!= '\0'; ++s
)
594 while (t
< &buffer
[totalSize
])
598 void LaunchClosureWriter::addEnvVar(const char* envVar
)
600 unsigned len
= (unsigned)strlen(envVar
);
602 strcpy(temp
, envVar
);
603 unsigned paddedSize
= len
+1;
604 while ( (paddedSize
% 4) != 0 )
605 temp
[paddedSize
++] = '\0';
606 append(TypedBytes::Type::envVar
, temp
, paddedSize
);
609 void LaunchClosureWriter::addInterposingTuples(const Array
<InterposingTuple
>& tuples
)
611 append(TypedBytes::Type::interposeTuples
, tuples
.begin(), (uint32_t)tuples
.count()*sizeof(InterposingTuple
));
614 void LaunchClosureWriter::setDyldCacheUUID(const uuid_t uuid
)
616 append(TypedBytes::Type::dyldCacheUUID
, uuid
, sizeof(uuid_t
));
619 void LaunchClosureWriter::setBootUUID(const char* uuid
)
621 unsigned len
= (unsigned)strlen(uuid
);
624 unsigned paddedSize
= len
+1;
625 while ( (paddedSize
% 4) != 0 )
626 temp
[paddedSize
++] = '\0';
627 append(TypedBytes::Type::bootUUID
, temp
, paddedSize
);
630 void LaunchClosureWriter::setObjCSelectorInfo(const Array
<uint8_t>& hashTable
, const Array
<Image::ObjCSelectorImage
>& hashTableImages
) {
631 uint32_t count
= (uint32_t)hashTableImages
.count();
632 uint32_t totalSize
= (uint32_t)(sizeof(count
) + (sizeof(Image::ObjCSelectorImage
) * count
) + hashTable
.count());
633 totalSize
= (totalSize
+ 3) & (-4); // align
634 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::selectorTable
, nullptr, totalSize
);
636 // Write out out the image count
637 memcpy(buffer
, &count
, sizeof(count
));
638 buffer
+= sizeof(count
);
640 // Write out out the image nums
641 memcpy(buffer
, hashTableImages
.begin(), sizeof(Image::ObjCSelectorImage
) * count
);
642 buffer
+= sizeof(Image::ObjCSelectorImage
) * count
;
644 // Write out out the image count
645 memcpy(buffer
, hashTable
.begin(), hashTable
.count());
648 void LaunchClosureWriter::setObjCClassAndProtocolInfo(const Array
<uint8_t>& classHashTable
, const Array
<uint8_t>& protocolHashTable
,
649 const Array
<Image::ObjCClassImage
>& hashTableImages
) {
650 // The layout here is:
651 // uint32_t offset to class table (note this is 0 if there are no classes)
652 // uint32_t offset to protocol table (note this is 0 if there are no protocols)
653 // uint32_t num images
654 // ObjCClassImage[num images]
656 // [ padding to 4-byte alignment if needed
657 // protocol hash table
658 // [ padding to 4-byte alignment if needed
660 uint32_t numImages
= (uint32_t)hashTableImages
.count();
662 uint32_t headerSize
= sizeof(uint32_t) * 3;
663 uint32_t imagesSize
= (sizeof(Image::ObjCClassImage
) * numImages
);
664 uint32_t classTableSize
= ((uint32_t)classHashTable
.count() + 3) & (-4); // pad to 4-byte multiple
665 uint32_t protocolTableSize
= ((uint32_t)protocolHashTable
.count() + 3) & (-4); // pad to 4-byte multiple
666 uint32_t offsetToClassTable
= (classTableSize
== 0) ? 0 : (headerSize
+ imagesSize
);
667 uint32_t offsetToProtocolTable
= (protocolTableSize
== 0) ? 0 : (headerSize
+ imagesSize
+ classTableSize
);
669 uint32_t totalSize
= headerSize
+ imagesSize
+ classTableSize
+ protocolTableSize
;
670 assert( (totalSize
& 3) == 0);
671 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::classTable
, nullptr, totalSize
);
673 // Write out out the header
674 memcpy(buffer
+ 0, &offsetToClassTable
, sizeof(uint32_t));
675 memcpy(buffer
+ 4, &offsetToProtocolTable
, sizeof(uint32_t));
676 memcpy(buffer
+ 8, &numImages
, sizeof(uint32_t));
678 // Write out out the image nums
679 memcpy(buffer
+ headerSize
, hashTableImages
.begin(), imagesSize
);
681 // Write out out the class hash table
682 if ( offsetToClassTable
!= 0 )
683 memcpy(buffer
+ offsetToClassTable
, classHashTable
.begin(), classHashTable
.count());
685 // Write out out the protocol hash table
686 if ( offsetToProtocolTable
!= 0 )
687 memcpy(buffer
+ offsetToProtocolTable
, protocolHashTable
.begin(), protocolHashTable
.count());
690 void LaunchClosureWriter::setObjCDuplicateClassesInfo(const Array
<uint8_t>& hashTable
) {
691 uint32_t totalSize
= (uint32_t)hashTable
.count();
692 totalSize
= (totalSize
+ 3) & (-4); // align
693 uint8_t* buffer
= (uint8_t*)append(TypedBytes::Type::duplicateClassesTable
, nullptr, totalSize
);
695 // Write out out the hash table
696 memcpy(buffer
, hashTable
.begin(), hashTable
.count());
699 //////////////////////////// DlopenClosureWriter ////////////////////////////////////////
701 DlopenClosureWriter::DlopenClosureWriter(const ImageArray
* images
)
703 setContainerType(TypedBytes::Type::dlopenClosure
);
704 append(TypedBytes::Type::imageArray
, images
->payload(), images
->payloadLength
);
707 const DlopenClosure
* DlopenClosureWriter::finalize()
709 return (DlopenClosure
*)finalizeContainer();
713 } // namespace closure