2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #ifndef CacheBuilder_h
26 #define CacheBuilder_h
31 #include <unordered_map>
32 #include <unordered_set>
34 #include "ClosureFileSystem.h"
35 #include "DyldSharedCache.h"
36 #include "Diagnostics.h"
37 #include "MachOAnalyzer.h"
38 #include "IMPCaches.hpp"
40 template <typename P
> class LinkeditOptimizer
;
45 CacheBuilder(const DyldSharedCache::CreateOptions
& options
, const dyld3::closure::FileSystem
& fileSystem
);
46 virtual ~CacheBuilder();
52 MustBeIncludedForDependent
,
53 MustBeExcludedIfUnused
55 InputFile(const char* path
, State state
) : path(path
), state(state
) { }
60 bool mustBeIncluded() const {
61 return (state
== MustBeIncluded
) || (state
== MustBeIncludedForDependent
);
65 // Contains a MachO which has been loaded from the file system and may potentially need to be unloaded later.
67 DyldSharedCache::MappedMachO mappedFile
;
68 dyld3::closure::LoadedFileInfo loadedFileInfo
;
72 std::string
errorMessage();
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;
83 uint64_t index
= ~0ULL; // The index of this region in the final binary
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;
92 struct SegmentMappingInfo
{
93 const void* srcSegment
;
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;
106 struct DylibTextCoalescer
{
108 typedef std::map
<uint32_t, uint32_t> DylibSectionOffsetToCacheSectionOffset
;
110 DylibSectionOffsetToCacheSectionOffset objcClassNames
;
111 DylibSectionOffsetToCacheSectionOffset objcMethNames
;
112 DylibSectionOffsetToCacheSectionOffset objcMethTypes
;
114 DylibSectionOffsetToCacheSectionOffset cfStrings
;
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;
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;
131 // Note this is for debugging only
132 uint64_t savedSpace
= 0;
136 uint8_t* bufferAddr
= nullptr;
137 uint32_t bufferSize
= 0;
138 uint64_t bufferVMAddr
= 0;
139 uint64_t cacheFileOffset
= 0;
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;
147 StringSection objcClassNames
;
148 StringSection objcMethNames
;
149 StringSection objcMethTypes
;
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
);
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;
171 ASLR_Tracker() = default;
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;
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;
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;
203 #if BUILDING_APP_CACHE_UTIL
204 // The x86_64 kernel collection needs 1-byte aligned fixups
205 kMinimumFixupAlignment
= 1
207 // Shared cache fixups must be at least 4-byte aligned
208 kMinimumFixupAlignment
= 4
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;
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
;
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;
236 typedef std::map
<uint64_t, std::set
<void*>> LOH_Tracker
;
238 // For use by the LinkeditOptimizer to work out which symbols to strip on each binary
239 enum class DylibStripMode
{
248 const LoadedMachO
* input
;
250 std::vector
<SegmentMappingInfo
> cacheLocation
;
251 DylibTextCoalescer textCoalescer
;
253 // <class name, metaclass> -> pointer
254 std::unordered_map
<IMPCaches::ClassKey
, std::unique_ptr
<IMPCaches::ClassData
>, IMPCaches::ClassKeyHasher
> impCachesClassData
;
258 template <typename P
>
259 friend class LinkeditOptimizer
;
261 struct UnmappedRegion
263 uint8_t* buffer
= nullptr;
264 uint64_t bufferSize
= 0;
265 uint64_t sizeInUse
= 0;
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;
271 void copyRawSegments();
272 void adjustAllImagesForNewSegmentLocations(uint64_t cacheBaseAddress
,
273 ASLR_Tracker
& aslrTracker
, LOH_Tracker
* lohTracker
,
274 const CacheBuilder::CacheCoalescedText
* coalescedText
);
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;
283 // implemented in OptimizerLinkedit.cpp
284 void optimizeLinkedit(UnmappedRegion
* localSymbolsRegion
,
285 const std::vector
<std::tuple
<const mach_header
*, const char*, DylibStripMode
>>& images
);
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
[]);
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
;
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
;
310 inline uint64_t align(uint64_t addr
, uint8_t p2
)
312 uint64_t mask
= (1 << p2
);
313 return (addr
+ mask
- 1) & (-mask
);
316 inline uint8_t* align_buffer(uint8_t* addr
, uint8_t p2
)
318 return (uint8_t *)align((uintptr_t)addr
, p2
);
322 #endif /* CacheBuilder_h */