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;
84 uint64_t index
= ~0ULL; // The index of this region in the final binary
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;
93 struct SegmentMappingInfo
{
94 const void* srcSegment
;
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;
107 struct DylibTextCoalescer
{
109 typedef std::map
<uint32_t, uint32_t> DylibSectionOffsetToCacheSectionOffset
;
111 DylibSectionOffsetToCacheSectionOffset objcClassNames
;
112 DylibSectionOffsetToCacheSectionOffset objcMethNames
;
113 DylibSectionOffsetToCacheSectionOffset objcMethTypes
;
115 DylibSectionOffsetToCacheSectionOffset cfStrings
;
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;
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;
132 // Note this is for debugging only
133 uint64_t savedSpace
= 0;
137 uint8_t* bufferAddr
= nullptr;
138 uint32_t bufferSize
= 0;
139 uint64_t bufferVMAddr
= 0;
140 uint64_t cacheFileOffset
= 0;
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;
148 StringSection objcClassNames
;
149 StringSection objcMethNames
;
150 StringSection objcMethTypes
;
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
);
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;
172 ASLR_Tracker() = default;
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;
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;
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;
204 #if BUILDING_APP_CACHE_UTIL
205 // The x86_64 kernel collection needs 1-byte aligned fixups
206 kMinimumFixupAlignment
= 1
208 // Shared cache fixups must be at least 4-byte aligned
209 kMinimumFixupAlignment
= 4
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;
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
;
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;
237 typedef std::map
<uint64_t, std::set
<void*>> LOH_Tracker
;
239 // For use by the LinkeditOptimizer to work out which symbols to strip on each binary
240 enum class DylibStripMode
{
249 const LoadedMachO
* input
;
251 std::vector
<SegmentMappingInfo
> cacheLocation
;
252 DylibTextCoalescer textCoalescer
;
254 // <class name, metaclass> -> pointer
255 std::unordered_map
<IMPCaches::ClassKey
, std::unique_ptr
<IMPCaches::ClassData
>, IMPCaches::ClassKeyHasher
> impCachesClassData
;
259 template <typename P
>
260 friend class LinkeditOptimizer
;
262 struct UnmappedRegion
264 uint8_t* buffer
= nullptr;
265 uint64_t bufferSize
= 0;
266 uint64_t sizeInUse
= 0;
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;
272 void copyRawSegments();
273 void adjustAllImagesForNewSegmentLocations(uint64_t cacheBaseAddress
,
274 ASLR_Tracker
& aslrTracker
, LOH_Tracker
* lohTracker
,
275 const CacheBuilder::CacheCoalescedText
* coalescedText
);
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;
284 // implemented in OptimizerLinkedit.cpp
285 void optimizeLinkedit(UnmappedRegion
* localSymbolsRegion
,
286 const std::vector
<std::tuple
<const mach_header
*, const char*, DylibStripMode
>>& images
);
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
[]);
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
;
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
;
311 inline uint64_t align(uint64_t addr
, uint8_t p2
)
313 uint64_t mask
= (1 << p2
);
314 return (addr
+ mask
- 1) & (-mask
);
317 inline uint8_t* align_buffer(uint8_t* addr
, uint8_t p2
)
319 return (uint8_t *)align((uintptr_t)addr
, p2
);
323 #endif /* CacheBuilder_h */