dyld-733.6.tar.gz
[apple/dyld.git] / dyld3 / shared-cache / CacheBuilder.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 CacheBuilder_h
26 #define CacheBuilder_h
27
28 #include <string>
29 #include <vector>
30 #include <map>
31 #include <unordered_map>
32 #include <unordered_set>
33
34 #include "ClosureFileSystem.h"
35 #include "DyldSharedCache.h"
36 #include "Diagnostics.h"
37 #include "MachOAnalyzer.h"
38
39
40
41 template <typename P> class LinkeditOptimizer;
42
43
44 class CacheBuilder {
45 public:
46 CacheBuilder(const DyldSharedCache::CreateOptions& options, const dyld3::closure::FileSystem& fileSystem);
47
48 struct InputFile {
49 enum State {
50 Unset,
51 MustBeIncluded,
52 MustBeIncludedForDependent,
53 MustBeExcludedIfUnused
54 };
55 InputFile(const char* path, State state) : path(path), state(state) { }
56 const char* path;
57 State state = Unset;
58 Diagnostics diag;
59
60 bool mustBeIncluded() const {
61 return (state == MustBeIncluded) || (state == MustBeIncludedForDependent);
62 }
63 };
64
65 // Contains a MachO which has been loaded from the file system and may potentially need to be unloaded later.
66 struct LoadedMachO {
67 DyldSharedCache::MappedMachO mappedFile;
68 dyld3::closure::LoadedFileInfo loadedFileInfo;
69 InputFile* inputFile;
70 };
71
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;
86 void deleteBuffer();
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;
94
95 void forEachCacheDylib(void (^callback)(const std::string& path));
96
97 struct SegmentMappingInfo {
98 const void* srcSegment;
99 const char* segName;
100 void* dstSegment;
101 uint64_t dstCacheUnslidAddress;
102 uint32_t dstCacheFileOffset;
103 uint32_t dstCacheSegmentSize;
104 uint32_t dstCacheFileSize;
105 uint32_t copySegmentSize;
106 uint32_t srcSegmentIndex;
107 };
108
109 struct DylibTextCoalescer {
110
111 typedef std::map<uint32_t, uint32_t> DylibSectionOffsetToCacheSectionOffset;
112
113 DylibSectionOffsetToCacheSectionOffset objcClassNames;
114 DylibSectionOffsetToCacheSectionOffset objcMethNames;
115 DylibSectionOffsetToCacheSectionOffset objcMethTypes;
116
117 bool sectionWasCoalesced(std::string_view sectionName) const;
118 DylibSectionOffsetToCacheSectionOffset& getSectionCoalescer(std::string_view sectionName);
119 const DylibSectionOffsetToCacheSectionOffset& getSectionCoalescer(std::string_view sectionName) const;
120 };
121
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;
130
131 // Note this is for debugging only
132 uint64_t savedSpace = 0;
133 };
134
135 StringSection objcClassNames;
136 StringSection objcMethNames;
137 StringSection objcMethTypes;
138
139 void parseCoalescableText(const dyld3::MachOAnalyzer* ma,
140 DylibTextCoalescer& textCoalescer);
141 void clear();
142
143 StringSection& getSectionData(std::string_view sectionName);
144 const StringSection& getSectionData(std::string_view sectionName) const;
145 };
146
147 class ASLR_Tracker
148 {
149 public:
150 ~ASLR_Tracker();
151
152 void setDataRegion(const void* rwRegionStart, size_t rwRegionSize);
153 void add(void* p);
154 void remove(void* p);
155 bool has(void* p);
156 const bool* bitmap() { return _bitmap; }
157 unsigned dataPageCount() { return _pageCount; }
158 void disable() { _enabled = false; };
159
160 private:
161
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;
168 };
169
170 typedef std::map<uint64_t, std::set<void*>> LOH_Tracker;
171
172 struct Region
173 {
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;
179 };
180
181 private:
182 template <typename P>
183 friend class LinkeditOptimizer;
184
185 struct ArchLayout
186 {
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 uint16_t csPageSize;
194 uint8_t sharedRegionAlignP2;
195 uint8_t slideInfoBytesPerPage;
196 bool sharedRegionsAreDiscontiguous;
197 bool is64;
198 bool useValueAdd;
199 };
200
201 static const ArchLayout _s_archLayout[];
202 static const char* const _s_neverStubEliminateDylibs[];
203 static const char* const _s_neverStubEliminateSymbols[];
204
205 struct UnmappedRegion
206 {
207 uint8_t* buffer = nullptr;
208 uint64_t bufferSize = 0;
209 uint64_t sizeInUse = 0;
210 };
211
212 struct DylibInfo
213 {
214 const LoadedMachO* input;
215 std::string runtimePath;
216 std::vector<SegmentMappingInfo> cacheLocation;
217 DylibTextCoalescer textCoalescer;
218 };
219
220 void makeSortedDylibs(const std::vector<LoadedMachO>& dylibs, const std::unordered_map<std::string, unsigned> sortOrder);
221 void processSelectorStrings(const std::vector<LoadedMachO>& executables);
222 void parseCoalescableSegments();
223 void assignSegmentAddresses();
224
225 uint64_t cacheOverflowAmount();
226 size_t evictLeafDylibs(uint64_t reductionTarget, std::vector<const LoadedMachO*>& overflowDylibs);
227
228 void fipsSign();
229 void codeSign();
230 uint64_t pathHash(const char* path);
231 void writeCacheHeader();
232 void copyRawSegments();
233 void adjustAllImagesForNewSegmentLocations();
234 void writeSlideInfoV1();
235 void writeSlideInfoV3(const bool bitmap[], unsigned dataPageCoun);
236 uint16_t pageStartV3(uint8_t* pageContent, uint32_t pageSize, const bool bitmap[]);
237 void findDylibAndSegment(const void* contentPtr, std::string& dylibName, std::string& segName);
238 void addImageArray();
239 void buildImageArray(std::vector<DyldSharedCache::FileAlias>& aliases);
240 void addOtherImageArray(const std::vector<LoadedMachO>&, std::vector<const LoadedMachO*>& overflowDylibs);
241 void addClosures(const std::vector<LoadedMachO>&);
242 void markPaddingInaccessible();
243
244 bool writeCache(void (^cacheSizeCallback)(uint64_t size), bool (^copyCallback)(const uint8_t* src, uint64_t size, uint64_t dstOffset));
245
246 template <typename P> void writeSlideInfoV2(const bool bitmap[], unsigned dataPageCount);
247 template <typename P> bool makeRebaseChainV2(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const struct dyld_cache_slide_info2* info);
248 template <typename P> void addPageStartsV2(uint8_t* pageContent, const bool bitmap[], const struct dyld_cache_slide_info2* info,
249 std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
250
251 template <typename P> void writeSlideInfoV4(const bool bitmap[], unsigned dataPageCount);
252 template <typename P> bool makeRebaseChainV4(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const struct dyld_cache_slide_info4* info);
253 template <typename P> void addPageStartsV4(uint8_t* pageContent, const bool bitmap[], const struct dyld_cache_slide_info4* info,
254 std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
255
256 // implemented in AdjustDylibSegemnts.cpp
257 void adjustDylibSegments(const DylibInfo& dylib, Diagnostics& diag) const;
258
259 // implemented in OptimizerLinkedit.cpp
260 void optimizeLinkedit();
261
262 // implemented in OptimizerObjC.cpp
263 void optimizeObjC();
264 uint32_t computeReadOnlyObjC(uint32_t selRefCount, uint32_t classDefCount, uint32_t protocolDefCount);
265 uint32_t computeReadWriteObjC(uint32_t imageCount, uint32_t protocolDefCount);
266
267 // implemented in OptimizerBranches.cpp
268 void optimizeAwayStubs();
269
270 typedef std::unordered_map<std::string, const dyld3::MachOAnalyzer*> InstallNameToMA;
271
272 typedef uint64_t CacheOffset;
273
274 const DyldSharedCache::CreateOptions& _options;
275 const dyld3::closure::FileSystem& _fileSystem;
276 Region _readExecuteRegion;
277 Region _readWriteRegion;
278 Region _readOnlyRegion;
279 UnmappedRegion _localSymbolsRegion;
280 UnmappedRegion _codeSignatureRegion;
281 vm_address_t _fullAllocatedBuffer;
282 uint64_t _nonLinkEditReadOnlySize;
283 Diagnostics _diagnostics;
284 std::set<const dyld3::MachOAnalyzer*> _evictions;
285 const ArchLayout* _archLayout;
286 uint32_t _aliasCount;
287 uint64_t _slideInfoFileOffset;
288 uint64_t _slideInfoBufferSizeAllocated;
289 uint8_t* _objcReadOnlyBuffer;
290 uint64_t _objcReadOnlyBufferSizeUsed;
291 uint64_t _objcReadOnlyBufferSizeAllocated;
292 uint8_t* _objcReadWriteBuffer;
293 uint64_t _objcReadWriteBufferSizeAllocated;
294 uint64_t _allocatedBufferSize;
295 CacheCoalescedText _coalescedText;
296 uint64_t _selectorStringsFromExecutables;
297 std::vector<DylibInfo> _sortedDylibs;
298 InstallNameToMA _installNameToCacheDylib;
299 std::unordered_map<std::string, uint32_t> _dataDirtySegsOrder;
300 // Note this is mutable as the only parallel writes to it are done atomically to the bitmap
301 mutable ASLR_Tracker _aslrTracker;
302 std::map<void*, std::string> _missingWeakImports;
303 mutable LOH_Tracker _lohTracker;
304 const dyld3::closure::ImageArray* _imageArray;
305 uint32_t _sharedStringsPoolVmOffset;
306 uint8_t _cdHashFirst[20];
307 uint8_t _cdHashSecond[20];
308 std::unordered_map<const dyld3::MachOLoaded*, std::set<CacheOffset>> _dylibToItsExports;
309 std::set<std::pair<const dyld3::MachOLoaded*, CacheOffset>> _dylibWeakExports;
310 std::unordered_map<CacheOffset, std::vector<dyld_cache_patchable_location>> _exportsToUses;
311 std::unordered_map<CacheOffset, std::string> _exportsToName;
312 };
313
314
315
316
317 inline uint64_t align(uint64_t addr, uint8_t p2)
318 {
319 uint64_t mask = (1 << p2);
320 return (addr + mask - 1) & (-mask);
321 }
322
323
324
325 #endif /* CacheBuilder_h */