1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 * Copyright (c) 2014 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/errno.h>
28 #include <sys/fcntl.h>
29 #include <mach-o/loader.h>
30 #include <mach-o/fat.h>
36 #include <unordered_map>
37 #include <unordered_set>
39 #include "CacheBuilder.h"
40 #include "Diagnostics.h"
41 #include "DyldSharedCache.h"
43 #include "MachOFileAbstraction.hpp"
44 #include "MachOLoaded.h"
45 #include "MachOAnalyzer.h"
46 #include "mach-o/fixup-chains.h"
49 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
50 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
58 Adjustor(DyldSharedCache
* cacheBuffer
, macho_header
<P
>* mh
, const std::vector
<CacheBuilder::SegmentMappingInfo
>& mappingInfo
, Diagnostics
& diag
);
59 void adjustImageForNewSegmentLocations(CacheBuilder::ASLR_Tracker
& aslrTracker
,
60 CacheBuilder::LOH_Tracker
& lohTracker
,
61 const CacheBuilder::CacheCoalescedText
& coalescedText
,
62 const CacheBuilder::DylibTextCoalescer
& textCoalescer
);
65 void adjustReferencesUsingInfoV2(CacheBuilder::ASLR_Tracker
& aslrTracker
, CacheBuilder::LOH_Tracker
& lohTracker
,
66 const CacheBuilder::CacheCoalescedText
& coalescedText
,
67 const CacheBuilder::DylibTextCoalescer
& textCoalescer
);
68 void adjustReference(uint32_t kind
, uint8_t* mappedAddr
, uint64_t fromNewAddress
, uint64_t toNewAddress
, int64_t adjust
, int64_t targetSlide
,
69 uint64_t imageStartAddress
, uint64_t imageEndAddress
,
70 CacheBuilder::ASLR_Tracker
& aslrTracker
, CacheBuilder::LOH_Tracker
* lohTracker
,
71 uint32_t*& lastMappedAddr32
, uint32_t& lastKind
, uint64_t& lastToNewAddress
);
72 void adjustDataPointers(CacheBuilder::ASLR_Tracker
& aslrTracker
);
73 void adjustRebaseChains(CacheBuilder::ASLR_Tracker
& aslrTracker
);
74 void slidePointer(int segIndex
, uint64_t segOffset
, uint8_t type
, CacheBuilder::ASLR_Tracker
& aslrTracker
);
75 void adjustSymbolTable();
76 void adjustChainedFixups();
77 void adjustExportsTrie(std::vector
<uint8_t>& newTrieBytes
);
78 void rebuildLinkEdit();
80 void adjustInstruction(uint8_t kind
, uint8_t* textLoc
, uint64_t codeToDataDelta
);
81 void rebuildLinkEditAndLoadCommands(const CacheBuilder::DylibTextCoalescer
& textCoalescer
);
82 uint64_t slideForOrigAddress(uint64_t addr
);
83 void convertGeneric64RebaseToIntermediate(dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* chainPtr
, CacheBuilder::ASLR_Tracker
& aslrTracker
, uint64_t targetSlide
);
84 void convertArm64eRebaseToIntermediate(dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* chainPtr
, CacheBuilder::ASLR_Tracker
& aslrTracker
, uint64_t targetSlide
);
87 typedef typename
P::uint_t pint_t
;
88 typedef typename
P::E E
;
90 DyldSharedCache
* _cacheBuffer
;
92 Diagnostics
& _diagnostics
;
93 const uint8_t* _linkeditBias
= nullptr;
94 unsigned _linkeditSegIndex
= 0;
95 bool _maskPointers
= false;
96 bool _splitSegInfoV2
= false;
97 const char* _installName
= nullptr;
98 macho_symtab_command
<P
>* _symTabCmd
= nullptr;
99 macho_dysymtab_command
<P
>* _dynSymTabCmd
= nullptr;
100 macho_dyld_info_command
<P
>* _dyldInfo
= nullptr;
101 macho_linkedit_data_command
<P
>* _splitSegInfoCmd
= nullptr;
102 macho_linkedit_data_command
<P
>* _functionStartsCmd
= nullptr;
103 macho_linkedit_data_command
<P
>* _dataInCodeCmd
= nullptr;
104 macho_linkedit_data_command
<P
>* _exportTrieCmd
= nullptr;
105 macho_linkedit_data_command
<P
>* _chainedFixupsCmd
= nullptr;
106 uint16_t _chainedFixupsFormat
= 0;
107 std::vector
<uint64_t> _segOrigStartAddresses
;
108 std::vector
<uint64_t> _segSlides
;
109 std::vector
<macho_segment_command
<P
>*> _segCmds
;
110 const std::vector
<CacheBuilder::SegmentMappingInfo
>& _mappingInfo
;
113 template <typename P
>
114 Adjustor
<P
>::Adjustor(DyldSharedCache
* cacheBuffer
, macho_header
<P
>* mh
, const std::vector
<CacheBuilder::SegmentMappingInfo
>& mappingInfo
, Diagnostics
& diag
)
115 : _cacheBuffer(cacheBuffer
), _mh(mh
), _diagnostics(diag
), _mappingInfo(mappingInfo
)
117 assert((mh
->magic() == MH_MAGIC
) || (mh
->magic() == MH_MAGIC_64
));
118 macho_segment_command
<P
>* segCmd
;
119 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)mh
+ sizeof(macho_header
<P
>));
120 const uint32_t cmd_count
= mh
->ncmds();
121 const macho_load_command
<P
>* cmd
= cmds
;
122 unsigned segIndex
= 0;
123 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
124 switch (cmd
->cmd()) {
126 _installName
= ((macho_dylib_command
<P
>*)cmd
)->name();
129 _symTabCmd
= (macho_symtab_command
<P
>*)cmd
;
132 _dynSymTabCmd
= (macho_dysymtab_command
<P
>*)cmd
;
135 case LC_DYLD_INFO_ONLY
:
136 _dyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
138 case LC_SEGMENT_SPLIT_INFO
:
139 _splitSegInfoCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
141 case LC_FUNCTION_STARTS
:
142 _functionStartsCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
144 case LC_DATA_IN_CODE
:
145 _dataInCodeCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
147 case LC_DYLD_CHAINED_FIXUPS
:
148 _chainedFixupsCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
149 _chainedFixupsFormat
= dyld3::MachOAnalyzer::chainedPointerFormat((dyld_chained_fixups_header
*)&_linkeditBias
[_chainedFixupsCmd
->dataoff()]);
151 case LC_DYLD_EXPORTS_TRIE
:
152 _exportTrieCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
154 case macho_segment_command
<P
>::CMD
:
155 segCmd
= (macho_segment_command
<P
>*)cmd
;
156 _segCmds
.push_back(segCmd
);
157 _segOrigStartAddresses
.push_back(segCmd
->vmaddr());
158 _segSlides
.push_back(_mappingInfo
[segIndex
].dstCacheUnslidAddress
- segCmd
->vmaddr());
159 if ( strcmp(segCmd
->segname(), "__LINKEDIT") == 0 ) {
160 _linkeditBias
= (uint8_t*)_mappingInfo
[segIndex
].dstSegment
- segCmd
->fileoff();
161 _linkeditSegIndex
= segIndex
;
166 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
168 _maskPointers
= (P::E::get32(mh
->cputype()) == CPU_TYPE_ARM64
) || (P::E::get32(mh
->cputype()) == CPU_TYPE_ARM64_32
);
169 if ( _splitSegInfoCmd
!= NULL
) {
170 const uint8_t* infoStart
= &_linkeditBias
[_splitSegInfoCmd
->dataoff()];
171 _splitSegInfoV2
= (*infoStart
== DYLD_CACHE_ADJ_V2_FORMAT
);
174 _diagnostics
.error("missing LC_SEGMENT_SPLIT_INFO in %s", _installName
);
178 template <typename P
>
179 void Adjustor
<P
>::adjustImageForNewSegmentLocations(CacheBuilder::ASLR_Tracker
& aslrTracker
,
180 CacheBuilder::LOH_Tracker
& lohTracker
,
181 const CacheBuilder::CacheCoalescedText
& coalescedText
,
182 const CacheBuilder::DylibTextCoalescer
& textCoalescer
)
184 if ( _diagnostics
.hasError() )
186 if ( _splitSegInfoV2
) {
187 adjustReferencesUsingInfoV2(aslrTracker
, lohTracker
, coalescedText
, textCoalescer
);
188 adjustChainedFixups();
190 else if ( _chainedFixupsCmd
!= nullptr ) {
191 // need to adjust the chain fixup segment_offset fields in LINKEDIT before chains can be walked
192 adjustChainedFixups();
193 adjustRebaseChains(aslrTracker
);
197 adjustDataPointers(aslrTracker
);
200 if ( _diagnostics
.hasError() )
203 if ( _diagnostics
.hasError() )
205 if ( _diagnostics
.hasError() )
207 rebuildLinkEditAndLoadCommands(textCoalescer
);
211 ((dyld3::MachOAnalyzer
*)_mh
)->validateDyldCacheDylib(diag
, _installName
);
212 if ( diag
.hasError() ) {
213 fprintf(stderr
, "%s\n", diag
.errorMessage().c_str());
218 template <typename P
>
219 uint64_t Adjustor
<P
>::slideForOrigAddress(uint64_t addr
)
221 for (unsigned i
=0; i
< _segOrigStartAddresses
.size(); ++i
) {
222 if ( (_segOrigStartAddresses
[i
] <= addr
) && (addr
< (_segOrigStartAddresses
[i
]+_segCmds
[i
]->vmsize())) )
223 return _segSlides
[i
];
225 // On arm64, high nibble of pointers can have extra bits
226 if ( _maskPointers
&& (addr
& 0xF000000000000000) ) {
227 return slideForOrigAddress(addr
& 0x0FFFFFFFFFFFFFFF);
229 _diagnostics
.error("slide not known for dylib address 0x%llX in %s", addr
, _installName
);
233 template <typename P
>
234 void Adjustor
<P
>::rebuildLinkEditAndLoadCommands(const CacheBuilder::DylibTextCoalescer
& textCoalescer
)
236 // Exports trie is only data structure in LINKEDIT that might grow
237 std::vector
<uint8_t> newTrieBytes
;
238 adjustExportsTrie(newTrieBytes
);
240 // Remove: code signature, rebase info, code-sign-dirs, split seg info
241 uint32_t chainedFixupsOffset
= 0;
242 uint32_t chainedFixupsSize
= _chainedFixupsCmd
? _chainedFixupsCmd
->datasize() : 0;
243 uint32_t bindOffset
= chainedFixupsOffset
+ chainedFixupsSize
;
244 uint32_t bindSize
= _dyldInfo
? _dyldInfo
->bind_size() : 0;
245 uint32_t weakBindOffset
= bindOffset
+ bindSize
;
246 uint32_t weakBindSize
= _dyldInfo
? _dyldInfo
->weak_bind_size() : 0;
247 uint32_t lazyBindOffset
= weakBindOffset
+ weakBindSize
;
248 uint32_t lazyBindSize
= _dyldInfo
? _dyldInfo
->lazy_bind_size() : 0;
249 uint32_t exportOffset
= lazyBindOffset
+ lazyBindSize
;
250 uint32_t exportSize
= (uint32_t)newTrieBytes
.size();
251 uint32_t splitSegInfoOffset
= exportOffset
+ exportSize
;
252 uint32_t splitSegInfosSize
= (_splitSegInfoCmd
? _splitSegInfoCmd
->datasize() : 0);
253 uint32_t funcStartsOffset
= splitSegInfoOffset
+ splitSegInfosSize
;
254 uint32_t funcStartsSize
= (_functionStartsCmd
? _functionStartsCmd
->datasize() : 0);
255 uint32_t dataInCodeOffset
= funcStartsOffset
+ funcStartsSize
;
256 uint32_t dataInCodeSize
= (_dataInCodeCmd
? _dataInCodeCmd
->datasize() : 0);
257 uint32_t symbolTableOffset
= dataInCodeOffset
+ dataInCodeSize
;
258 uint32_t symbolTableSize
= _symTabCmd
->nsyms() * sizeof(macho_nlist
<P
>);
259 uint32_t indirectTableOffset
= symbolTableOffset
+ symbolTableSize
;
260 uint32_t indirectTableSize
= _dynSymTabCmd
->nindirectsyms() * sizeof(uint32_t);
261 uint32_t symbolStringsOffset
= indirectTableOffset
+ indirectTableSize
;
262 uint32_t symbolStringsSize
= _symTabCmd
->strsize();
263 uint32_t newLinkEditSize
= symbolStringsOffset
+ symbolStringsSize
;
265 size_t linkeditBufferSize
= align(_segCmds
[_linkeditSegIndex
]->vmsize(), 12);
266 if ( linkeditBufferSize
< newLinkEditSize
) {
267 _diagnostics
.error("LINKEDIT overflow in %s", _installName
);
271 uint8_t* newLinkeditBufer
= (uint8_t*)::calloc(linkeditBufferSize
, 1);
272 if ( chainedFixupsSize
)
273 memcpy(&newLinkeditBufer
[chainedFixupsOffset
], &_linkeditBias
[_chainedFixupsCmd
->dataoff()], chainedFixupsSize
);
275 memcpy(&newLinkeditBufer
[bindOffset
], &_linkeditBias
[_dyldInfo
->bind_off()], bindSize
);
277 memcpy(&newLinkeditBufer
[lazyBindOffset
], &_linkeditBias
[_dyldInfo
->lazy_bind_off()], lazyBindSize
);
279 memcpy(&newLinkeditBufer
[weakBindOffset
], &_linkeditBias
[_dyldInfo
->weak_bind_off()], weakBindSize
);
281 memcpy(&newLinkeditBufer
[exportOffset
], &newTrieBytes
[0], exportSize
);
282 if ( splitSegInfosSize
)
283 memcpy(&newLinkeditBufer
[splitSegInfoOffset
], &_linkeditBias
[_splitSegInfoCmd
->dataoff()], splitSegInfosSize
);
284 if ( funcStartsSize
)
285 memcpy(&newLinkeditBufer
[funcStartsOffset
], &_linkeditBias
[_functionStartsCmd
->dataoff()], funcStartsSize
);
286 if ( dataInCodeSize
)
287 memcpy(&newLinkeditBufer
[dataInCodeOffset
], &_linkeditBias
[_dataInCodeCmd
->dataoff()], dataInCodeSize
);
288 if ( symbolTableSize
)
289 memcpy(&newLinkeditBufer
[symbolTableOffset
], &_linkeditBias
[_symTabCmd
->symoff()], symbolTableSize
);
290 if ( indirectTableSize
)
291 memcpy(&newLinkeditBufer
[indirectTableOffset
], &_linkeditBias
[_dynSymTabCmd
->indirectsymoff()], indirectTableSize
);
292 if ( symbolStringsSize
)
293 memcpy(&newLinkeditBufer
[symbolStringsOffset
], &_linkeditBias
[_symTabCmd
->stroff()], symbolStringsSize
);
295 memcpy(_mappingInfo
[_linkeditSegIndex
].dstSegment
, newLinkeditBufer
, newLinkEditSize
);
296 ::bzero(((uint8_t*)_mappingInfo
[_linkeditSegIndex
].dstSegment
)+newLinkEditSize
, linkeditBufferSize
-newLinkEditSize
);
297 ::free(newLinkeditBufer
);
298 uint32_t linkeditStartOffset
= (uint32_t)_mappingInfo
[_linkeditSegIndex
].dstCacheFileOffset
;
300 // updates load commands and removed ones no longer needed
301 macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)_mh
+ sizeof(macho_header
<P
>));
302 uint32_t cmd_count
= _mh
->ncmds();
303 const macho_load_command
<P
>* cmd
= cmds
;
304 const unsigned origLoadCommandsSize
= _mh
->sizeofcmds();
305 unsigned bytesRemaining
= origLoadCommandsSize
;
306 unsigned removedCount
= 0;
307 unsigned segIndex
= 0;
308 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
309 macho_symtab_command
<P
>* symTabCmd
;
310 macho_dysymtab_command
<P
>* dynSymTabCmd
;
311 macho_dyld_info_command
<P
>* dyldInfo
;
312 macho_linkedit_data_command
<P
>* functionStartsCmd
;
313 macho_linkedit_data_command
<P
>* dataInCodeCmd
;
314 macho_linkedit_data_command
<P
>* chainedFixupsCmd
;
315 macho_linkedit_data_command
<P
>* exportTrieCmd
;
316 macho_linkedit_data_command
<P
>* splitSegInfoCmd
;
317 macho_segment_command
<P
>* segCmd
;
318 macho_routines_command
<P
>* routinesCmd
;
319 macho_dylib_command
<P
>* dylibIDCmd
;
320 uint32_t cmdSize
= cmd
->cmdsize();
321 int32_t segFileOffsetDelta
;
323 switch ( cmd
->cmd() ) {
325 dylibIDCmd
= (macho_dylib_command
<P
>*)cmd
;
326 dylibIDCmd
->set_timestamp(2); // match what static linker sets in LC_LOAD_DYLIB
329 symTabCmd
= (macho_symtab_command
<P
>*)cmd
;
330 symTabCmd
->set_symoff(linkeditStartOffset
+symbolTableOffset
);
331 symTabCmd
->set_stroff(linkeditStartOffset
+symbolStringsOffset
);
334 dynSymTabCmd
= (macho_dysymtab_command
<P
>*)cmd
;
335 dynSymTabCmd
->set_indirectsymoff(linkeditStartOffset
+indirectTableOffset
);
338 case LC_DYLD_INFO_ONLY
:
339 dyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
340 dyldInfo
->set_rebase_off(0);
341 dyldInfo
->set_rebase_size(0);
342 dyldInfo
->set_bind_off(bindSize
? linkeditStartOffset
+bindOffset
: 0);
343 dyldInfo
->set_bind_size(bindSize
);
344 dyldInfo
->set_weak_bind_off(weakBindSize
? linkeditStartOffset
+weakBindOffset
: 0);
345 dyldInfo
->set_weak_bind_size(weakBindSize
);
346 dyldInfo
->set_lazy_bind_off(lazyBindSize
? linkeditStartOffset
+lazyBindOffset
: 0);
347 dyldInfo
->set_lazy_bind_size(lazyBindSize
);
348 dyldInfo
->set_export_off(exportSize
? linkeditStartOffset
+exportOffset
: 0);
349 dyldInfo
->set_export_size(exportSize
);
351 case LC_FUNCTION_STARTS
:
352 functionStartsCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
353 functionStartsCmd
->set_dataoff(linkeditStartOffset
+funcStartsOffset
);
355 case LC_DATA_IN_CODE
:
356 dataInCodeCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
357 dataInCodeCmd
->set_dataoff(linkeditStartOffset
+dataInCodeOffset
);
359 case LC_DYLD_CHAINED_FIXUPS
:
360 chainedFixupsCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
361 chainedFixupsCmd
->set_dataoff(chainedFixupsSize
? linkeditStartOffset
+chainedFixupsOffset
: 0);
362 chainedFixupsCmd
->set_datasize(chainedFixupsSize
);
364 case LC_DYLD_EXPORTS_TRIE
:
365 exportTrieCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
366 exportTrieCmd
->set_dataoff(exportSize
? linkeditStartOffset
+exportOffset
: 0);
367 exportTrieCmd
->set_datasize(exportSize
);
369 case macho_routines_command
<P
>::CMD
:
370 routinesCmd
= (macho_routines_command
<P
>*)cmd
;
371 routinesCmd
->set_init_address(routinesCmd
->init_address()+slideForOrigAddress(routinesCmd
->init_address()));
373 case macho_segment_command
<P
>::CMD
:
374 segCmd
= (macho_segment_command
<P
>*)cmd
;
375 segFileOffsetDelta
= (int32_t)(_mappingInfo
[segIndex
].dstCacheFileOffset
- segCmd
->fileoff());
376 segCmd
->set_vmaddr(_mappingInfo
[segIndex
].dstCacheUnslidAddress
);
377 segCmd
->set_vmsize(_mappingInfo
[segIndex
].dstCacheSegmentSize
);
378 segCmd
->set_fileoff(_mappingInfo
[segIndex
].dstCacheFileOffset
);
379 segCmd
->set_filesize(_mappingInfo
[segIndex
].dstCacheFileSize
);
380 if ( strcmp(segCmd
->segname(), "__LINKEDIT") == 0 )
381 segCmd
->set_vmsize(linkeditBufferSize
);
382 if ( segCmd
->nsects() > 0 ) {
383 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((uint8_t*)segCmd
+ sizeof(macho_segment_command
<P
>));
384 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
386 for (macho_section
<P
>* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
387 if ( (strcmp(segCmd
->segname(), "__TEXT") == 0) && textCoalescer
.sectionWasCoalesced(sect
->sectname())) {
388 // Put coalesced sections at the end of the segment
389 sect
->set_addr(segCmd
->vmaddr() + segCmd
->filesize());
393 sect
->set_addr(sect
->addr() + _segSlides
[segIndex
]);
394 if ( sect
->offset() != 0 )
395 sect
->set_offset(sect
->offset() + segFileOffsetDelta
);
402 _diagnostics
.warning("dyld shared cache does not support LC_RPATH found in %s", _installName
);
405 case LC_SEGMENT_SPLIT_INFO
:
406 splitSegInfoCmd
= (macho_linkedit_data_command
<P
>*)cmd
;
407 splitSegInfoCmd
->set_dataoff(linkeditStartOffset
+splitSegInfoOffset
);
409 case LC_CODE_SIGNATURE
:
410 case LC_DYLIB_CODE_SIGN_DRS
:
416 macho_load_command
<P
>* nextCmd
= (macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmdSize
);
418 ::memmove((void*)cmd
, (void*)nextCmd
, bytesRemaining
);
422 bytesRemaining
-= cmdSize
;
426 // zero out stuff removed
427 ::bzero((void*)cmd
, bytesRemaining
);
429 _mh
->set_ncmds(cmd_count
-removedCount
);
430 _mh
->set_sizeofcmds(origLoadCommandsSize
-bytesRemaining
);
431 _mh
->set_flags(_mh
->flags() | 0x80000000);
435 template <typename P
>
436 void Adjustor
<P
>::adjustSymbolTable()
438 macho_nlist
<P
>* symbolTable
= (macho_nlist
<P
>*)&_linkeditBias
[_symTabCmd
->symoff()];
440 // adjust global symbol table entries
441 macho_nlist
<P
>* lastExport
= &symbolTable
[_dynSymTabCmd
->iextdefsym()+_dynSymTabCmd
->nextdefsym()];
442 for (macho_nlist
<P
>* entry
= &symbolTable
[_dynSymTabCmd
->iextdefsym()]; entry
< lastExport
; ++entry
) {
443 if ( (entry
->n_type() & N_TYPE
) == N_SECT
)
444 entry
->set_n_value(entry
->n_value() + slideForOrigAddress(entry
->n_value()));
447 // adjust local symbol table entries
448 macho_nlist
<P
>* lastLocal
= &symbolTable
[_dynSymTabCmd
->ilocalsym()+_dynSymTabCmd
->nlocalsym()];
449 for (macho_nlist
<P
>* entry
= &symbolTable
[_dynSymTabCmd
->ilocalsym()]; entry
< lastLocal
; ++entry
) {
450 if ( (entry
->n_sect() != NO_SECT
) && ((entry
->n_type() & N_STAB
) == 0) )
451 entry
->set_n_value(entry
->n_value() + slideForOrigAddress(entry
->n_value()));
456 template <typename P
>
457 void Adjustor
<P
>::adjustChainedFixups()
459 if ( _chainedFixupsCmd
== nullptr )
462 // Pass a start hint in to withChainStarts which takes account of the LINKEDIT shifting but we haven't
463 // yet updated that LC_SEGMENT to point to the new data
464 const dyld_chained_fixups_header
* header
= (dyld_chained_fixups_header
*)&_linkeditBias
[_chainedFixupsCmd
->dataoff()];
465 uint64_t startsOffset
= ((uint64_t)header
+ header
->starts_offset
) - (uint64_t)_mh
;
467 // segment_offset in dyld_chained_starts_in_segment is wrong. We need to move it to the new segment offset
468 ((dyld3::MachOAnalyzer
*)_mh
)->withChainStarts(_diagnostics
, startsOffset
, ^(const dyld_chained_starts_in_image
* starts
) {
469 for (uint32_t segIndex
=0; segIndex
< starts
->seg_count
; ++segIndex
) {
470 if ( starts
->seg_info_offset
[segIndex
] == 0 )
472 dyld_chained_starts_in_segment
* segInfo
= (dyld_chained_starts_in_segment
*)((uint8_t*)starts
+ starts
->seg_info_offset
[segIndex
]);
473 segInfo
->segment_offset
= (uint64_t)_mappingInfo
[segIndex
].dstSegment
- (uint64_t)_mh
;
478 template <typename P
>
479 void Adjustor
<P
>::slidePointer(int segIndex
, uint64_t segOffset
, uint8_t type
, CacheBuilder::ASLR_Tracker
& aslrTracker
)
481 pint_t
* mappedAddrP
= (pint_t
*)((uint8_t*)_mappingInfo
[segIndex
].dstSegment
+ segOffset
);
482 uint32_t* mappedAddr32
= (uint32_t*)mappedAddrP
;
486 case REBASE_TYPE_POINTER
:
487 valueP
= (pint_t
)P::getP(*mappedAddrP
);
488 P::setP(*mappedAddrP
, valueP
+ slideForOrigAddress(valueP
));
489 aslrTracker
.add(mappedAddrP
);
492 case REBASE_TYPE_TEXT_ABSOLUTE32
:
493 value32
= P::E::get32(*mappedAddr32
);
494 P::E::set32(*mappedAddr32
, value32
+ (uint32_t)slideForOrigAddress(value32
));
497 case REBASE_TYPE_TEXT_PCREL32
:
498 // general text relocs not support
500 _diagnostics
.error("unknown rebase type 0x%02X in %s", type
, _installName
);
505 static bool isThumbMovw(uint32_t instruction
)
507 return ( (instruction
& 0x8000FBF0) == 0x0000F240 );
510 static bool isThumbMovt(uint32_t instruction
)
512 return ( (instruction
& 0x8000FBF0) == 0x0000F2C0 );
515 static uint16_t getThumbWord(uint32_t instruction
)
517 uint32_t i
= ((instruction
& 0x00000400) >> 10);
518 uint32_t imm4
= (instruction
& 0x0000000F);
519 uint32_t imm3
= ((instruction
& 0x70000000) >> 28);
520 uint32_t imm8
= ((instruction
& 0x00FF0000) >> 16);
521 return ((imm4
<< 12) | (i
<< 11) | (imm3
<< 8) | imm8
);
524 static uint32_t setThumbWord(uint32_t instruction
, uint16_t word
) {
525 uint32_t imm4
= (word
& 0xF000) >> 12;
526 uint32_t i
= (word
& 0x0800) >> 11;
527 uint32_t imm3
= (word
& 0x0700) >> 8;
528 uint32_t imm8
= word
& 0x00FF;
529 return (instruction
& 0x8F00FBF0) | imm4
| (i
<< 10) | (imm3
<< 28) | (imm8
<< 16);
532 static bool isArmMovw(uint32_t instruction
)
534 return (instruction
& 0x0FF00000) == 0x03000000;
537 static bool isArmMovt(uint32_t instruction
)
539 return (instruction
& 0x0FF00000) == 0x03400000;
542 static uint16_t getArmWord(uint32_t instruction
)
544 uint32_t imm4
= ((instruction
& 0x000F0000) >> 16);
545 uint32_t imm12
= (instruction
& 0x00000FFF);
546 return (imm4
<< 12) | imm12
;
549 static uint32_t setArmWord(uint32_t instruction
, uint16_t word
) {
550 uint32_t imm4
= (word
& 0xF000) >> 12;
551 uint32_t imm12
= word
& 0x0FFF;
552 return (instruction
& 0xFFF0F000) | (imm4
<< 16) | imm12
;
556 template <typename P
>
557 void Adjustor
<P
>::convertArm64eRebaseToIntermediate(dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* chainPtr
, CacheBuilder::ASLR_Tracker
& aslrTracker
, uint64_t targetSlide
)
559 assert(chainPtr
->arm64e
.authRebase
.bind
== 0);
560 dyld3::MachOLoaded::ChainedFixupPointerOnDisk orgPtr
= *chainPtr
;
561 dyld3::MachOLoaded::ChainedFixupPointerOnDisk tmp
;
562 if ( chainPtr
->arm64e
.authRebase
.auth
) {
563 uint64_t targetVMAddr
= orgPtr
.arm64e
.authRebase
.target
+ _segOrigStartAddresses
[0] + targetSlide
;
564 // we need to change the rebase to point to the new address in the dyld cache, but it may not fit
565 tmp
.arm64e
.authRebase
.target
= targetVMAddr
;
566 if ( tmp
.arm64e
.authRebase
.target
== targetVMAddr
) {
567 // everything fits, just update target
568 chainPtr
->arm64e
.authRebase
.target
= targetVMAddr
;
571 // see if it fits in a plain rebase
572 tmp
.arm64e
.rebase
.target
= targetVMAddr
;
573 if ( tmp
.arm64e
.rebase
.target
== targetVMAddr
) {
574 // does fit in plain rebase, so convert to that and store auth data in side table
575 aslrTracker
.setAuthData(chainPtr
, chainPtr
->arm64e
.authRebase
.diversity
, chainPtr
->arm64e
.authRebase
.addrDiv
, chainPtr
->arm64e
.authRebase
.key
);
576 chainPtr
->arm64e
.rebase
.target
= targetVMAddr
;
577 chainPtr
->arm64e
.rebase
.high8
= 0;
578 chainPtr
->arm64e
.rebase
.next
= orgPtr
.arm64e
.rebase
.next
;
579 chainPtr
->arm64e
.rebase
.bind
= 0;
580 chainPtr
->arm64e
.rebase
.auth
= 0;
583 // target cannot fit into rebase chain, so store target in side table
584 aslrTracker
.setAuthData(chainPtr
, chainPtr
->arm64e
.authRebase
.diversity
, chainPtr
->arm64e
.authRebase
.addrDiv
, chainPtr
->arm64e
.authRebase
.key
);
585 aslrTracker
.setRebaseTarget64(chainPtr
, targetVMAddr
);
586 chainPtr
->arm64e
.rebase
.target
= CacheBuilder::kRebaseTargetInSideTableArm64e
; // magic value that means look in side table
587 chainPtr
->arm64e
.rebase
.high8
= 0;
588 chainPtr
->arm64e
.rebase
.next
= orgPtr
.arm64e
.rebase
.next
;
589 chainPtr
->arm64e
.rebase
.bind
= 0;
590 chainPtr
->arm64e
.rebase
.auth
= 0;
594 uint64_t targetVMAddr
= orgPtr
.arm64e
.rebase
.target
+ targetSlide
;
595 tmp
.arm64e
.rebase
.target
= targetVMAddr
;
596 if ( tmp
.arm64e
.rebase
.target
== targetVMAddr
) {
597 // target dyld cache address fits in plain rebase, so all we need to do is adjust that
598 chainPtr
->arm64e
.rebase
.target
= targetVMAddr
;
601 // target cannot fit into rebase chain, so store target in side table
602 aslrTracker
.setRebaseTarget64(chainPtr
, targetVMAddr
);
603 chainPtr
->arm64e
.rebase
.target
= CacheBuilder::kRebaseTargetInSideTableArm64e
; // magic value that means look in side table
608 template <typename P
>
609 void Adjustor
<P
>::convertGeneric64RebaseToIntermediate(dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* chainPtr
, CacheBuilder::ASLR_Tracker
& aslrTracker
, uint64_t targetSlide
)
611 dyld3::MachOLoaded::ChainedFixupPointerOnDisk orgPtr
= *chainPtr
;
612 dyld3::MachOLoaded::ChainedFixupPointerOnDisk tmp
;
614 uint64_t targetVMAddr
= orgPtr
.generic64
.rebase
.target
+ targetSlide
;
615 // we need to change the rebase to point to the new address in the dyld cache, but it may not fit
616 tmp
.generic64
.rebase
.target
= targetVMAddr
;
617 if ( tmp
.generic64
.rebase
.target
== targetVMAddr
) {
618 // everything fits, just update target
619 chainPtr
->generic64
.rebase
.target
= targetVMAddr
;
623 // target cannot fit into rebase chain, so store target in side table
624 aslrTracker
.setRebaseTarget64(chainPtr
, targetVMAddr
);
625 chainPtr
->generic64
.rebase
.target
= CacheBuilder::kRebaseTargetInSideTableArm64
; // magic value that means look in side table
629 template <typename P
>
630 void Adjustor
<P
>::adjustReference(uint32_t kind
, uint8_t* mappedAddr
, uint64_t fromNewAddress
, uint64_t toNewAddress
,
631 int64_t adjust
, int64_t targetSlide
, uint64_t imageStartAddress
, uint64_t imageEndAddress
,
632 CacheBuilder::ASLR_Tracker
& aslrTracker
, CacheBuilder::LOH_Tracker
* lohTracker
,
633 uint32_t*& lastMappedAddr32
, uint32_t& lastKind
, uint64_t& lastToNewAddress
)
636 uint64_t* mappedAddr64
= 0;
638 uint32_t* mappedAddr32
= 0;
639 uint32_t instruction
;
640 dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* chainPtr
;
641 int64_t offsetAdjust
;
644 case DYLD_CACHE_ADJ_V2_DELTA_32
:
645 mappedAddr32
= (uint32_t*)mappedAddr
;
646 value32
= P::E::get32(*mappedAddr32
);
647 delta
= (int32_t)value32
;
649 if ( (delta
> 0x80000000) || (-delta
> 0x80000000) ) {
650 _diagnostics
.error("DYLD_CACHE_ADJ_V2_DELTA_32 can't be adjust by 0x%016llX in %s", adjust
, _installName
);
653 P::E::set32(*mappedAddr32
, (int32_t)delta
);
655 case DYLD_CACHE_ADJ_V2_POINTER_32
:
656 mappedAddr32
= (uint32_t*)mappedAddr
;
657 if ( _chainedFixupsCmd
!= nullptr ) {
658 chainPtr
= (dyld3::MachOLoaded::ChainedFixupPointerOnDisk
*)mappedAddr32
;
659 switch (_chainedFixupsFormat
) {
660 case DYLD_CHAINED_PTR_32
:
661 // ignore binds, fix up rebases to have new targets
662 if ( chainPtr
->generic32
.rebase
.bind
== 0 ) {
663 // there is not enough space in 32-bit pointer to store new vmaddr in cache in 26-bit target
664 // so store target in side table that will be applied when binds are resolved
665 aslrTracker
.add(mappedAddr32
);
666 uint32_t target
= (uint32_t)(chainPtr
->generic32
.rebase
.target
+ targetSlide
);
667 aslrTracker
.setRebaseTarget32(chainPtr
, target
);
668 chainPtr
->generic32
.rebase
.target
= CacheBuilder::kRebaseTargetInSideTableGeneric32
;
672 _diagnostics
.error("unknown 32-bit chained fixup format %d in %s", _chainedFixupsFormat
, _installName
);
677 if ( toNewAddress
!= (uint64_t)(E::get32(*mappedAddr32
) + targetSlide
) ) {
678 _diagnostics
.error("bad DYLD_CACHE_ADJ_V2_POINTER_32 value not as expected at address 0x%llX in %s", fromNewAddress
, _installName
);
681 E::set32(*mappedAddr32
, (uint32_t)toNewAddress
);
682 aslrTracker
.add(mappedAddr32
);
685 case DYLD_CACHE_ADJ_V2_POINTER_64
:
686 mappedAddr64
= (uint64_t*)mappedAddr
;
687 if ( _chainedFixupsCmd
!= nullptr ) {
688 chainPtr
= (dyld3::MachOLoaded::ChainedFixupPointerOnDisk
*)mappedAddr64
;
689 switch (_chainedFixupsFormat
) {
690 case DYLD_CHAINED_PTR_ARM64E
:
691 // ignore binds and adjust rebases to new segment locations
692 if ( chainPtr
->arm64e
.authRebase
.bind
== 0 ) {
693 convertArm64eRebaseToIntermediate(chainPtr
, aslrTracker
, targetSlide
);
694 // Note, the pointer remains a chain with just the target of the rebase adjusted to the new target location
695 aslrTracker
.add(chainPtr
);
698 case DYLD_CHAINED_PTR_64
:
699 // ignore binds and adjust rebases to new segment locations
700 if ( chainPtr
->generic64
.rebase
.bind
== 0 ) {
701 convertGeneric64RebaseToIntermediate(chainPtr
, aslrTracker
, targetSlide
);
702 // Note, the pointer remains a chain with just the target of the rebase adjusted to the new target location
703 aslrTracker
.add(chainPtr
);
706 case DYLD_CHAINED_PTR_64_OFFSET
:
707 case DYLD_CHAINED_PTR_ARM64E_OFFSET
:
708 _diagnostics
.error("unhandled 64-bit chained fixup format %d in %s", _chainedFixupsFormat
, _installName
);
711 _diagnostics
.error("unknown 64-bit chained fixup format %d in %s", _chainedFixupsFormat
, _installName
);
716 if ( toNewAddress
!= (E::get64(*mappedAddr64
) + targetSlide
) ) {
717 _diagnostics
.error("bad DYLD_CACHE_ADJ_V2_POINTER_64 value not as expected at address 0x%llX in %s", fromNewAddress
, _installName
);
720 E::set64(*mappedAddr64
, toNewAddress
);
721 aslrTracker
.add(mappedAddr64
);
722 uint8_t high8
= toNewAddress
>> 56;
724 aslrTracker
.setHigh8(mappedAddr64
, high8
);
727 case DYLD_CACHE_ADJ_V2_THREADED_POINTER_64
:
728 // old style arm64e binary
729 chainPtr
= (dyld3::MachOLoaded::ChainedFixupPointerOnDisk
*)mappedAddr
;
730 // ignore binds, they are proccessed later
731 if ( chainPtr
->arm64e
.authRebase
.bind
== 0 ) {
732 convertArm64eRebaseToIntermediate(chainPtr
, aslrTracker
, targetSlide
);
733 // Note, the pointer remains a chain with just the target of the rebase adjusted to the new target location
734 aslrTracker
.add(chainPtr
);
737 case DYLD_CACHE_ADJ_V2_DELTA_64
:
738 mappedAddr64
= (uint64_t*)mappedAddr
;
739 value64
= P::E::get64(*mappedAddr64
);
740 E::set64(*mappedAddr64
, value64
+ adjust
);
742 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32
:
745 mappedAddr32
= (uint32_t*)mappedAddr
;
746 value32
= P::E::get32(*mappedAddr32
);
747 value64
= toNewAddress
- imageStartAddress
;
748 if ( value64
> imageEndAddress
) {
749 _diagnostics
.error("DYLD_CACHE_ADJ_V2_IMAGE_OFF_32 can't be adjust to 0x%016llX in %s", toNewAddress
, _installName
);
752 P::E::set32(*mappedAddr32
, (uint32_t)value64
);
754 case DYLD_CACHE_ADJ_V2_ARM64_ADRP
:
755 mappedAddr32
= (uint32_t*)mappedAddr
;
757 (*lohTracker
)[toNewAddress
].insert(mappedAddr
);
758 instruction
= P::E::get32(*mappedAddr32
);
759 if ( (instruction
& 0x9F000000) == 0x90000000 ) {
760 int64_t pageDistance
= ((toNewAddress
& ~0xFFF) - (fromNewAddress
& ~0xFFF));
761 int64_t newPage21
= pageDistance
>> 12;
762 if ( (newPage21
> 2097151) || (newPage21
< -2097151) ) {
763 _diagnostics
.error("DYLD_CACHE_ADJ_V2_ARM64_ADRP can't be adjusted that far in %s", _installName
);
766 instruction
= (instruction
& 0x9F00001F) | ((newPage21
<< 29) & 0x60000000) | ((newPage21
<< 3) & 0x00FFFFE0);
767 P::E::set32(*mappedAddr32
, instruction
);
770 // ADRP instructions are sometimes optimized to other instructions (e.g. ADR) after the split-seg-info is generated
773 case DYLD_CACHE_ADJ_V2_ARM64_OFF12
:
774 mappedAddr32
= (uint32_t*)mappedAddr
;
776 (*lohTracker
)[toNewAddress
].insert(mappedAddr
);
777 instruction
= P::E::get32(*mappedAddr32
);
778 offsetAdjust
= (adjust
& 0xFFF);
779 if ( offsetAdjust
== 0 )
781 if ( (instruction
& 0x3B000000) == 0x39000000 ) {
783 if ( offsetAdjust
!= 0 ) {
784 uint32_t encodedAddend
= ((instruction
& 0x003FFC00) >> 10);
785 uint32_t newAddend
= 0;
786 switch ( instruction
& 0xC0000000 ) {
788 if ( (instruction
& 0x04800000) == 0x04800000 ) {
789 if ( offsetAdjust
& 0xF ) {
790 _diagnostics
.error("can't adjust off12 scale=16 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust
, mappedAddr
, _installName
);
793 if ( encodedAddend
*16 >= 4096 ) {
794 _diagnostics
.error("off12 scale=16 instruction points outside its page at mapped address=%p in %s", mappedAddr
, _installName
);
796 newAddend
= (encodedAddend
+ offsetAdjust
/16) % 256;
800 newAddend
= (encodedAddend
+ (int32_t)offsetAdjust
) % 4096;
804 if ( offsetAdjust
& 1 ) {
805 _diagnostics
.error("can't adjust off12 scale=2 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust
, mappedAddr
, _installName
);
808 if ( encodedAddend
*2 >= 4096 ) {
809 _diagnostics
.error("off12 scale=2 instruction points outside its page at mapped address=%p in %s", mappedAddr
, _installName
);
812 newAddend
= (encodedAddend
+ offsetAdjust
/2) % 2048;
815 if ( offsetAdjust
& 3 ) {
816 _diagnostics
.error("can't adjust off12 scale=4 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust
, mappedAddr
, _installName
);
819 if ( encodedAddend
*4 >= 4096 ) {
820 _diagnostics
.error("off12 scale=4 instruction points outside its page at mapped address=%p in %s", mappedAddr
, _installName
);
823 newAddend
= (encodedAddend
+ offsetAdjust
/4) % 1024;
826 if ( offsetAdjust
& 7 ) {
827 _diagnostics
.error("can't adjust off12 scale=8 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust
, mappedAddr
, _installName
);
830 if ( encodedAddend
*8 >= 4096 ) {
831 _diagnostics
.error("off12 scale=8 instruction points outside its page at mapped address=%p in %s", mappedAddr
, _installName
);
834 newAddend
= (encodedAddend
+ offsetAdjust
/8) % 512;
837 uint32_t newInstruction
= (instruction
& 0xFFC003FF) | (newAddend
<< 10);
838 P::E::set32(*mappedAddr32
, newInstruction
);
841 else if ( (instruction
& 0xFFC00000) == 0x91000000 ) {
843 if ( instruction
& 0x00C00000 ) {
844 _diagnostics
.error("ADD off12 uses shift at mapped address=%p in %s", mappedAddr
, _installName
);
847 uint32_t encodedAddend
= ((instruction
& 0x003FFC00) >> 10);
848 uint32_t newAddend
= (encodedAddend
+ offsetAdjust
) & 0xFFF;
849 uint32_t newInstruction
= (instruction
& 0xFFC003FF) | (newAddend
<< 10);
850 P::E::set32(*mappedAddr32
, newInstruction
);
852 else if ( instruction
!= 0xD503201F ) {
853 // ignore imm12 instructions optimized into a NOP, but warn about others
854 _diagnostics
.error("unknown off12 instruction 0x%08X at 0x%0llX in %s", instruction
, fromNewAddress
, _installName
);
858 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT
:
859 mappedAddr32
= (uint32_t*)mappedAddr
;
860 // to update a movw/movt pair we need to extract the 32-bit they will make,
861 // add the adjust and write back the new movw/movt pair.
862 if ( lastKind
== kind
) {
863 if ( lastToNewAddress
== toNewAddress
) {
864 uint32_t instruction1
= P::E::get32(*lastMappedAddr32
);
865 uint32_t instruction2
= P::E::get32(*mappedAddr32
);
866 if ( isThumbMovw(instruction1
) && isThumbMovt(instruction2
) ) {
867 uint16_t high
= getThumbWord(instruction2
);
868 uint16_t low
= getThumbWord(instruction1
);
869 uint32_t full
= high
<< 16 | low
;
871 instruction1
= setThumbWord(instruction1
, full
& 0xFFFF);
872 instruction2
= setThumbWord(instruction2
, full
>> 16);
874 else if ( isThumbMovt(instruction1
) && isThumbMovw(instruction2
) ) {
875 uint16_t high
= getThumbWord(instruction1
);
876 uint16_t low
= getThumbWord(instruction2
);
877 uint32_t full
= high
<< 16 | low
;
879 instruction2
= setThumbWord(instruction2
, full
& 0xFFFF);
880 instruction1
= setThumbWord(instruction1
, full
>> 16);
883 _diagnostics
.error("two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but not paried in %s", _installName
);
886 P::E::set32(*lastMappedAddr32
, instruction1
);
887 P::E::set32(*mappedAddr32
, instruction2
);
891 _diagnostics
.error("two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but target different addresses in %s", _installName
);
896 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT
:
897 mappedAddr32
= (uint32_t*)mappedAddr
;
898 // to update a movw/movt pair we need to extract the 32-bit they will make,
899 // add the adjust and write back the new movw/movt pair.
900 if ( lastKind
== kind
) {
901 if ( lastToNewAddress
== toNewAddress
) {
902 uint32_t instruction1
= P::E::get32(*lastMappedAddr32
);
903 uint32_t instruction2
= P::E::get32(*mappedAddr32
);
904 if ( isArmMovw(instruction1
) && isArmMovt(instruction2
) ) {
905 uint16_t high
= getArmWord(instruction2
);
906 uint16_t low
= getArmWord(instruction1
);
907 uint32_t full
= high
<< 16 | low
;
909 instruction1
= setArmWord(instruction1
, full
& 0xFFFF);
910 instruction2
= setArmWord(instruction2
, full
>> 16);
912 else if ( isArmMovt(instruction1
) && isArmMovw(instruction2
) ) {
913 uint16_t high
= getArmWord(instruction1
);
914 uint16_t low
= getArmWord(instruction2
);
915 uint32_t full
= high
<< 16 | low
;
917 instruction2
= setArmWord(instruction2
, full
& 0xFFFF);
918 instruction1
= setArmWord(instruction1
, full
>> 16);
921 _diagnostics
.error("two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but not paired in %s", _installName
);
924 P::E::set32(*lastMappedAddr32
, instruction1
);
925 P::E::set32(*mappedAddr32
, instruction2
);
929 _diagnostics
.error("two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but target different addresses in %s", _installName
);
934 case DYLD_CACHE_ADJ_V2_ARM64_BR26
:
935 case DYLD_CACHE_ADJ_V2_THUMB_BR22
:
936 case DYLD_CACHE_ADJ_V2_ARM_BR24
:
937 // nothing to do with calls to stubs
940 _diagnostics
.error("unknown split seg kind=%d in %s", kind
, _installName
);
944 lastToNewAddress
= toNewAddress
;
945 lastMappedAddr32
= mappedAddr32
;
948 template <typename P
>
949 void Adjustor
<P
>::adjustReferencesUsingInfoV2(CacheBuilder::ASLR_Tracker
& aslrTracker
,
950 CacheBuilder::LOH_Tracker
& lohTracker
,
951 const CacheBuilder::CacheCoalescedText
& coalescedText
,
952 const CacheBuilder::DylibTextCoalescer
& textCoalescer
)
954 static const bool log
= false;
956 const uint8_t* infoStart
= &_linkeditBias
[_splitSegInfoCmd
->dataoff()];
957 const uint8_t* infoEnd
= &infoStart
[_splitSegInfoCmd
->datasize()];
958 if ( *infoStart
++ != DYLD_CACHE_ADJ_V2_FORMAT
) {
959 _diagnostics
.error("malformed split seg info in %s", _installName
);
962 // build section arrays of slide and mapped address for each section
963 std::vector
<uint64_t> sectionSlides
;
964 std::vector
<uint64_t> sectionNewAddress
;
965 std::vector
<uint8_t*> sectionMappedAddress
;
966 sectionSlides
.reserve(16);
967 sectionNewAddress
.reserve(16);
968 sectionMappedAddress
.reserve(16);
969 // section index 0 refers to mach_header
970 sectionMappedAddress
.push_back((uint8_t*)_mappingInfo
[0].dstSegment
);
971 sectionSlides
.push_back(_segSlides
[0]);
972 sectionNewAddress
.push_back(_mappingInfo
[0].dstCacheUnslidAddress
);
973 // section 1 and later refer to real sections
974 unsigned sectionIndex
= 0;
975 unsigned objcSelRefsSectionIndex
= ~0U;
976 std::map
<uint64_t, std::string_view
> coalescedSectionNames
;
977 std::map
<uint64_t, uint64_t> coalescedSectionOriginalVMAddrs
;
978 for (unsigned segmentIndex
=0; segmentIndex
< _segCmds
.size(); ++segmentIndex
) {
979 macho_segment_command
<P
>* segCmd
= _segCmds
[segmentIndex
];
980 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
981 macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
983 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
984 if ( (strcmp(segCmd
->segname(), "__TEXT") == 0) && textCoalescer
.sectionWasCoalesced(sect
->sectname())) {
985 // If we coalesced the segment then the sections aren't really there to be fixed up
986 sectionMappedAddress
.push_back(nullptr);
987 sectionSlides
.push_back(0);
988 sectionNewAddress
.push_back(0);
990 fprintf(stderr
, " %s/%s, sectIndex=%d, mapped at=%p\n",
991 sect
->segname(), sect
->sectname(), sectionIndex
, sectionMappedAddress
.back());
994 std::string_view sectionName
= sect
->sectname();
995 if (sectionName
.size() > 16)
996 sectionName
= sectionName
.substr(0, 16);
997 coalescedSectionNames
[sectionIndex
] = sectionName
;
998 coalescedSectionOriginalVMAddrs
[sectionIndex
] = sect
->addr();
1000 sectionMappedAddress
.push_back((uint8_t*)_mappingInfo
[segmentIndex
].dstSegment
+ sect
->addr() - segCmd
->vmaddr());
1001 sectionSlides
.push_back(_segSlides
[segmentIndex
]);
1002 sectionNewAddress
.push_back(_mappingInfo
[segmentIndex
].dstCacheUnslidAddress
+ sect
->addr() - segCmd
->vmaddr());
1004 fprintf(stderr
, " %s/%s, sectIndex=%d, mapped at=%p\n",
1005 sect
->segname(), sect
->sectname(), sectionIndex
, sectionMappedAddress
.back());
1008 if (!strcmp(sect
->segname(), "__DATA") && !strcmp(sect
->sectname(), "__objc_selrefs"))
1009 objcSelRefsSectionIndex
= sectionIndex
;
1014 // Whole :== <count> FromToSection+
1015 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1016 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1017 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1018 const uint8_t* p
= infoStart
;
1019 uint64_t sectionCount
= read_uleb128(p
, infoEnd
);
1020 for (uint64_t i
=0; i
< sectionCount
; ++i
) {
1021 uint32_t* lastMappedAddr32
= NULL
;
1022 uint32_t lastKind
= 0;
1023 uint64_t lastToNewAddress
= 0;
1024 uint64_t fromSectionIndex
= read_uleb128(p
, infoEnd
);
1025 uint64_t toSectionIndex
= read_uleb128(p
, infoEnd
);
1026 uint64_t toOffsetCount
= read_uleb128(p
, infoEnd
);
1027 uint64_t fromSectionSlide
= sectionSlides
[fromSectionIndex
];
1028 uint64_t fromSectionNewAddress
= sectionNewAddress
[fromSectionIndex
];
1029 uint8_t* fromSectionMappedAddress
= sectionMappedAddress
[fromSectionIndex
];
1030 uint64_t toSectionSlide
= sectionSlides
[toSectionIndex
];
1031 uint64_t toSectionNewAddress
= sectionNewAddress
[toSectionIndex
];
1032 CacheBuilder::LOH_Tracker
* lohTrackerPtr
= (toSectionIndex
== objcSelRefsSectionIndex
) ? &lohTracker
: nullptr;
1033 if (log
) printf(" from sect=%lld (mapped=%p), to sect=%lld (new addr=0x%llX):\n", fromSectionIndex
, fromSectionMappedAddress
, toSectionIndex
, toSectionNewAddress
);
1034 uint64_t toSectionOffset
= 0;
1036 // We don't support updating split seg from a coalesced segment
1037 if (coalescedSectionNames
.find(fromSectionIndex
) != coalescedSectionNames
.end()) {
1038 _diagnostics
.error("split seg from coalesced segment in %s", _installName
);
1041 for (uint64_t j
=0; j
< toOffsetCount
; ++j
) {
1042 uint64_t toSectionDelta
= read_uleb128(p
, infoEnd
);
1043 uint64_t fromOffsetCount
= read_uleb128(p
, infoEnd
);
1044 toSectionOffset
+= toSectionDelta
;
1045 for (uint64_t k
=0; k
< fromOffsetCount
; ++k
) {
1046 uint64_t kind
= read_uleb128(p
, infoEnd
);
1048 _diagnostics
.error("unknown split seg info v2 kind value (%llu) in %s", kind
, _installName
);
1051 uint64_t fromSectDeltaCount
= read_uleb128(p
, infoEnd
);
1052 uint64_t fromSectionOffset
= 0;
1053 for (uint64_t l
=0; l
< fromSectDeltaCount
; ++l
) {
1054 uint64_t delta
= read_uleb128(p
, infoEnd
);
1055 fromSectionOffset
+= delta
;
1056 //if (log) printf(" kind=%lld, from offset=0x%0llX, to offset=0x%0llX, adjust=0x%llX, targetSlide=0x%llX\n", kind, fromSectionOffset, toSectionOffset, delta, toSectionSlide);
1058 uint8_t* fromMappedAddr
= fromSectionMappedAddress
+ fromSectionOffset
;
1059 uint64_t toNewAddress
= toSectionNewAddress
+ toSectionOffset
;
1060 uint64_t fromNewAddress
= fromSectionNewAddress
+ fromSectionOffset
;
1061 uint64_t imageStartAddress
= sectionNewAddress
.front();
1062 uint64_t imageEndAddress
= sectionNewAddress
.back();
1063 if ( toSectionIndex
!= 255 ) {
1064 auto textCoalIt
= coalescedSectionNames
.find(toSectionIndex
);
1065 if (textCoalIt
!= coalescedSectionNames
.end() ) {
1066 //printf("Section name: %s\n", textCoalIt->second.data());
1067 const CacheBuilder::DylibTextCoalescer::DylibSectionOffsetToCacheSectionOffset
& offsetMap
= textCoalescer
.getSectionCoalescer(textCoalIt
->second
);
1068 auto offsetIt
= offsetMap
.find((uint32_t)toSectionOffset
);
1069 assert(offsetIt
!= offsetMap
.end());
1070 uint64_t baseVMAddr
= coalescedText
.getSectionData(textCoalIt
->second
).bufferVMAddr
;
1071 toNewAddress
= baseVMAddr
+ offsetIt
->second
;
1073 // The 'to' section is gone, but we still need the 'to' slide. Instead of a section slide, compute the slide
1074 // for this individual atom
1075 uint64_t toAtomOriginalVMAddr
= coalescedSectionOriginalVMAddrs
[toSectionIndex
] + toSectionOffset
;
1076 uint64_t toAtomSlide
= toNewAddress
- toAtomOriginalVMAddr
;
1077 int64_t deltaAdjust
= toAtomSlide
- fromSectionSlide
;
1078 adjustReference((uint32_t)kind
, fromMappedAddr
, fromNewAddress
, toNewAddress
, deltaAdjust
, toAtomSlide
,
1079 imageStartAddress
, imageEndAddress
, aslrTracker
, lohTrackerPtr
, lastMappedAddr32
, lastKind
, lastToNewAddress
);
1082 int64_t deltaAdjust
= toSectionSlide
- fromSectionSlide
;
1083 adjustReference((uint32_t)kind
, fromMappedAddr
, fromNewAddress
, toNewAddress
, deltaAdjust
, toSectionSlide
,
1084 imageStartAddress
, imageEndAddress
, aslrTracker
, lohTrackerPtr
, lastMappedAddr32
, lastKind
, lastToNewAddress
);
1087 if ( _diagnostics
.hasError() )
1097 template <typename P
>
1098 void Adjustor
<P
>::adjustRebaseChains(CacheBuilder::ASLR_Tracker
& aslrTracker
)
1100 const dyld3::MachOAnalyzer
* ma
= (dyld3::MachOAnalyzer
*)_mh
;
1101 const dyld_chained_fixups_header
* chainHeader
= (dyld_chained_fixups_header
*)(&_linkeditBias
[_chainedFixupsCmd
->dataoff()]);
1102 const dyld_chained_starts_in_image
* startsInfo
= (dyld_chained_starts_in_image
*)((uint8_t*)chainHeader
+ chainHeader
->starts_offset
);
1103 ma
->forEachFixupInAllChains(_diagnostics
, startsInfo
, false,
1104 ^(dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* fixupLoc
, const dyld_chained_starts_in_segment
* segInfo
, bool& stop
) {
1105 switch ( segInfo
->pointer_format
) {
1106 case DYLD_CHAINED_PTR_64
:
1107 // only look at rebases
1108 if ( fixupLoc
->generic64
.rebase
.bind
== 0 ) {
1109 uint64_t rebaseTargetInDylib
= fixupLoc
->generic64
.rebase
.target
;
1110 uint64_t rebaseTargetInDyldcache
= fixupLoc
->generic64
.rebase
.target
+ slideForOrigAddress(rebaseTargetInDylib
);
1111 convertGeneric64RebaseToIntermediate(fixupLoc
, aslrTracker
, rebaseTargetInDyldcache
);
1112 aslrTracker
.add(fixupLoc
);
1115 case DYLD_CHAINED_PTR_64_OFFSET
:
1116 _diagnostics
.error("unhandled 64-bit chained fixup format %d in %s", _chainedFixupsFormat
, _installName
);
1119 _diagnostics
.error("unsupported chained fixup format %d", segInfo
->pointer_format
);
1126 template <typename P
>
1127 void Adjustor
<P
>::adjustDataPointers(CacheBuilder::ASLR_Tracker
& aslrTracker
)
1129 const uint8_t* p
= &_linkeditBias
[_dyldInfo
->rebase_off()];
1130 const uint8_t* end
= &p
[_dyldInfo
->rebase_size()];
1134 uint64_t segOffset
= 0;
1138 while ( !done
&& (p
< end
) ) {
1139 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
1140 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
1143 case REBASE_OPCODE_DONE
:
1146 case REBASE_OPCODE_SET_TYPE_IMM
:
1149 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
1150 segIndex
= immediate
;
1151 segOffset
= read_uleb128(p
, end
);
1153 case REBASE_OPCODE_ADD_ADDR_ULEB
:
1154 segOffset
+= read_uleb128(p
, end
);
1156 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
1157 segOffset
+= immediate
*sizeof(pint_t
);
1159 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
1160 for (int i
=0; i
< immediate
; ++i
) {
1161 slidePointer(segIndex
, segOffset
, type
, aslrTracker
);
1162 segOffset
+= sizeof(pint_t
);
1165 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
1166 count
= read_uleb128(p
, end
);
1167 for (uint32_t i
=0; i
< count
; ++i
) {
1168 slidePointer(segIndex
, segOffset
, type
, aslrTracker
);
1169 segOffset
+= sizeof(pint_t
);
1172 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
1173 slidePointer(segIndex
, segOffset
, type
, aslrTracker
);
1174 segOffset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
1176 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
1177 count
= read_uleb128(p
, end
);
1178 skip
= read_uleb128(p
, end
);
1179 for (uint32_t i
=0; i
< count
; ++i
) {
1180 slidePointer(segIndex
, segOffset
, type
, aslrTracker
);
1181 segOffset
+= skip
+ sizeof(pint_t
);
1185 _diagnostics
.error("unknown rebase opcode 0x%02X in %s", opcode
, _installName
);
1193 template <typename P
>
1194 void Adjustor
<P
>::adjustInstruction(uint8_t kind
, uint8_t* textLoc
, uint64_t codeToDataDelta
)
1196 uint32_t* fixupLoc32
= (uint32_t*)textLoc
;
1197 uint64_t* fixupLoc64
= (uint64_t*)textLoc
;
1198 uint32_t instruction
;
1203 case 1: // 32-bit pointer (including x86_64 RIP-rel)
1204 value32
= P::E::get32(*fixupLoc32
);
1205 value32
+= codeToDataDelta
;
1206 P::E::set32(*fixupLoc32
, value32
);
1208 case 2: // 64-bit pointer
1209 value64
= P::E::get64(*fixupLoc64
);
1210 value64
+= codeToDataDelta
;
1211 P::E::set64(*fixupLoc64
, value64
);
1213 case 4: // only used for i386, a reference to something in the IMPORT segment
1215 case 5: // used by thumb2 movw
1216 instruction
= P::E::get32(*fixupLoc32
);
1217 // slide is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
1218 value32
= (instruction
& 0x0000000F) + ((uint32_t)codeToDataDelta
>> 12);
1219 instruction
= (instruction
& 0xFFFFFFF0) | (value32
& 0x0000000F);
1220 P::E::set32(*fixupLoc32
, instruction
);
1222 case 6: // used by ARM movw
1223 instruction
= P::E::get32(*fixupLoc32
);
1224 // slide is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
1225 value32
= ((instruction
& 0x000F0000) >> 16) + ((uint32_t)codeToDataDelta
>> 12);
1226 instruction
= (instruction
& 0xFFF0FFFF) | ((value32
<<16) & 0x000F0000);
1227 P::E::set32(*fixupLoc32
, instruction
);
1245 // used by thumb2 movt (low nibble of kind is high 4-bits of paired movw)
1247 instruction
= P::E::get32(*fixupLoc32
);
1248 assert((instruction
& 0x8000FBF0) == 0x0000F2C0);
1249 // extract 16-bit value from instruction
1250 uint32_t i
= ((instruction
& 0x00000400) >> 10);
1251 uint32_t imm4
= (instruction
& 0x0000000F);
1252 uint32_t imm3
= ((instruction
& 0x70000000) >> 28);
1253 uint32_t imm8
= ((instruction
& 0x00FF0000) >> 16);
1254 uint32_t imm16
= (imm4
<< 12) | (i
<< 11) | (imm3
<< 8) | imm8
;
1255 // combine with codeToDataDelta and kind nibble
1256 uint32_t targetValue
= (imm16
<< 16) | ((kind
& 0xF) << 12);
1257 uint32_t newTargetValue
= targetValue
+ (uint32_t)codeToDataDelta
;
1258 // construct new bits slices
1259 uint32_t imm4_
= (newTargetValue
& 0xF0000000) >> 28;
1260 uint32_t i_
= (newTargetValue
& 0x08000000) >> 27;
1261 uint32_t imm3_
= (newTargetValue
& 0x07000000) >> 24;
1262 uint32_t imm8_
= (newTargetValue
& 0x00FF0000) >> 16;
1263 // update instruction to match codeToDataDelta
1264 uint32_t newInstruction
= (instruction
& 0x8F00FBF0) | imm4_
| (i_
<< 10) | (imm3_
<< 28) | (imm8_
<< 16);
1265 P::E::set32(*fixupLoc32
, newInstruction
);
1284 // used by arm movt (low nibble of kind is high 4-bits of paired movw)
1286 instruction
= P::E::get32(*fixupLoc32
);
1287 // extract 16-bit value from instruction
1288 uint32_t imm4
= ((instruction
& 0x000F0000) >> 16);
1289 uint32_t imm12
= (instruction
& 0x00000FFF);
1290 uint32_t imm16
= (imm4
<< 12) | imm12
;
1291 // combine with codeToDataDelta and kind nibble
1292 uint32_t targetValue
= (imm16
<< 16) | ((kind
& 0xF) << 12);
1293 uint32_t newTargetValue
= targetValue
+ (uint32_t)codeToDataDelta
;
1294 // construct new bits slices
1295 uint32_t imm4_
= (newTargetValue
& 0xF0000000) >> 28;
1296 uint32_t imm12_
= (newTargetValue
& 0x0FFF0000) >> 16;
1297 // update instruction to match codeToDataDelta
1298 uint32_t newInstruction
= (instruction
& 0xFFF0F000) | (imm4_
<< 16) | imm12_
;
1299 P::E::set32(*fixupLoc32
, newInstruction
);
1302 case 3: // used for arm64 ADRP
1303 instruction
= P::E::get32(*fixupLoc32
);
1304 if ( (instruction
& 0x9F000000) == 0x90000000 ) {
1305 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
1306 value64
= ((instruction
& 0x60000000) >> 17) | ((instruction
& 0x00FFFFE0) << 9);
1307 value64
+= codeToDataDelta
;
1308 instruction
= (instruction
& 0x9F00001F) | ((value64
<< 17) & 0x60000000) | ((value64
>> 9) & 0x00FFFFE0);
1309 P::E::set32(*fixupLoc32
, instruction
);
1317 template <typename P
>
1318 void Adjustor
<P
>::adjustCode()
1320 // find compressed info on how code needs to be updated
1321 const uint8_t* infoStart
= &_linkeditBias
[_splitSegInfoCmd
->dataoff()];
1322 const uint8_t* infoEnd
= &infoStart
[_splitSegInfoCmd
->datasize()];;
1324 // This encoding only works if all data segments slide by the same amount
1325 uint64_t codeToDataDelta
= _segSlides
[1] - _segSlides
[0];
1327 // compressed data is: [ <kind> [uleb128-delta]+ <0> ] + <0>
1328 for (const uint8_t* p
= infoStart
; (*p
!= 0) && (p
< infoEnd
);) {
1329 uint8_t kind
= *p
++;
1330 uint8_t* textLoc
= (uint8_t*)_mappingInfo
[0].dstSegment
;
1331 while (uint64_t delta
= read_uleb128(p
, infoEnd
)) {
1333 adjustInstruction(kind
, textLoc
, codeToDataDelta
);
1339 template <typename P
>
1340 void Adjustor
<P
>::adjustExportsTrie(std::vector
<uint8_t>& newTrieBytes
)
1342 // if no export info, nothing to adjust
1343 uint32_t exportOffset
= 0;
1344 uint32_t exportSize
= 0;
1345 if ( _dyldInfo
!= nullptr ) {
1346 exportOffset
= _dyldInfo
->export_off();
1347 exportSize
= _dyldInfo
->export_size();
1349 exportOffset
= _exportTrieCmd
->dataoff();
1350 exportSize
= _exportTrieCmd
->datasize();
1353 if ( exportSize
== 0 )
1356 // since export info addresses are offsets from mach_header, everything in __TEXT is fine
1357 // only __DATA addresses need to be updated
1358 const uint8_t* start
= &_linkeditBias
[exportOffset
];
1359 const uint8_t* end
= &start
[exportSize
];
1360 std::vector
<ExportInfoTrie::Entry
> originalExports
;
1361 if ( !ExportInfoTrie::parseTrie(start
, end
, originalExports
) ) {
1362 _diagnostics
.error("malformed exports trie in %s", _installName
);
1366 std::vector
<ExportInfoTrie::Entry
> newExports
;
1367 newExports
.reserve(originalExports
.size());
1368 uint64_t baseAddress
= _segOrigStartAddresses
[0];
1369 uint64_t baseAddressSlide
= slideForOrigAddress(baseAddress
);
1370 for (auto& entry
: originalExports
) {
1371 // remove symbols used by the static linker only
1372 if ( (strncmp(entry
.name
.c_str(), "$ld$", 4) == 0)
1373 || (strncmp(entry
.name
.c_str(), ".objc_class_name",16) == 0)
1374 || (strncmp(entry
.name
.c_str(), ".objc_category_name",19) == 0) ) {
1377 // adjust symbols in slid segments
1378 if ( (entry
.info
.flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) != EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
)
1379 entry
.info
.address
+= (slideForOrigAddress(entry
.info
.address
+ baseAddress
) - baseAddressSlide
);
1380 newExports
.push_back(entry
);
1383 // rebuild export trie
1384 newTrieBytes
.reserve(exportSize
);
1386 ExportInfoTrie(newExports
).emit(newTrieBytes
);
1388 while ( (newTrieBytes
.size() % sizeof(pint_t
)) != 0 )
1389 newTrieBytes
.push_back(0);
1393 } // anonymous namespace
1395 void CacheBuilder::adjustDylibSegments(const DylibInfo
& dylib
, Diagnostics
& diag
) const
1397 DyldSharedCache
* cache
= (DyldSharedCache
*)_readExecuteRegion
.buffer
;
1399 Adjustor
<Pointer64
<LittleEndian
>> adjustor64(cache
, (macho_header
<Pointer64
<LittleEndian
>>*)dylib
.cacheLocation
[0].dstSegment
, dylib
.cacheLocation
, diag
);
1400 adjustor64
.adjustImageForNewSegmentLocations(_aslrTracker
, _lohTracker
, _coalescedText
, dylib
.textCoalescer
);
1403 Adjustor
<Pointer32
<LittleEndian
>> adjustor32(cache
, (macho_header
<Pointer32
<LittleEndian
>>*)dylib
.cacheLocation
[0].dstSegment
, dylib
.cacheLocation
, diag
);
1404 adjustor32
.adjustImageForNewSegmentLocations(_aslrTracker
, _lohTracker
, _coalescedText
, dylib
.textCoalescer
);