dyld-625.13.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 void writeMapFileBuffer(uint8_t*& buffer, uint64_t& bufferSize);
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
94 void forEachCacheDylib(void (^callback)(const std::string& path));
95
96 struct SegmentMappingInfo {
97 const void* srcSegment;
98 const char* segName;
99 void* dstSegment;
100 uint64_t dstCacheUnslidAddress;
101 uint32_t dstCacheFileOffset;
102 uint32_t dstCacheSegmentSize;
103 uint32_t copySegmentSize;
104 uint32_t srcSegmentIndex;
105 };
106
107 class ASLR_Tracker
108 {
109 public:
110 ~ASLR_Tracker();
111
112 void setDataRegion(const void* rwRegionStart, size_t rwRegionSize);
113 void add(void* p);
114 void remove(void* p);
115 bool has(void* p);
116 const bool* bitmap() { return _bitmap; }
117 unsigned dataPageCount() { return _pageCount; }
118
119 private:
120
121 uint8_t* _regionStart = nullptr;
122 uint8_t* _endStart = nullptr;
123 bool* _bitmap = nullptr;
124 unsigned _pageCount = 0;
125 unsigned _pageSize = 4096;
126 };
127
128 typedef std::map<uint64_t, std::set<void*>> LOH_Tracker;
129
130 struct Region
131 {
132 uint8_t* buffer = nullptr;
133 uint64_t bufferSize = 0;
134 uint64_t sizeInUse = 0;
135 uint64_t unslidLoadAddress = 0;
136 uint64_t cacheFileOffset = 0;
137 };
138
139 private:
140 template <typename P>
141 friend class LinkeditOptimizer;
142
143 struct ArchLayout
144 {
145 uint64_t sharedMemoryStart;
146 uint64_t sharedMemorySize;
147 uint64_t sharedRegionPadding;
148 uint64_t pointerDeltaMask;
149 const char* archName;
150 uint32_t branchPoolTextSize;
151 uint32_t branchPoolLinkEditSize;
152 uint32_t branchReach;
153 uint8_t sharedRegionAlignP2;
154 uint8_t slideInfoBytesPerPage;
155 bool sharedRegionsAreDiscontiguous;
156 bool is64;
157 };
158
159 static const ArchLayout _s_archLayout[];
160 static const char* const _s_neverStubEliminate[];
161
162 struct UnmappedRegion
163 {
164 uint8_t* buffer = nullptr;
165 uint64_t bufferSize = 0;
166 uint64_t sizeInUse = 0;
167 };
168
169 struct DylibInfo
170 {
171 const LoadedMachO* input;
172 std::string runtimePath;
173 std::vector<SegmentMappingInfo> cacheLocation;
174 };
175
176 void makeSortedDylibs(const std::vector<LoadedMachO>& dylibs, const std::unordered_map<std::string, unsigned> sortOrder);
177 void assignSegmentAddresses();
178
179 uint64_t cacheOverflowAmount();
180 size_t evictLeafDylibs(uint64_t reductionTarget, std::vector<const LoadedMachO*>& overflowDylibs);
181
182 void fipsSign();
183 void codeSign();
184 uint64_t pathHash(const char* path);
185 void writeCacheHeader();
186 void copyRawSegments();
187 void adjustAllImagesForNewSegmentLocations();
188 void writeSlideInfoV1();
189 void writeSlideInfoV3(const bool bitmap[], unsigned dataPageCoun);
190 uint16_t pageStartV3(uint8_t* pageContent, uint32_t pageSize, const bool bitmap[]);
191 void findDylibAndSegment(const void* contentPtr, std::string& dylibName, std::string& segName);
192 void addImageArray();
193 void buildImageArray(std::vector<DyldSharedCache::FileAlias>& aliases);
194 void addOtherImageArray(const std::vector<LoadedMachO>&, std::vector<const LoadedMachO*>& overflowDylibs);
195 void addClosures(const std::vector<LoadedMachO>&);
196 void markPaddingInaccessible();
197
198 bool writeCache(void (^cacheSizeCallback)(uint64_t size), bool (^copyCallback)(const uint8_t* src, uint64_t size, uint64_t dstOffset));
199
200 template <typename P> void writeSlideInfoV2(const bool bitmap[], unsigned dataPageCount);
201 template <typename P> bool makeRebaseChainV2(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const struct dyld_cache_slide_info2* info);
202 template <typename P> void addPageStartsV2(uint8_t* pageContent, const bool bitmap[], const struct dyld_cache_slide_info2* info,
203 std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
204
205 template <typename P> void writeSlideInfoV4(const bool bitmap[], unsigned dataPageCount);
206 template <typename P> bool makeRebaseChainV4(uint8_t* pageContent, uint16_t lastLocationOffset, uint16_t newOffset, const struct dyld_cache_slide_info4* info);
207 template <typename P> void addPageStartsV4(uint8_t* pageContent, const bool bitmap[], const struct dyld_cache_slide_info4* info,
208 std::vector<uint16_t>& pageStarts, std::vector<uint16_t>& pageExtras);
209
210 // implemented in AdjustDylibSegemnts.cpp
211 void adjustDylibSegments(const DylibInfo& dylib, Diagnostics& diag) const;
212
213 // implemented in OptimizerLinkedit.cpp
214 void optimizeLinkedit(const std::vector<uint64_t>& branchPoolOffsets);
215
216 // implemented in OptimizerObjC.cpp
217 void optimizeObjC();
218
219 // implemented in OptimizerBranches.cpp
220 void optimizeAwayStubs(const std::vector<uint64_t>& branchPoolStartAddrs, uint64_t branchPoolsLinkEditStartAddr);
221
222
223 typedef std::unordered_map<std::string, const dyld3::MachOAnalyzer*> InstallNameToMA;
224
225
226 const DyldSharedCache::CreateOptions& _options;
227 const dyld3::closure::FileSystem& _fileSystem;
228 Region _readExecuteRegion;
229 Region _readWriteRegion;
230 Region _readOnlyRegion;
231 UnmappedRegion _localSymbolsRegion;
232 UnmappedRegion _codeSignatureRegion;
233 vm_address_t _fullAllocatedBuffer;
234 uint64_t _nonLinkEditReadOnlySize;
235 Diagnostics _diagnostics;
236 std::set<const dyld3::MachOAnalyzer*> _evictions;
237 const ArchLayout* _archLayout;
238 uint32_t _aliasCount;
239 uint64_t _slideInfoFileOffset;
240 uint64_t _slideInfoBufferSizeAllocated;
241 uint64_t _allocatedBufferSize;
242 std::vector<DylibInfo> _sortedDylibs;
243 InstallNameToMA _installNameToCacheDylib;
244 std::unordered_map<std::string, uint32_t> _dataDirtySegsOrder;
245 // Note this is mutable as the only parallel writes to it are done atomically to the bitmap
246 mutable ASLR_Tracker _aslrTracker;
247 std::map<void*, std::string> _missingWeakImports;
248 mutable LOH_Tracker _lohTracker;
249 const dyld3::closure::ImageArray* _imageArray;
250 uint32_t _sharedStringsPoolVmOffset;
251 std::vector<uint64_t> _branchPoolStarts;
252 uint64_t _branchPoolsLinkEditStartAddr;
253 uint8_t _cdHashFirst[20];
254 uint8_t _cdHashSecond[20];
255 };
256
257
258
259
260 inline uint64_t align(uint64_t addr, uint8_t p2)
261 {
262 uint64_t mask = (1 << p2);
263 return (addr + mask - 1) & (-mask);
264 }
265
266
267
268 #endif /* CacheBuilder_h */