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@
25 #ifndef CacheBuilder_h
26 #define CacheBuilder_h
31 #include <unordered_map>
32 #include <unordered_set>
34 #include "ClosureFileSystem.h"
35 #include "DyldSharedCache.h"
36 #include "Diagnostics.h"
37 #include "MachOAnalyzer.h"
41 template <typename P
> class LinkeditOptimizer
;
46 CacheBuilder(const DyldSharedCache::CreateOptions
& options
, const dyld3::closure::FileSystem
& fileSystem
);
52 MustBeIncludedForDependent
,
53 MustBeExcludedIfUnused
55 InputFile(const char* path
, State state
) : path(path
), state(state
) { }
60 bool mustBeIncluded() const {
61 return (state
== MustBeIncluded
) || (state
== MustBeIncludedForDependent
);
65 // Contains a MachO which has been loaded from the file system and may potentially need to be unloaded later.
67 DyldSharedCache::MappedMachO mappedFile
;
68 dyld3::closure::LoadedFileInfo loadedFileInfo
;
72 void build(std::vector
<InputFile
>& inputFiles
,
73 std::vector
<DyldSharedCache::FileAlias
>& aliases
);
74 void build(const std::vector
<LoadedMachO
>& dylibs
,
75 const std::vector
<LoadedMachO
>& otherOsDylibsInput
,
76 const std::vector
<LoadedMachO
>& osExecutables
,
77 std::vector
<DyldSharedCache::FileAlias
>& aliases
);
78 void build(const std::vector
<DyldSharedCache::MappedMachO
>& dylibsToCache
,
79 const std::vector
<DyldSharedCache::MappedMachO
>& otherOsDylibs
,
80 const std::vector
<DyldSharedCache::MappedMachO
>& osExecutables
,
81 std::vector
<DyldSharedCache::FileAlias
>& aliases
);
82 void writeFile(const std::string
& path
);
83 void writeBuffer(uint8_t*& buffer
, uint64_t& size
);
84 void writeMapFile(const std::string
& path
);
85 std::string
getMapFileBuffer(const std::string
& cacheDisposition
) const;
87 std::string
errorMessage();
88 const std::set
<std::string
> warnings();
89 const std::set
<const dyld3::MachOAnalyzer
*> evictions();
90 const bool agileSignature();
91 const std::string
cdHashFirst();
92 const std::string
cdHashSecond();
93 const std::string
uuid() const;
95 void forEachCacheDylib(void (^callback
)(const std::string
& path
));
97 struct SegmentMappingInfo
{
98 const void* srcSegment
;
101 uint64_t dstCacheUnslidAddress
;
102 uint32_t dstCacheFileOffset
;
103 uint32_t dstCacheSegmentSize
;
104 uint32_t dstCacheFileSize
;
105 uint32_t copySegmentSize
;
106 uint32_t srcSegmentIndex
;
109 struct DylibTextCoalescer
{
111 typedef std::map
<uint32_t, uint32_t> DylibSectionOffsetToCacheSectionOffset
;
113 DylibSectionOffsetToCacheSectionOffset objcClassNames
;
114 DylibSectionOffsetToCacheSectionOffset objcMethNames
;
115 DylibSectionOffsetToCacheSectionOffset objcMethTypes
;
117 bool sectionWasCoalesced(std::string_view sectionName
) const;
118 DylibSectionOffsetToCacheSectionOffset
& getSectionCoalescer(std::string_view sectionName
);
119 const DylibSectionOffsetToCacheSectionOffset
& getSectionCoalescer(std::string_view sectionName
) const;
122 struct CacheCoalescedText
{
123 static const char* SupportedSections
[3];
124 struct StringSection
{
125 // Map from class name strings to offsets in to the class names buffer
126 std::map
<std::string_view
, uint32_t> stringsToOffsets
;
127 uint8_t* bufferAddr
= nullptr;
128 uint32_t bufferSize
= 0;
129 uint64_t bufferVMAddr
= 0;
131 // Note this is for debugging only
132 uint64_t savedSpace
= 0;
135 StringSection objcClassNames
;
136 StringSection objcMethNames
;
137 StringSection objcMethTypes
;
139 void parseCoalescableText(const dyld3::MachOAnalyzer
* ma
,
140 DylibTextCoalescer
& textCoalescer
);
143 StringSection
& getSectionData(std::string_view sectionName
);
144 const StringSection
& getSectionData(std::string_view sectionName
) const;
152 void setDataRegion(const void* rwRegionStart
, size_t rwRegionSize
);
154 void remove(void* p
);
156 const bool* bitmap() { return _bitmap
; }
157 unsigned dataPageCount() { return _pageCount
; }
158 void disable() { _enabled
= false; };
162 uint8_t* _regionStart
= nullptr;
163 uint8_t* _endStart
= nullptr;
164 bool* _bitmap
= nullptr;
165 unsigned _pageCount
= 0;
166 unsigned _pageSize
= 4096;
167 bool _enabled
= true;
170 typedef std::map
<uint64_t, std::set
<void*>> LOH_Tracker
;
174 uint8_t* buffer
= nullptr;
175 uint64_t bufferSize
= 0;
176 uint64_t sizeInUse
= 0;
177 uint64_t unslidLoadAddress
= 0;
178 uint64_t cacheFileOffset
= 0;
182 template <typename P
>
183 friend class LinkeditOptimizer
;
187 uint64_t sharedMemoryStart
;
188 uint64_t sharedMemorySize
;
189 uint64_t textAndDataMaxSize
;
190 uint64_t sharedRegionPadding
;
191 uint64_t pointerDeltaMask
;
192 const char* archName
;
193 uint8_t sharedRegionAlignP2
;
194 uint8_t slideInfoBytesPerPage
;
195 bool sharedRegionsAreDiscontiguous
;
200 static const ArchLayout _s_archLayout
[];
201 static const char* const _s_neverStubEliminateDylibs
[];
202 static const char* const _s_neverStubEliminateSymbols
[];
204 struct UnmappedRegion
206 uint8_t* buffer
= nullptr;
207 uint64_t bufferSize
= 0;
208 uint64_t sizeInUse
= 0;
213 const LoadedMachO
* input
;
214 std::string runtimePath
;
215 std::vector
<SegmentMappingInfo
> cacheLocation
;
216 DylibTextCoalescer textCoalescer
;
219 void makeSortedDylibs(const std::vector
<LoadedMachO
>& dylibs
, const std::unordered_map
<std::string
, unsigned> sortOrder
);
220 void processSelectorStrings(const std::vector
<LoadedMachO
>& executables
);
221 void parseCoalescableSegments();
222 void assignSegmentAddresses();
224 uint64_t cacheOverflowAmount();
225 size_t evictLeafDylibs(uint64_t reductionTarget
, std::vector
<const LoadedMachO
*>& overflowDylibs
);
229 uint64_t pathHash(const char* path
);
230 void writeCacheHeader();
231 void copyRawSegments();
232 void adjustAllImagesForNewSegmentLocations();
233 void writeSlideInfoV1();
234 void writeSlideInfoV3(const bool bitmap
[], unsigned dataPageCoun
);
235 uint16_t pageStartV3(uint8_t* pageContent
, uint32_t pageSize
, const bool bitmap
[]);
236 void findDylibAndSegment(const void* contentPtr
, std::string
& dylibName
, std::string
& segName
);
237 void addImageArray();
238 void buildImageArray(std::vector
<DyldSharedCache::FileAlias
>& aliases
);
239 void addOtherImageArray(const std::vector
<LoadedMachO
>&, std::vector
<const LoadedMachO
*>& overflowDylibs
);
240 void addClosures(const std::vector
<LoadedMachO
>&);
241 void markPaddingInaccessible();
243 bool writeCache(void (^cacheSizeCallback
)(uint64_t size
), bool (^copyCallback
)(const uint8_t* src
, uint64_t size
, uint64_t dstOffset
));
245 template <typename P
> void writeSlideInfoV2(const bool bitmap
[], unsigned dataPageCount
);
246 template <typename P
> bool makeRebaseChainV2(uint8_t* pageContent
, uint16_t lastLocationOffset
, uint16_t newOffset
, const struct dyld_cache_slide_info2
* info
);
247 template <typename P
> void addPageStartsV2(uint8_t* pageContent
, const bool bitmap
[], const struct dyld_cache_slide_info2
* info
,
248 std::vector
<uint16_t>& pageStarts
, std::vector
<uint16_t>& pageExtras
);
250 template <typename P
> void writeSlideInfoV4(const bool bitmap
[], unsigned dataPageCount
);
251 template <typename P
> bool makeRebaseChainV4(uint8_t* pageContent
, uint16_t lastLocationOffset
, uint16_t newOffset
, const struct dyld_cache_slide_info4
* info
);
252 template <typename P
> void addPageStartsV4(uint8_t* pageContent
, const bool bitmap
[], const struct dyld_cache_slide_info4
* info
,
253 std::vector
<uint16_t>& pageStarts
, std::vector
<uint16_t>& pageExtras
);
255 // implemented in AdjustDylibSegemnts.cpp
256 void adjustDylibSegments(const DylibInfo
& dylib
, Diagnostics
& diag
) const;
258 // implemented in OptimizerLinkedit.cpp
259 void optimizeLinkedit();
261 // implemented in OptimizerObjC.cpp
263 uint32_t computeReadOnlyObjC(uint32_t selRefCount
, uint32_t classDefCount
, uint32_t protocolDefCount
);
264 uint32_t computeReadWriteObjC(uint32_t imageCount
, uint32_t protocolDefCount
);
266 // implemented in OptimizerBranches.cpp
267 void optimizeAwayStubs();
269 typedef std::unordered_map
<std::string
, const dyld3::MachOAnalyzer
*> InstallNameToMA
;
271 typedef uint64_t CacheOffset
;
273 const DyldSharedCache::CreateOptions
& _options
;
274 const dyld3::closure::FileSystem
& _fileSystem
;
275 Region _readExecuteRegion
;
276 Region _readWriteRegion
;
277 Region _readOnlyRegion
;
278 UnmappedRegion _localSymbolsRegion
;
279 UnmappedRegion _codeSignatureRegion
;
280 vm_address_t _fullAllocatedBuffer
;
281 uint64_t _nonLinkEditReadOnlySize
;
282 Diagnostics _diagnostics
;
283 std::set
<const dyld3::MachOAnalyzer
*> _evictions
;
284 const ArchLayout
* _archLayout
;
285 uint32_t _aliasCount
;
286 uint64_t _slideInfoFileOffset
;
287 uint64_t _slideInfoBufferSizeAllocated
;
288 uint8_t* _objcReadOnlyBuffer
;
289 uint64_t _objcReadOnlyBufferSizeUsed
;
290 uint64_t _objcReadOnlyBufferSizeAllocated
;
291 uint8_t* _objcReadWriteBuffer
;
292 uint64_t _objcReadWriteBufferSizeAllocated
;
293 uint64_t _allocatedBufferSize
;
294 CacheCoalescedText _coalescedText
;
295 uint64_t _selectorStringsFromExecutables
;
296 std::vector
<DylibInfo
> _sortedDylibs
;
297 InstallNameToMA _installNameToCacheDylib
;
298 std::unordered_map
<std::string
, uint32_t> _dataDirtySegsOrder
;
299 // Note this is mutable as the only parallel writes to it are done atomically to the bitmap
300 mutable ASLR_Tracker _aslrTracker
;
301 std::map
<void*, std::string
> _missingWeakImports
;
302 mutable LOH_Tracker _lohTracker
;
303 const dyld3::closure::ImageArray
* _imageArray
;
304 uint32_t _sharedStringsPoolVmOffset
;
305 uint8_t _cdHashFirst
[20];
306 uint8_t _cdHashSecond
[20];
307 std::unordered_map
<const dyld3::MachOLoaded
*, std::set
<CacheOffset
>> _dylibToItsExports
;
308 std::set
<std::pair
<const dyld3::MachOLoaded
*, CacheOffset
>> _dylibWeakExports
;
309 std::unordered_map
<CacheOffset
, std::vector
<dyld_cache_patchable_location
>> _exportsToUses
;
310 std::unordered_map
<CacheOffset
, std::string
> _exportsToName
;
316 inline uint64_t align(uint64_t addr
, uint8_t p2
)
318 uint64_t mask
= (1 << p2
);
319 return (addr
+ mask
- 1) & (-mask
);
324 #endif /* CacheBuilder_h */