dyld-750.5.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 std::string errorMessage();
73
74 struct SegmentMappingInfo {
75 const void* srcSegment;
76 const char* segName;
77 void* dstSegment;
78 uint64_t dstCacheUnslidAddress;
79 uint32_t dstCacheFileOffset;
80 uint32_t dstCacheSegmentSize;
81 uint32_t dstCacheFileSize;
82 uint32_t copySegmentSize;
83 uint32_t srcSegmentIndex;
84 };
85
86 struct DylibTextCoalescer {
87
88 typedef std::map<uint32_t, uint32_t> DylibSectionOffsetToCacheSectionOffset;
89
90 DylibSectionOffsetToCacheSectionOffset objcClassNames;
91 DylibSectionOffsetToCacheSectionOffset objcMethNames;
92 DylibSectionOffsetToCacheSectionOffset objcMethTypes;
93
94 bool sectionWasCoalesced(std::string_view sectionName) const;
95 DylibSectionOffsetToCacheSectionOffset& getSectionCoalescer(std::string_view sectionName);
96 const DylibSectionOffsetToCacheSectionOffset& getSectionCoalescer(std::string_view sectionName) const;
97 };
98
99 struct CacheCoalescedText {
100 static const char* SupportedSections[3];
101 struct StringSection {
102 // Map from class name strings to offsets in to the class names buffer
103 std::map<std::string_view, uint32_t> stringsToOffsets;
104 uint8_t* bufferAddr = nullptr;
105 uint32_t bufferSize = 0;
106 uint64_t bufferVMAddr = 0;
107
108 // Note this is for debugging only
109 uint64_t savedSpace = 0;
110 };
111
112 StringSection objcClassNames;
113 StringSection objcMethNames;
114 StringSection objcMethTypes;
115
116 void parseCoalescableText(const dyld3::MachOAnalyzer* ma,
117 DylibTextCoalescer& textCoalescer);
118 void clear();
119
120 StringSection& getSectionData(std::string_view sectionName);
121 const StringSection& getSectionData(std::string_view sectionName) const;
122 };
123
124 class ASLR_Tracker
125 {
126 public:
127 ~ASLR_Tracker();
128
129 void setDataRegion(const void* rwRegionStart, size_t rwRegionSize);
130 void add(void* p);
131 void setHigh8(void* p, uint8_t high8);
132 void setAuthData(void* p, uint16_t diversity, bool hasAddrDiv, uint8_t key);
133 void setRebaseTarget32(void*p, uint32_t targetVMAddr);
134 void setRebaseTarget64(void*p, uint64_t targetVMAddr);
135 void remove(void* p);
136 bool has(void* p);
137 const bool* bitmap() { return _bitmap; }
138 unsigned dataPageCount() { return _pageCount; }
139 void disable() { _enabled = false; };
140 bool hasHigh8(void* p, uint8_t* highByte);
141 bool hasAuthData(void* p, uint16_t* diversity, bool* hasAddrDiv, uint8_t* key);
142 bool hasRebaseTarget32(void* p, uint32_t* vmAddr);
143 bool hasRebaseTarget64(void* p, uint64_t* vmAddr);
144
145 private:
146
147 uint8_t* _regionStart = nullptr;
148 uint8_t* _regionEnd = nullptr;
149 bool* _bitmap = nullptr;
150 unsigned _pageCount = 0;
151 unsigned _pageSize = 4096;
152 bool _enabled = true;
153
154 struct AuthData {
155 uint16_t diversity;
156 bool addrDiv;
157 uint8_t key;
158 };
159 std::unordered_map<void*, uint8_t> _high8Map;
160 std::unordered_map<void*, AuthData> _authDataMap;
161 std::unordered_map<void*, uint32_t> _rebaseTarget32;
162 std::unordered_map<void*, uint64_t> _rebaseTarget64;
163 };
164
165 typedef std::map<uint64_t, std::set<void*>> LOH_Tracker;
166
167 static const uint64_t kRebaseTargetInSideTableArm64e = 0x7FFFFFFFFFFULL;
168 static const uint64_t kRebaseTargetInSideTableArm64 = 0xFFFFFFFFFULL;
169 static const uint64_t kRebaseTargetInSideTableGeneric32 = 0x3FFFFFFULL;
170
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 protected:
182 template <typename P>
183 friend class LinkeditOptimizer;
184
185 struct UnmappedRegion
186 {
187 uint8_t* buffer = nullptr;
188 uint64_t bufferSize = 0;
189 uint64_t sizeInUse = 0;
190 };
191
192 struct DylibInfo
193 {
194 const LoadedMachO* input;
195 std::string runtimePath;
196 std::vector<SegmentMappingInfo> cacheLocation;
197 DylibTextCoalescer textCoalescer;
198 };
199
200 void copyRawSegments();
201 void adjustAllImagesForNewSegmentLocations();
202
203 // implemented in AdjustDylibSegemnts.cpp
204 void adjustDylibSegments(const DylibInfo& dylib, Diagnostics& diag) const;
205
206 // implemented in OptimizerLinkedit.cpp
207 void optimizeLinkedit();
208
209 const DyldSharedCache::CreateOptions& _options;
210 const dyld3::closure::FileSystem& _fileSystem;
211 Region _readExecuteRegion;
212 Region _readWriteRegion;
213 Region _readOnlyRegion;
214 UnmappedRegion _localSymbolsRegion;
215 vm_address_t _fullAllocatedBuffer;
216 uint64_t _nonLinkEditReadOnlySize;
217 Diagnostics _diagnostics;
218 uint64_t _allocatedBufferSize;
219 std::vector<DylibInfo> _sortedDylibs;
220 CacheCoalescedText _coalescedText;
221 uint32_t _sharedStringsPoolVmOffset = 0;
222 bool _is64 = false;
223 // Note this is mutable as the only parallel writes to it are done atomically to the bitmap
224 mutable ASLR_Tracker _aslrTracker;
225 mutable LOH_Tracker _lohTracker;
226 };
227
228
229
230
231 inline uint64_t align(uint64_t addr, uint8_t p2)
232 {
233 uint64_t mask = (1 << p2);
234 return (addr + mask - 1) & (-mask);
235 }
236
237
238
239 #endif /* CacheBuilder_h */