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