dyld-732.8.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 uint8_t sharedRegionAlignP2;
194 uint8_t slideInfoBytesPerPage;
195 bool sharedRegionsAreDiscontiguous;
196 bool is64;
197 bool useValueAdd;
198 };
199
200 static const ArchLayout _s_archLayout[];
201 static const char* const _s_neverStubEliminateDylibs[];
202 static const char* const _s_neverStubEliminateSymbols[];
203
204 struct UnmappedRegion
205 {
206 uint8_t* buffer = nullptr;
207 uint64_t bufferSize = 0;
208 uint64_t sizeInUse = 0;
209 };
210
211 struct DylibInfo
212 {
213 const LoadedMachO* input;
214 std::string runtimePath;
215 std::vector<SegmentMappingInfo> cacheLocation;
216 DylibTextCoalescer textCoalescer;
217 };
218
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();
223
224 uint64_t cacheOverflowAmount();
225 size_t evictLeafDylibs(uint64_t reductionTarget, std::vector<const LoadedMachO*>& overflowDylibs);
226
227 void fipsSign();
228 void codeSign();
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();
242
243 bool writeCache(void (^cacheSizeCallback)(uint64_t size), bool (^copyCallback)(const uint8_t* src, uint64_t size, uint64_t dstOffset));
244
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);
249
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);
254
255 // implemented in AdjustDylibSegemnts.cpp
256 void adjustDylibSegments(const DylibInfo& dylib, Diagnostics& diag) const;
257
258 // implemented in OptimizerLinkedit.cpp
259 void optimizeLinkedit();
260
261 // implemented in OptimizerObjC.cpp
262 void optimizeObjC();
263 uint32_t computeReadOnlyObjC(uint32_t selRefCount, uint32_t classDefCount, uint32_t protocolDefCount);
264 uint32_t computeReadWriteObjC(uint32_t imageCount, uint32_t protocolDefCount);
265
266 // implemented in OptimizerBranches.cpp
267 void optimizeAwayStubs();
268
269 typedef std::unordered_map<std::string, const dyld3::MachOAnalyzer*> InstallNameToMA;
270
271 typedef uint64_t CacheOffset;
272
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;
311 };
312
313
314
315
316 inline uint64_t align(uint64_t addr, uint8_t p2)
317 {
318 uint64_t mask = (1 << p2);
319 return (addr + mask - 1) & (-mask);
320 }
321
322
323
324 #endif /* CacheBuilder_h */