dyld-750.5.tar.gz
[apple/dyld.git] / dyld3 / shared-cache / AdjustDylibSegments.cpp
1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 *
3 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <dirent.h>
27 #include <sys/errno.h>
28 #include <sys/fcntl.h>
29 #include <mach-o/loader.h>
30 #include <mach-o/fat.h>
31 #include <assert.h>
32
33 #include <fstream>
34 #include <string>
35 #include <algorithm>
36 #include <unordered_map>
37 #include <unordered_set>
38
39 #include "CacheBuilder.h"
40 #include "Diagnostics.h"
41 #include "DyldSharedCache.h"
42 #include "Trie.hpp"
43 #include "MachOFileAbstraction.hpp"
44 #include "MachOLoaded.h"
45 #include "MachOAnalyzer.h"
46 #include "mach-o/fixup-chains.h"
47
48
49 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
50 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
51 #endif
52
53 namespace {
54
55 template <typename P>
56 class Adjustor {
57 public:
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);
63
64 private:
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();
79 void adjustCode();
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);
85
86
87 typedef typename P::uint_t pint_t;
88 typedef typename P::E E;
89
90 DyldSharedCache* _cacheBuffer;
91 macho_header<P>* _mh;
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;
111 };
112
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)
116 {
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()) {
125 case LC_ID_DYLIB:
126 _installName = ((macho_dylib_command<P>*)cmd)->name();
127 break;
128 case LC_SYMTAB:
129 _symTabCmd = (macho_symtab_command<P>*)cmd;
130 break;
131 case LC_DYSYMTAB:
132 _dynSymTabCmd = (macho_dysymtab_command<P>*)cmd;
133 break;
134 case LC_DYLD_INFO:
135 case LC_DYLD_INFO_ONLY:
136 _dyldInfo = (macho_dyld_info_command<P>*)cmd;
137 break;
138 case LC_SEGMENT_SPLIT_INFO:
139 _splitSegInfoCmd = (macho_linkedit_data_command<P>*)cmd;
140 break;
141 case LC_FUNCTION_STARTS:
142 _functionStartsCmd = (macho_linkedit_data_command<P>*)cmd;
143 break;
144 case LC_DATA_IN_CODE:
145 _dataInCodeCmd = (macho_linkedit_data_command<P>*)cmd;
146 break;
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()]);
150 break;
151 case LC_DYLD_EXPORTS_TRIE:
152 _exportTrieCmd = (macho_linkedit_data_command<P>*)cmd;
153 break;
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;
162 }
163 ++segIndex;
164 break;
165 }
166 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
167 }
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);
172 }
173 else {
174 _diagnostics.error("missing LC_SEGMENT_SPLIT_INFO in %s", _installName);
175 }
176 }
177
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)
183 {
184 if ( _diagnostics.hasError() )
185 return;
186 if ( _splitSegInfoV2 ) {
187 adjustReferencesUsingInfoV2(aslrTracker, lohTracker, coalescedText, textCoalescer);
188 adjustChainedFixups();
189 }
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);
194 adjustCode();
195 }
196 else {
197 adjustDataPointers(aslrTracker);
198 adjustCode();
199 }
200 if ( _diagnostics.hasError() )
201 return;
202 adjustSymbolTable();
203 if ( _diagnostics.hasError() )
204 return;
205 if ( _diagnostics.hasError() )
206 return;
207 rebuildLinkEditAndLoadCommands(textCoalescer);
208
209 #if DEBUG
210 Diagnostics diag;
211 ((dyld3::MachOAnalyzer*)_mh)->validateDyldCacheDylib(diag, _installName);
212 if ( diag.hasError() ) {
213 fprintf(stderr, "%s\n", diag.errorMessage().c_str());
214 }
215 #endif
216 }
217
218 template <typename P>
219 uint64_t Adjustor<P>::slideForOrigAddress(uint64_t addr)
220 {
221 for (unsigned i=0; i < _segOrigStartAddresses.size(); ++i) {
222 if ( (_segOrigStartAddresses[i] <= addr) && (addr < (_segOrigStartAddresses[i]+_segCmds[i]->vmsize())) )
223 return _segSlides[i];
224 }
225 // On arm64, high nibble of pointers can have extra bits
226 if ( _maskPointers && (addr & 0xF000000000000000) ) {
227 return slideForOrigAddress(addr & 0x0FFFFFFFFFFFFFFF);
228 }
229 _diagnostics.error("slide not known for dylib address 0x%llX in %s", addr, _installName);
230 return 0;
231 }
232
233 template <typename P>
234 void Adjustor<P>::rebuildLinkEditAndLoadCommands(const CacheBuilder::DylibTextCoalescer& textCoalescer)
235 {
236 // Exports trie is only data structure in LINKEDIT that might grow
237 std::vector<uint8_t> newTrieBytes;
238 adjustExportsTrie(newTrieBytes);
239
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;
264
265 size_t linkeditBufferSize = align(_segCmds[_linkeditSegIndex]->vmsize(), 12);
266 if ( linkeditBufferSize < newLinkEditSize ) {
267 _diagnostics.error("LINKEDIT overflow in %s", _installName);
268 return;
269 }
270
271 uint8_t* newLinkeditBufer = (uint8_t*)::calloc(linkeditBufferSize, 1);
272 if ( chainedFixupsSize )
273 memcpy(&newLinkeditBufer[chainedFixupsOffset], &_linkeditBias[_chainedFixupsCmd->dataoff()], chainedFixupsSize);
274 if ( bindSize )
275 memcpy(&newLinkeditBufer[bindOffset], &_linkeditBias[_dyldInfo->bind_off()], bindSize);
276 if ( lazyBindSize )
277 memcpy(&newLinkeditBufer[lazyBindOffset], &_linkeditBias[_dyldInfo->lazy_bind_off()], lazyBindSize);
278 if ( weakBindSize )
279 memcpy(&newLinkeditBufer[weakBindOffset], &_linkeditBias[_dyldInfo->weak_bind_off()], weakBindSize);
280 if ( exportSize )
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);
294
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;
299
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;
322 bool remove = false;
323 switch ( cmd->cmd() ) {
324 case LC_ID_DYLIB:
325 dylibIDCmd = (macho_dylib_command<P>*)cmd;
326 dylibIDCmd->set_timestamp(2); // match what static linker sets in LC_LOAD_DYLIB
327 break;
328 case LC_SYMTAB:
329 symTabCmd = (macho_symtab_command<P>*)cmd;
330 symTabCmd->set_symoff(linkeditStartOffset+symbolTableOffset);
331 symTabCmd->set_stroff(linkeditStartOffset+symbolStringsOffset);
332 break;
333 case LC_DYSYMTAB:
334 dynSymTabCmd = (macho_dysymtab_command<P>*)cmd;
335 dynSymTabCmd->set_indirectsymoff(linkeditStartOffset+indirectTableOffset);
336 break;
337 case LC_DYLD_INFO:
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);
350 break;
351 case LC_FUNCTION_STARTS:
352 functionStartsCmd = (macho_linkedit_data_command<P>*)cmd;
353 functionStartsCmd->set_dataoff(linkeditStartOffset+funcStartsOffset);
354 break;
355 case LC_DATA_IN_CODE:
356 dataInCodeCmd = (macho_linkedit_data_command<P>*)cmd;
357 dataInCodeCmd->set_dataoff(linkeditStartOffset+dataInCodeOffset);
358 break;
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);
363 break;
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);
368 break;
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()));
372 break;
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 = &sectionsStart[segCmd->nsects()];
385
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());
390 sect->set_offset(0);
391 sect->set_size(0);
392 } else {
393 sect->set_addr(sect->addr() + _segSlides[segIndex]);
394 if ( sect->offset() != 0 )
395 sect->set_offset(sect->offset() + segFileOffsetDelta);
396 }
397 }
398 }
399 ++segIndex;
400 break;
401 case LC_RPATH:
402 _diagnostics.warning("dyld shared cache does not support LC_RPATH found in %s", _installName);
403 remove = true;
404 break;
405 case LC_SEGMENT_SPLIT_INFO:
406 splitSegInfoCmd = (macho_linkedit_data_command<P>*)cmd;
407 splitSegInfoCmd->set_dataoff(linkeditStartOffset+splitSegInfoOffset);
408 break;
409 case LC_CODE_SIGNATURE:
410 case LC_DYLIB_CODE_SIGN_DRS:
411 remove = true;
412 break;
413 default:
414 break;
415 }
416 macho_load_command<P>* nextCmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmdSize);
417 if ( remove ) {
418 ::memmove((void*)cmd, (void*)nextCmd, bytesRemaining);
419 ++removedCount;
420 }
421 else {
422 bytesRemaining -= cmdSize;
423 cmd = nextCmd;
424 }
425 }
426 // zero out stuff removed
427 ::bzero((void*)cmd, bytesRemaining);
428 // update header
429 _mh->set_ncmds(cmd_count-removedCount);
430 _mh->set_sizeofcmds(origLoadCommandsSize-bytesRemaining);
431 _mh->set_flags(_mh->flags() | 0x80000000);
432 }
433
434
435 template <typename P>
436 void Adjustor<P>::adjustSymbolTable()
437 {
438 macho_nlist<P>* symbolTable = (macho_nlist<P>*)&_linkeditBias[_symTabCmd->symoff()];
439
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()));
445 }
446
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()));
452 }
453 }
454
455
456 template <typename P>
457 void Adjustor<P>::adjustChainedFixups()
458 {
459 if ( _chainedFixupsCmd == nullptr )
460 return;
461
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;
466
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 )
471 continue;
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;
474 }
475 });
476 }
477
478 template <typename P>
479 void Adjustor<P>::slidePointer(int segIndex, uint64_t segOffset, uint8_t type, CacheBuilder::ASLR_Tracker& aslrTracker)
480 {
481 pint_t* mappedAddrP = (pint_t*)((uint8_t*)_mappingInfo[segIndex].dstSegment + segOffset);
482 uint32_t* mappedAddr32 = (uint32_t*)mappedAddrP;
483 pint_t valueP;
484 uint32_t value32;
485 switch ( type ) {
486 case REBASE_TYPE_POINTER:
487 valueP = (pint_t)P::getP(*mappedAddrP);
488 P::setP(*mappedAddrP, valueP + slideForOrigAddress(valueP));
489 aslrTracker.add(mappedAddrP);
490 break;
491
492 case REBASE_TYPE_TEXT_ABSOLUTE32:
493 value32 = P::E::get32(*mappedAddr32);
494 P::E::set32(*mappedAddr32, value32 + (uint32_t)slideForOrigAddress(value32));
495 break;
496
497 case REBASE_TYPE_TEXT_PCREL32:
498 // general text relocs not support
499 default:
500 _diagnostics.error("unknown rebase type 0x%02X in %s", type, _installName);
501 }
502 }
503
504
505 static bool isThumbMovw(uint32_t instruction)
506 {
507 return ( (instruction & 0x8000FBF0) == 0x0000F240 );
508 }
509
510 static bool isThumbMovt(uint32_t instruction)
511 {
512 return ( (instruction & 0x8000FBF0) == 0x0000F2C0 );
513 }
514
515 static uint16_t getThumbWord(uint32_t instruction)
516 {
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);
522 }
523
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);
530 }
531
532 static bool isArmMovw(uint32_t instruction)
533 {
534 return (instruction & 0x0FF00000) == 0x03000000;
535 }
536
537 static bool isArmMovt(uint32_t instruction)
538 {
539 return (instruction & 0x0FF00000) == 0x03400000;
540 }
541
542 static uint16_t getArmWord(uint32_t instruction)
543 {
544 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
545 uint32_t imm12 = (instruction & 0x00000FFF);
546 return (imm4 << 12) | imm12;
547 }
548
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;
553 }
554
555
556 template <typename P>
557 void Adjustor<P>::convertArm64eRebaseToIntermediate(dyld3::MachOLoaded::ChainedFixupPointerOnDisk* chainPtr, CacheBuilder::ASLR_Tracker& aslrTracker, uint64_t targetSlide)
558 {
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;
569 return;
570 }
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;
581 return;
582 }
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;
591 return;
592 }
593 else {
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;
599 return;
600 }
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
604 }
605 }
606
607
608 template <typename P>
609 void Adjustor<P>::convertGeneric64RebaseToIntermediate(dyld3::MachOLoaded::ChainedFixupPointerOnDisk* chainPtr, CacheBuilder::ASLR_Tracker& aslrTracker, uint64_t targetSlide)
610 {
611 dyld3::MachOLoaded::ChainedFixupPointerOnDisk orgPtr = *chainPtr;
612 dyld3::MachOLoaded::ChainedFixupPointerOnDisk tmp;
613
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;
620 return;
621 }
622
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
626 }
627
628
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)
634 {
635 uint64_t value64;
636 uint64_t* mappedAddr64 = 0;
637 uint32_t value32;
638 uint32_t* mappedAddr32 = 0;
639 uint32_t instruction;
640 dyld3::MachOLoaded::ChainedFixupPointerOnDisk* chainPtr;
641 int64_t offsetAdjust;
642 int64_t delta;
643 switch ( kind ) {
644 case DYLD_CACHE_ADJ_V2_DELTA_32:
645 mappedAddr32 = (uint32_t*)mappedAddr;
646 value32 = P::E::get32(*mappedAddr32);
647 delta = (int32_t)value32;
648 delta += adjust;
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);
651 return;
652 }
653 P::E::set32(*mappedAddr32, (int32_t)delta);
654 break;
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;
669 }
670 break;
671 default:
672 _diagnostics.error("unknown 32-bit chained fixup format %d in %s", _chainedFixupsFormat, _installName);
673 break;
674 }
675 }
676 else {
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);
679 return;
680 }
681 E::set32(*mappedAddr32, (uint32_t)toNewAddress);
682 aslrTracker.add(mappedAddr32);
683 }
684 break;
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);
696 }
697 break;
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);
704 }
705 break;
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);
709 break;
710 default:
711 _diagnostics.error("unknown 64-bit chained fixup format %d in %s", _chainedFixupsFormat, _installName);
712 break;
713 }
714 }
715 else {
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);
718 return;
719 }
720 E::set64(*mappedAddr64, toNewAddress);
721 aslrTracker.add(mappedAddr64);
722 uint8_t high8 = toNewAddress >> 56;
723 if ( high8 )
724 aslrTracker.setHigh8(mappedAddr64, high8);
725 }
726 break;
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);
735 }
736 break;
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);
741 break;
742 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
743 if ( adjust == 0 )
744 break;
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);
750 return;
751 }
752 P::E::set32(*mappedAddr32, (uint32_t)value64);
753 break;
754 case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
755 mappedAddr32 = (uint32_t*)mappedAddr;
756 if (lohTracker)
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);
764 return;
765 }
766 instruction = (instruction & 0x9F00001F) | ((newPage21 << 29) & 0x60000000) | ((newPage21 << 3) & 0x00FFFFE0);
767 P::E::set32(*mappedAddr32, instruction);
768 }
769 else {
770 // ADRP instructions are sometimes optimized to other instructions (e.g. ADR) after the split-seg-info is generated
771 }
772 break;
773 case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
774 mappedAddr32 = (uint32_t*)mappedAddr;
775 if (lohTracker)
776 (*lohTracker)[toNewAddress].insert(mappedAddr);
777 instruction = P::E::get32(*mappedAddr32);
778 offsetAdjust = (adjust & 0xFFF);
779 if ( offsetAdjust == 0 )
780 break;
781 if ( (instruction & 0x3B000000) == 0x39000000 ) {
782 // LDR/STR imm12
783 if ( offsetAdjust != 0 ) {
784 uint32_t encodedAddend = ((instruction & 0x003FFC00) >> 10);
785 uint32_t newAddend = 0;
786 switch ( instruction & 0xC0000000 ) {
787 case 0x00000000:
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);
791 return;
792 }
793 if ( encodedAddend*16 >= 4096 ) {
794 _diagnostics.error("off12 scale=16 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
795 }
796 newAddend = (encodedAddend + offsetAdjust/16) % 256;
797 }
798 else {
799 // scale=1
800 newAddend = (encodedAddend + (int32_t)offsetAdjust) % 4096;
801 }
802 break;
803 case 0x40000000:
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);
806 return;
807 }
808 if ( encodedAddend*2 >= 4096 ) {
809 _diagnostics.error("off12 scale=2 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
810 return;
811 }
812 newAddend = (encodedAddend + offsetAdjust/2) % 2048;
813 break;
814 case 0x80000000:
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);
817 return;
818 }
819 if ( encodedAddend*4 >= 4096 ) {
820 _diagnostics.error("off12 scale=4 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
821 return;
822 }
823 newAddend = (encodedAddend + offsetAdjust/4) % 1024;
824 break;
825 case 0xC0000000:
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);
828 return;
829 }
830 if ( encodedAddend*8 >= 4096 ) {
831 _diagnostics.error("off12 scale=8 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
832 return;
833 }
834 newAddend = (encodedAddend + offsetAdjust/8) % 512;
835 break;
836 }
837 uint32_t newInstruction = (instruction & 0xFFC003FF) | (newAddend << 10);
838 P::E::set32(*mappedAddr32, newInstruction);
839 }
840 }
841 else if ( (instruction & 0xFFC00000) == 0x91000000 ) {
842 // ADD imm12
843 if ( instruction & 0x00C00000 ) {
844 _diagnostics.error("ADD off12 uses shift at mapped address=%p in %s", mappedAddr, _installName);
845 return;
846 }
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);
851 }
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);
855 return;
856 }
857 break;
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;
870 full += adjust;
871 instruction1 = setThumbWord(instruction1, full & 0xFFFF);
872 instruction2 = setThumbWord(instruction2, full >> 16);
873 }
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;
878 full += adjust;
879 instruction2 = setThumbWord(instruction2, full & 0xFFFF);
880 instruction1 = setThumbWord(instruction1, full >> 16);
881 }
882 else {
883 _diagnostics.error("two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but not paried in %s", _installName);
884 return;
885 }
886 P::E::set32(*lastMappedAddr32, instruction1);
887 P::E::set32(*mappedAddr32, instruction2);
888 kind = 0;
889 }
890 else {
891 _diagnostics.error("two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but target different addresses in %s", _installName);
892 return;
893 }
894 }
895 break;
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;
908 full += adjust;
909 instruction1 = setArmWord(instruction1, full & 0xFFFF);
910 instruction2 = setArmWord(instruction2, full >> 16);
911 }
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;
916 full += adjust;
917 instruction2 = setArmWord(instruction2, full & 0xFFFF);
918 instruction1 = setArmWord(instruction1, full >> 16);
919 }
920 else {
921 _diagnostics.error("two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but not paired in %s", _installName);
922 return;
923 }
924 P::E::set32(*lastMappedAddr32, instruction1);
925 P::E::set32(*mappedAddr32, instruction2);
926 kind = 0;
927 }
928 else {
929 _diagnostics.error("two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but target different addresses in %s", _installName);
930 return;
931 }
932 }
933 break;
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
938 break;
939 default:
940 _diagnostics.error("unknown split seg kind=%d in %s", kind, _installName);
941 return;
942 }
943 lastKind = kind;
944 lastToNewAddress = toNewAddress;
945 lastMappedAddr32 = mappedAddr32;
946 }
947
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)
953 {
954 static const bool log = false;
955
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);
960 return;
961 }
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 = &sectionsStart[segCmd->nsects()];
982
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);
989 if (log) {
990 fprintf(stderr, " %s/%s, sectIndex=%d, mapped at=%p\n",
991 sect->segname(), sect->sectname(), sectionIndex, sectionMappedAddress.back());
992 }
993 ++sectionIndex;
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();
999 } else {
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());
1003 if (log) {
1004 fprintf(stderr, " %s/%s, sectIndex=%d, mapped at=%p\n",
1005 sect->segname(), sect->sectname(), sectionIndex, sectionMappedAddress.back());
1006 }
1007 ++sectionIndex;
1008 if (!strcmp(sect->segname(), "__DATA") && !strcmp(sect->sectname(), "__objc_selrefs"))
1009 objcSelRefsSectionIndex = sectionIndex;
1010 }
1011 }
1012 }
1013
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;
1035
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);
1039 return;
1040 }
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);
1047 if ( kind > 13 ) {
1048 _diagnostics.error("unknown split seg info v2 kind value (%llu) in %s", kind, _installName);
1049 return;
1050 }
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);
1057
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;
1072
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);
1080
1081 } else {
1082 int64_t deltaAdjust = toSectionSlide - fromSectionSlide;
1083 adjustReference((uint32_t)kind, fromMappedAddr, fromNewAddress, toNewAddress, deltaAdjust, toSectionSlide,
1084 imageStartAddress, imageEndAddress, aslrTracker, lohTrackerPtr, lastMappedAddr32, lastKind, lastToNewAddress);
1085 }
1086 }
1087 if ( _diagnostics.hasError() )
1088 return;
1089 }
1090 }
1091 }
1092 }
1093
1094 }
1095
1096
1097 template <typename P>
1098 void Adjustor<P>::adjustRebaseChains(CacheBuilder::ASLR_Tracker& aslrTracker)
1099 {
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);
1113 }
1114 break;
1115 case DYLD_CHAINED_PTR_64_OFFSET:
1116 _diagnostics.error("unhandled 64-bit chained fixup format %d in %s", _chainedFixupsFormat, _installName);
1117 break;
1118 default:
1119 _diagnostics.error("unsupported chained fixup format %d", segInfo->pointer_format);
1120 stop = true;
1121 }
1122 });
1123 }
1124
1125
1126 template <typename P>
1127 void Adjustor<P>::adjustDataPointers(CacheBuilder::ASLR_Tracker& aslrTracker)
1128 {
1129 const uint8_t* p = &_linkeditBias[_dyldInfo->rebase_off()];
1130 const uint8_t* end = &p[_dyldInfo->rebase_size()];
1131
1132 uint8_t type = 0;
1133 int segIndex = 0;
1134 uint64_t segOffset = 0;
1135 uint64_t count;
1136 uint64_t skip;
1137 bool done = false;
1138 while ( !done && (p < end) ) {
1139 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
1140 uint8_t opcode = *p & REBASE_OPCODE_MASK;
1141 ++p;
1142 switch (opcode) {
1143 case REBASE_OPCODE_DONE:
1144 done = true;
1145 break;
1146 case REBASE_OPCODE_SET_TYPE_IMM:
1147 type = immediate;
1148 break;
1149 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1150 segIndex = immediate;
1151 segOffset = read_uleb128(p, end);
1152 break;
1153 case REBASE_OPCODE_ADD_ADDR_ULEB:
1154 segOffset += read_uleb128(p, end);
1155 break;
1156 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
1157 segOffset += immediate*sizeof(pint_t);
1158 break;
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);
1163 }
1164 break;
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);
1170 }
1171 break;
1172 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
1173 slidePointer(segIndex, segOffset, type, aslrTracker);
1174 segOffset += read_uleb128(p, end) + sizeof(pint_t);
1175 break;
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);
1182 }
1183 break;
1184 default:
1185 _diagnostics.error("unknown rebase opcode 0x%02X in %s", opcode, _installName);
1186 done = true;
1187 break;
1188 }
1189 }
1190 }
1191
1192
1193 template <typename P>
1194 void Adjustor<P>::adjustInstruction(uint8_t kind, uint8_t* textLoc, uint64_t codeToDataDelta)
1195 {
1196 uint32_t* fixupLoc32 = (uint32_t*)textLoc;
1197 uint64_t* fixupLoc64 = (uint64_t*)textLoc;
1198 uint32_t instruction;
1199 uint32_t value32;
1200 uint64_t value64;
1201
1202 switch (kind) {
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);
1207 break;
1208 case 2: // 64-bit pointer
1209 value64 = P::E::get64(*fixupLoc64);
1210 value64 += codeToDataDelta;
1211 P::E::set64(*fixupLoc64, value64);
1212 break;
1213 case 4: // only used for i386, a reference to something in the IMPORT segment
1214 break;
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);
1221 break;
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);
1228 break;
1229 case 0x10:
1230 case 0x11:
1231 case 0x12:
1232 case 0x13:
1233 case 0x14:
1234 case 0x15:
1235 case 0x16:
1236 case 0x17:
1237 case 0x18:
1238 case 0x19:
1239 case 0x1A:
1240 case 0x1B:
1241 case 0x1C:
1242 case 0x1D:
1243 case 0x1E:
1244 case 0x1F:
1245 // used by thumb2 movt (low nibble of kind is high 4-bits of paired movw)
1246 {
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);
1266 }
1267 break;
1268 case 0x20:
1269 case 0x21:
1270 case 0x22:
1271 case 0x23:
1272 case 0x24:
1273 case 0x25:
1274 case 0x26:
1275 case 0x27:
1276 case 0x28:
1277 case 0x29:
1278 case 0x2A:
1279 case 0x2B:
1280 case 0x2C:
1281 case 0x2D:
1282 case 0x2E:
1283 case 0x2F:
1284 // used by arm movt (low nibble of kind is high 4-bits of paired movw)
1285 {
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);
1300 }
1301 break;
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);
1310 }
1311 break;
1312 default:
1313 break;
1314 }
1315 }
1316
1317 template <typename P>
1318 void Adjustor<P>::adjustCode()
1319 {
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()];;
1323
1324 // This encoding only works if all data segments slide by the same amount
1325 uint64_t codeToDataDelta = _segSlides[1] - _segSlides[0];
1326
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)) {
1332 textLoc += delta;
1333 adjustInstruction(kind, textLoc, codeToDataDelta);
1334 }
1335 }
1336 }
1337
1338
1339 template <typename P>
1340 void Adjustor<P>::adjustExportsTrie(std::vector<uint8_t>& newTrieBytes)
1341 {
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();
1348 } else {
1349 exportOffset = _exportTrieCmd->dataoff();
1350 exportSize = _exportTrieCmd->datasize();
1351 }
1352
1353 if ( exportSize == 0 )
1354 return;
1355
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);
1363 return;
1364 }
1365
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) ) {
1375 continue;
1376 }
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);
1381 }
1382
1383 // rebuild export trie
1384 newTrieBytes.reserve(exportSize);
1385
1386 ExportInfoTrie(newExports).emit(newTrieBytes);
1387 // align
1388 while ( (newTrieBytes.size() % sizeof(pint_t)) != 0 )
1389 newTrieBytes.push_back(0);
1390 }
1391
1392
1393 } // anonymous namespace
1394
1395 void CacheBuilder::adjustDylibSegments(const DylibInfo& dylib, Diagnostics& diag) const
1396 {
1397 DyldSharedCache* cache = (DyldSharedCache*)_readExecuteRegion.buffer;
1398 if ( _is64 ) {
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);
1401 }
1402 else {
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);
1405 }
1406 }
1407
1408
1409
1410
1411
1412