dyld-832.7.1.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 #include "IMPCaches.hpp"
39
40 template <typename P> class LinkeditOptimizer;
41
42
43 class CacheBuilder {
44 public:
45 CacheBuilder(const DyldSharedCache::CreateOptions& options, const dyld3::closure::FileSystem& fileSystem);
46 virtual ~CacheBuilder();
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 std::string errorMessage();
73
74 struct Region
75 {
76 uint8_t* buffer = nullptr;
77 uint64_t bufferSize = 0;
78 uint64_t sizeInUse = 0;
79 uint64_t unslidLoadAddress = 0;
80 uint64_t cacheFileOffset = 0;
81 uint8_t permissions = 0;
82 std::string name;
83 uint64_t index = ~0ULL; // The index of this region in the final binary
84
85 // Each region can optionally have its own slide info
86 uint8_t* slideInfoBuffer = nullptr;
87 uint64_t slideInfoBufferSizeAllocated = 0;
88 uint64_t slideInfoFileOffset = 0;
89 uint64_t slideInfoFileSize = 0;
90 };
91
92 struct SegmentMappingInfo {
93 const void* srcSegment;
94 const char* segName;
95 void* dstSegment;
96 uint64_t dstCacheUnslidAddress;
97 uint32_t dstCacheFileOffset;
98 uint32_t dstCacheSegmentSize;
99 uint32_t dstCacheFileSize;
100 uint32_t copySegmentSize;
101 uint32_t srcSegmentIndex;
102 // Used by the AppCacheBuilder to work out which one of the regions this segment is in
103 const Region* parentRegion = nullptr;
104 };
105
106 struct DylibTextCoalescer {
107
108 typedef std::map<uint32_t, uint32_t> DylibSectionOffsetToCacheSectionOffset;
109
110 DylibSectionOffsetToCacheSectionOffset objcClassNames;
111 DylibSectionOffsetToCacheSectionOffset objcMethNames;
112 DylibSectionOffsetToCacheSectionOffset objcMethTypes;
113
114 DylibSectionOffsetToCacheSectionOffset cfStrings;
115
116 bool segmentWasCoalesced(std::string_view segmentName) const;
117 bool sectionWasCoalesced(std::string_view segmentName, std::string_view sectionName) const;
118 DylibSectionOffsetToCacheSectionOffset& getSectionCoalescer(std::string_view segmentName, std::string_view sectionName);
119 const DylibSectionOffsetToCacheSectionOffset& getSectionCoalescer(std::string_view segmentName, 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 struct CFSection {
136 uint8_t* bufferAddr = nullptr;
137 uint32_t bufferSize = 0;
138 uint64_t bufferVMAddr = 0;
139 uint64_t cacheFileOffset = 0;
140
141 // The install name of the dylib for the ISA
142 const char* isaInstallName = nullptr;
143 const char* isaClassName = "___CFConstantStringClassReference";
144 uint64_t isaVMOffset = 0;
145 };
146
147 StringSection objcClassNames;
148 StringSection objcMethNames;
149 StringSection objcMethTypes;
150
151 CFSection cfStrings;
152
153 void parseCoalescableText(const dyld3::MachOAnalyzer* ma,
154 DylibTextCoalescer& textCoalescer,
155 const IMPCaches::SelectorMap& selectors,
156 IMPCaches::HoleMap& selectorHoleMap);
157 void parseCFConstants(const dyld3::MachOAnalyzer* ma,
158 DylibTextCoalescer& textCoalescer);
159 void clear();
160
161 StringSection& getSectionData(std::string_view sectionName);
162 const StringSection& getSectionData(std::string_view sectionName) const;
163 uint64_t getSectionVMAddr(std::string_view segmentName, std::string_view sectionName) const;
164 uint8_t* getSectionBufferAddr(std::string_view segmentName, std::string_view sectionName) const;
165 uint64_t getSectionObjcTag(std::string_view segmentName, std::string_view sectionName) const;
166 };
167
168 class ASLR_Tracker
169 {
170 public:
171 ASLR_Tracker() = default;
172 ~ASLR_Tracker();
173
174 ASLR_Tracker(ASLR_Tracker&&) = delete;
175 ASLR_Tracker(const ASLR_Tracker&) = delete;
176 ASLR_Tracker& operator=(ASLR_Tracker&& other) = delete;
177 ASLR_Tracker& operator=(const ASLR_Tracker& other) = delete;
178
179 void setDataRegion(const void* rwRegionStart, size_t rwRegionSize);
180 void add(void* loc, uint8_t level = (uint8_t)~0);
181 void setHigh8(void* p, uint8_t high8);
182 void setAuthData(void* p, uint16_t diversity, bool hasAddrDiv, uint8_t key);
183 void setRebaseTarget32(void*p, uint32_t targetVMAddr);
184 void setRebaseTarget64(void*p, uint64_t targetVMAddr);
185 void remove(void* p);
186 bool has(void* loc, uint8_t* level = nullptr) const;
187 const bool* bitmap() { return _bitmap; }
188 unsigned dataPageCount() { return _pageCount; }
189 unsigned pageSize() const { return _pageSize; }
190 void disable() { _enabled = false; };
191 bool hasHigh8(void* p, uint8_t* highByte) const;
192 bool hasAuthData(void* p, uint16_t* diversity, bool* hasAddrDiv, uint8_t* key) const;
193 bool hasRebaseTarget32(void* p, uint32_t* vmAddr) const;
194 bool hasRebaseTarget64(void* p, uint64_t* vmAddr) const;
195
196 // Get all the out of band rebase targets. Used for the kernel collection builder
197 // to emit the classic relocations
198 std::vector<void*> getRebaseTargets() const;
199
200 private:
201
202 enum {
203 #if BUILDING_APP_CACHE_UTIL
204 // The x86_64 kernel collection needs 1-byte aligned fixups
205 kMinimumFixupAlignment = 1
206 #else
207 // Shared cache fixups must be at least 4-byte aligned
208 kMinimumFixupAlignment = 4
209 #endif
210 };
211
212 uint8_t* _regionStart = nullptr;
213 uint8_t* _regionEnd = nullptr;
214 bool* _bitmap = nullptr;
215 unsigned _pageCount = 0;
216 unsigned _pageSize = 4096;
217 bool _enabled = true;
218
219 struct AuthData {
220 uint16_t diversity;
221 bool addrDiv;
222 uint8_t key;
223 };
224 std::unordered_map<void*, uint8_t> _high8Map;
225 std::unordered_map<void*, AuthData> _authDataMap;
226 std::unordered_map<void*, uint32_t> _rebaseTarget32;
227 std::unordered_map<void*, uint64_t> _rebaseTarget64;
228
229 // For kernel collections to work out which other collection a given
230 // fixup is relative to
231 #if BUILDING_APP_CACHE_UTIL
232 uint8_t* _cacheLevels = nullptr;
233 #endif
234 };
235
236 typedef std::map<uint64_t, std::set<void*>> LOH_Tracker;
237
238 // For use by the LinkeditOptimizer to work out which symbols to strip on each binary
239 enum class DylibStripMode {
240 stripNone,
241 stripLocals,
242 stripExports,
243 stripAll
244 };
245
246 struct DylibInfo
247 {
248 const LoadedMachO* input;
249 std::string dylibID;
250 std::vector<SegmentMappingInfo> cacheLocation;
251 DylibTextCoalescer textCoalescer;
252
253 // <class name, metaclass> -> pointer
254 std::unordered_map<IMPCaches::ClassKey, std::unique_ptr<IMPCaches::ClassData>, IMPCaches::ClassKeyHasher> impCachesClassData;
255 };
256
257 protected:
258 template <typename P>
259 friend class LinkeditOptimizer;
260
261 struct UnmappedRegion
262 {
263 uint8_t* buffer = nullptr;
264 uint64_t bufferSize = 0;
265 uint64_t sizeInUse = 0;
266 };
267
268 // Virtual methods overridden by the shared cache builder and app cache builder
269 virtual void forEachDylibInfo(void (^callback)(const DylibInfo& dylib, Diagnostics& dylibDiag)) = 0;
270
271 void copyRawSegments();
272 void adjustAllImagesForNewSegmentLocations(uint64_t cacheBaseAddress,
273 ASLR_Tracker& aslrTracker, LOH_Tracker* lohTracker,
274 const CacheBuilder::CacheCoalescedText* coalescedText);
275
276 // implemented in AdjustDylibSegemnts.cpp
277 void adjustDylibSegments(const DylibInfo& dylib, Diagnostics& diag,
278 uint64_t cacheBaseAddress,
279 CacheBuilder::ASLR_Tracker& aslrTracker,
280 CacheBuilder::LOH_Tracker* lohTracker,
281 const CacheBuilder::CacheCoalescedText* coalescedText) const;
282
283 // implemented in OptimizerLinkedit.cpp
284 void optimizeLinkedit(UnmappedRegion* localSymbolsRegion,
285 const std::vector<std::tuple<const mach_header*, const char*, DylibStripMode>>& images);
286
287 // implemented in OptimizerBranches.cpp
288 void optimizeAwayStubs(const std::vector<std::pair<const mach_header*, const char*>>& images,
289 int64_t cacheSlide, uint64_t cacheUnslidAddr,
290 const DyldSharedCache* dyldCache,
291 const char* const neverStubEliminateSymbols[]);
292
293 const DyldSharedCache::CreateOptions& _options;
294 const dyld3::closure::FileSystem& _fileSystem;
295 Region _readExecuteRegion;
296 Region _readOnlyRegion;
297 UnmappedRegion _localSymbolsRegion;
298 vm_address_t _fullAllocatedBuffer;
299 uint64_t _nonLinkEditReadOnlySize;
300 Diagnostics _diagnostics;
301 TimeRecorder _timeRecorder;
302 uint64_t _allocatedBufferSize;
303 CacheCoalescedText _coalescedText;
304 bool _is64 = false;
305 // Note this is mutable as the only parallel writes to it are done atomically to the bitmap
306 mutable ASLR_Tracker _aslrTracker;
307 mutable LOH_Tracker _lohTracker;
308 };
309
310 inline uint64_t align(uint64_t addr, uint8_t p2)
311 {
312 uint64_t mask = (1 << p2);
313 return (addr + mask - 1) & (-mask);
314 }
315
316 inline uint8_t* align_buffer(uint8_t* addr, uint8_t p2)
317 {
318 return (uint8_t *)align((uintptr_t)addr, p2);
319 }
320
321
322 #endif /* CacheBuilder_h */