]> git.saurik.com Git - apple/dyld.git/blob - dyld3/shared-cache/AdjustDylibSegments.cpp
dyld-551.4.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
45
46 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
47 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
48 #endif
49
50 namespace {
51
52 template <typename P>
53 class Adjustor {
54 public:
55 Adjustor(DyldSharedCache* cacheBuffer, macho_header<P>* mh, const std::vector<CacheBuilder::SegmentMappingInfo>& mappingInfo, Diagnostics& diag);
56 void adjustImageForNewSegmentLocations(std::vector<void*>& pointersForASLR);
57
58 private:
59 void adjustReferencesUsingInfoV2(std::vector<void*>& pointersForASLR);
60 void adjustReference(uint32_t kind, uint8_t* mappedAddr, uint64_t fromNewAddress, uint64_t toNewAddress, int64_t adjust, int64_t targetSlide,
61 uint64_t imageStartAddress, uint64_t imageEndAddress, std::vector<void*>& pointersForASLR, uint32_t*& lastMappedAddr32,
62 uint32_t& lastKind, uint64_t& lastToNewAddress);
63 void adjustDataPointers(std::vector<void*>& pointersForASLR);
64 void slidePointer(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersForASLR);
65 void adjustSymbolTable();
66 void adjustExportsTrie(std::vector<uint8_t>& newTrieBytes);
67 void rebuildLinkEdit();
68 void adjustCode();
69 void adjustInstruction(uint8_t kind, uint64_t cacheOffset, uint64_t codeToDataDelta);
70 void rebuildLinkEditAndLoadCommands();
71 uint64_t slideForOrigAddress(uint64_t addr);
72
73 typedef typename P::uint_t pint_t;
74 typedef typename P::E E;
75
76 DyldSharedCache* _cacheBuffer;
77 macho_header<P>* _mh;
78 Diagnostics& _diagnostics;
79 const uint8_t* _linkeditBias = nullptr;
80 int64_t _linkeditAdjust = 0;
81 unsigned _linkeditSegIndex = 0;
82 bool _maskPointers = false;
83 bool _splitSegInfoV2 = false;
84 const char* _installName = nullptr;
85 macho_symtab_command<P>* _symTabCmd = nullptr;
86 macho_dysymtab_command<P>* _dynSymTabCmd = nullptr;
87 macho_dyld_info_command<P>* _dyldInfo = nullptr;
88 macho_linkedit_data_command<P>* _splitSegInfoCmd = nullptr;
89 macho_linkedit_data_command<P>* _functionStartsCmd = nullptr;
90 macho_linkedit_data_command<P>* _dataInCodeCmd = nullptr;
91 std::vector<uint64_t> _segOrigStartAddresses;
92 std::vector<uint64_t> _segSlides;
93 std::vector<macho_segment_command<P>*> _segCmds;
94 const std::vector<CacheBuilder::SegmentMappingInfo>& _mappingInfo;
95 };
96
97 template <typename P>
98 Adjustor<P>::Adjustor(DyldSharedCache* cacheBuffer, macho_header<P>* mh, const std::vector<CacheBuilder::SegmentMappingInfo>& mappingInfo, Diagnostics& diag)
99 : _cacheBuffer(cacheBuffer), _mh(mh), _diagnostics(diag), _mappingInfo(mappingInfo)
100 {
101 assert((mh->magic() == MH_MAGIC) || (mh->magic() == MH_MAGIC_64));
102 macho_segment_command<P>* segCmd;
103 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
104 const uint32_t cmd_count = mh->ncmds();
105 const macho_load_command<P>* cmd = cmds;
106 unsigned segIndex = 0;
107 for (uint32_t i = 0; i < cmd_count; ++i) {
108 switch (cmd->cmd()) {
109 case LC_ID_DYLIB:
110 _installName = ((macho_dylib_command<P>*)cmd)->name();
111 break;
112 case LC_SYMTAB:
113 _symTabCmd = (macho_symtab_command<P>*)cmd;
114 break;
115 case LC_DYSYMTAB:
116 _dynSymTabCmd = (macho_dysymtab_command<P>*)cmd;
117 break;
118 case LC_DYLD_INFO:
119 case LC_DYLD_INFO_ONLY:
120 _dyldInfo = (macho_dyld_info_command<P>*)cmd;
121 break;
122 case LC_SEGMENT_SPLIT_INFO:
123 _splitSegInfoCmd = (macho_linkedit_data_command<P>*)cmd;
124 break;
125 case LC_FUNCTION_STARTS:
126 _functionStartsCmd = (macho_linkedit_data_command<P>*)cmd;
127 break;
128 case LC_DATA_IN_CODE:
129 _dataInCodeCmd = (macho_linkedit_data_command<P>*)cmd;
130 break;
131 case macho_segment_command<P>::CMD:
132 segCmd = (macho_segment_command<P>*)cmd;
133 _segCmds.push_back(segCmd);
134 _segOrigStartAddresses.push_back(segCmd->vmaddr());
135 _segSlides.push_back(_mappingInfo[segIndex].dstCacheAddress - segCmd->vmaddr());
136 if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) {
137 _linkeditAdjust = _mappingInfo[segIndex].dstCacheOffset - segCmd->fileoff();
138 _linkeditBias = (uint8_t*)cacheBuffer + _linkeditAdjust;
139 _linkeditSegIndex = segIndex;
140 }
141 ++segIndex;
142 break;
143 }
144 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
145 }
146 _maskPointers = (P::E::get32(mh->cputype()) == CPU_TYPE_ARM64);
147 if ( _splitSegInfoCmd != NULL ) {
148 const uint8_t* infoStart = &_linkeditBias[_splitSegInfoCmd->dataoff()];
149 _splitSegInfoV2 = (*infoStart == DYLD_CACHE_ADJ_V2_FORMAT);
150 }
151 else {
152 _diagnostics.error("missing LC_SEGMENT_SPLIT_INFO in %s", _installName);
153 }
154 }
155
156 template <typename P>
157 void Adjustor<P>::adjustImageForNewSegmentLocations(std::vector<void*>& pointersForASLR)
158 {
159 if ( _diagnostics.hasError() )
160 return;
161 if ( _splitSegInfoV2 ) {
162 adjustReferencesUsingInfoV2(pointersForASLR);
163 }
164 else {
165 adjustDataPointers(pointersForASLR);
166 adjustCode();
167 }
168 if ( _diagnostics.hasError() )
169 return;
170 adjustSymbolTable();
171 if ( _diagnostics.hasError() )
172 return;
173 rebuildLinkEditAndLoadCommands();
174 }
175
176 template <typename P>
177 uint64_t Adjustor<P>::slideForOrigAddress(uint64_t addr)
178 {
179 for (unsigned i=0; i < _segOrigStartAddresses.size(); ++i) {
180 if ( (_segOrigStartAddresses[i] <= addr) && (addr < (_segOrigStartAddresses[i]+_segCmds[i]->vmsize())) )
181 return _segSlides[i];
182 }
183 // On arm64, high nibble of pointers can have extra bits
184 if ( _maskPointers && (addr & 0xF000000000000000) ) {
185 return slideForOrigAddress(addr & 0x0FFFFFFFFFFFFFFF);
186 }
187 _diagnostics.error("slide not known for dylib address 0x%llX in %s", addr, _installName);
188 return 0;
189 }
190
191 template <typename P>
192 void Adjustor<P>::rebuildLinkEditAndLoadCommands()
193 {
194 // Exports trie is only data structure in LINKEDIT that might grow
195 std::vector<uint8_t> newTrieBytes;
196 adjustExportsTrie(newTrieBytes);
197
198 // Remove: code signature, rebase info, code-sign-dirs, split seg info
199 uint32_t bindOffset = 0;
200 uint32_t bindSize = _dyldInfo->bind_size();
201 uint32_t lazyBindOffset = bindOffset + bindSize;
202 uint32_t lazyBindSize = _dyldInfo->lazy_bind_size();
203 uint32_t weakBindOffset = lazyBindOffset + lazyBindSize;
204 uint32_t weakBindSize = _dyldInfo->weak_bind_size();
205 uint32_t exportOffset = weakBindOffset + weakBindSize;
206 uint32_t exportSize = (uint32_t)newTrieBytes.size();
207 uint32_t splitSegInfoOffset = exportOffset + exportSize;
208 uint32_t splitSegInfosSize = (_splitSegInfoCmd ? _splitSegInfoCmd->datasize() : 0);
209 uint32_t funcStartsOffset = splitSegInfoOffset + splitSegInfosSize;
210 uint32_t funcStartsSize = (_functionStartsCmd ? _functionStartsCmd->datasize() : 0);
211 uint32_t dataInCodeOffset = funcStartsOffset + funcStartsSize;
212 uint32_t dataInCodeSize = (_dataInCodeCmd ? _dataInCodeCmd->datasize() : 0);
213 uint32_t symbolTableOffset = dataInCodeOffset + dataInCodeSize;
214 uint32_t symbolTableSize = _symTabCmd->nsyms() * sizeof(macho_nlist<P>);
215 uint32_t indirectTableOffset = symbolTableOffset + symbolTableSize;
216 uint32_t indirectTableSize = _dynSymTabCmd->nindirectsyms() * sizeof(uint32_t);
217 uint32_t symbolStringsOffset = indirectTableOffset + indirectTableSize;
218 uint32_t symbolStringsSize = _symTabCmd->strsize();
219 uint32_t newLinkEditSize = symbolStringsOffset + symbolStringsSize;
220
221 size_t linkeditBufferSize = align(_segCmds[_linkeditSegIndex]->vmsize(), 12);
222 if ( linkeditBufferSize < newLinkEditSize ) {
223 _diagnostics.error("LINKEDIT overflow in %s", _installName);
224 return;
225 }
226
227 uint32_t linkeditStartOffset = (uint32_t)_mappingInfo[_linkeditSegIndex].dstCacheOffset;
228 uint8_t* newLinkeditBufer = (uint8_t*)::calloc(linkeditBufferSize, 1);
229 if ( bindSize )
230 memcpy(&newLinkeditBufer[bindOffset], &_linkeditBias[_dyldInfo->bind_off()], bindSize);
231 if ( lazyBindSize )
232 memcpy(&newLinkeditBufer[lazyBindOffset], &_linkeditBias[_dyldInfo->lazy_bind_off()], lazyBindSize);
233 if ( weakBindSize )
234 memcpy(&newLinkeditBufer[weakBindOffset], &_linkeditBias[_dyldInfo->weak_bind_off()], weakBindSize);
235 if ( exportSize )
236 memcpy(&newLinkeditBufer[exportOffset], &newTrieBytes[0], exportSize);
237 if ( splitSegInfosSize )
238 memcpy(&newLinkeditBufer[splitSegInfoOffset], &_linkeditBias[_splitSegInfoCmd->dataoff()], splitSegInfosSize);
239 if ( funcStartsSize )
240 memcpy(&newLinkeditBufer[funcStartsOffset], &_linkeditBias[_functionStartsCmd->dataoff()], funcStartsSize);
241 if ( dataInCodeSize )
242 memcpy(&newLinkeditBufer[dataInCodeOffset], &_linkeditBias[_dataInCodeCmd->dataoff()], dataInCodeSize);
243 if ( symbolTableSize )
244 memcpy(&newLinkeditBufer[symbolTableOffset], &_linkeditBias[_symTabCmd->symoff()], symbolTableSize);
245 if ( indirectTableSize )
246 memcpy(&newLinkeditBufer[indirectTableOffset], &_linkeditBias[_dynSymTabCmd->indirectsymoff()], indirectTableSize);
247 if ( symbolStringsSize )
248 memcpy(&newLinkeditBufer[symbolStringsOffset], &_linkeditBias[_symTabCmd->stroff()], symbolStringsSize);
249
250 memcpy((uint8_t*)_cacheBuffer+linkeditStartOffset, newLinkeditBufer, newLinkEditSize);
251 ::bzero((uint8_t*)_cacheBuffer+linkeditStartOffset+newLinkEditSize, linkeditBufferSize-newLinkEditSize);
252 ::free(newLinkeditBufer);
253
254 // updates load commands and removed ones no longer needed
255 macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)_mh + sizeof(macho_header<P>));
256 uint32_t cmd_count = _mh->ncmds();
257 const macho_load_command<P>* cmd = cmds;
258 const unsigned origLoadCommandsSize = _mh->sizeofcmds();
259 unsigned bytesRemaining = origLoadCommandsSize;
260 unsigned removedCount = 0;
261 unsigned segIndex = 0;
262 for (uint32_t i = 0; i < cmd_count; ++i) {
263 macho_symtab_command<P>* symTabCmd;
264 macho_dysymtab_command<P>* dynSymTabCmd;
265 macho_dyld_info_command<P>* dyldInfo;
266 macho_linkedit_data_command<P>* functionStartsCmd;
267 macho_linkedit_data_command<P>* dataInCodeCmd;
268 macho_linkedit_data_command<P>* splitSegInfoCmd;
269 macho_segment_command<P>* segCmd;
270 macho_routines_command<P>* routinesCmd;
271 macho_dylib_command<P>* dylibIDCmd;
272 uint32_t cmdSize = cmd->cmdsize();
273 int32_t segFileOffsetDelta;
274 bool remove = false;
275 switch ( cmd->cmd() ) {
276 case LC_ID_DYLIB:
277 dylibIDCmd = (macho_dylib_command<P>*)cmd;
278 dylibIDCmd->set_timestamp(2); // match what static linker sets in LC_LOAD_DYLIB
279 break;
280 case LC_SYMTAB:
281 symTabCmd = (macho_symtab_command<P>*)cmd;
282 symTabCmd->set_symoff(linkeditStartOffset+symbolTableOffset);
283 symTabCmd->set_stroff(linkeditStartOffset+symbolStringsOffset);
284 break;
285 case LC_DYSYMTAB:
286 dynSymTabCmd = (macho_dysymtab_command<P>*)cmd;
287 dynSymTabCmd->set_indirectsymoff(linkeditStartOffset+indirectTableOffset);
288 break;
289 case LC_DYLD_INFO:
290 case LC_DYLD_INFO_ONLY:
291 dyldInfo = (macho_dyld_info_command<P>*)cmd;
292 dyldInfo->set_rebase_off(0);
293 dyldInfo->set_rebase_size(0);
294 dyldInfo->set_bind_off(bindSize ? linkeditStartOffset+bindOffset : 0);
295 dyldInfo->set_bind_size(bindSize);
296 dyldInfo->set_weak_bind_off(weakBindSize ? linkeditStartOffset+weakBindOffset : 0);
297 dyldInfo->set_weak_bind_size(weakBindSize);
298 dyldInfo->set_lazy_bind_off(lazyBindSize ? linkeditStartOffset+lazyBindOffset : 0);
299 dyldInfo->set_lazy_bind_size(lazyBindSize);
300 dyldInfo->set_export_off(exportSize ? linkeditStartOffset+exportOffset : 0);
301 dyldInfo->set_export_size(exportSize);
302 break;
303 case LC_FUNCTION_STARTS:
304 functionStartsCmd = (macho_linkedit_data_command<P>*)cmd;
305 functionStartsCmd->set_dataoff(linkeditStartOffset+funcStartsOffset);
306 break;
307 case LC_DATA_IN_CODE:
308 dataInCodeCmd = (macho_linkedit_data_command<P>*)cmd;
309 dataInCodeCmd->set_dataoff(linkeditStartOffset+dataInCodeOffset);
310 break;
311 case macho_routines_command<P>::CMD:
312 routinesCmd = (macho_routines_command<P>*)cmd;
313 routinesCmd->set_init_address(routinesCmd->init_address()+slideForOrigAddress(routinesCmd->init_address()));
314 break;
315 case macho_segment_command<P>::CMD:
316 segCmd = (macho_segment_command<P>*)cmd;
317 segFileOffsetDelta = (int32_t)(_mappingInfo[segIndex].dstCacheOffset - segCmd->fileoff());
318 segCmd->set_vmaddr(_mappingInfo[segIndex].dstCacheAddress);
319 segCmd->set_vmsize(_mappingInfo[segIndex].dstCacheSegmentSize);
320 segCmd->set_fileoff(_mappingInfo[segIndex].dstCacheOffset);
321 segCmd->set_filesize(_mappingInfo[segIndex].copySegmentSize);
322 if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
323 segCmd->set_vmsize(linkeditBufferSize);
324 if ( segCmd->nsects() > 0 ) {
325 macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
326 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
327 for (macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
328 sect->set_addr(sect->addr() + _segSlides[segIndex]);
329 if ( sect->offset() != 0 )
330 sect->set_offset(sect->offset() + segFileOffsetDelta);
331 }
332 }
333 ++segIndex;
334 break;
335 case LC_RPATH:
336 _diagnostics.warning("dyld shared cache does not support LC_RPATH found in %s", _installName);
337 remove = true;
338 break;
339 case LC_SEGMENT_SPLIT_INFO:
340 splitSegInfoCmd = (macho_linkedit_data_command<P>*)cmd;
341 splitSegInfoCmd->set_dataoff(linkeditStartOffset+splitSegInfoOffset);
342 break;
343 case LC_CODE_SIGNATURE:
344 case LC_DYLIB_CODE_SIGN_DRS:
345 remove = true;
346 break;
347 default:
348 break;
349 }
350 macho_load_command<P>* nextCmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmdSize);
351 if ( remove ) {
352 ::memmove((void*)cmd, (void*)nextCmd, bytesRemaining);
353 ++removedCount;
354 }
355 else {
356 bytesRemaining -= cmdSize;
357 cmd = nextCmd;
358 }
359 }
360 // zero out stuff removed
361 ::bzero((void*)cmd, bytesRemaining);
362 // update header
363 _mh->set_ncmds(cmd_count-removedCount);
364 _mh->set_sizeofcmds(origLoadCommandsSize-bytesRemaining);
365 _mh->set_flags(_mh->flags() | 0x80000000);
366 }
367
368
369 template <typename P>
370 void Adjustor<P>::adjustSymbolTable()
371 {
372 macho_nlist<P>* symbolTable = (macho_nlist<P>*)&_linkeditBias[_symTabCmd->symoff()];
373
374 // adjust global symbol table entries
375 macho_nlist<P>* lastExport = &symbolTable[_dynSymTabCmd->iextdefsym()+_dynSymTabCmd->nextdefsym()];
376 for (macho_nlist<P>* entry = &symbolTable[_dynSymTabCmd->iextdefsym()]; entry < lastExport; ++entry) {
377 if ( (entry->n_type() & N_TYPE) == N_SECT )
378 entry->set_n_value(entry->n_value() + slideForOrigAddress(entry->n_value()));
379 }
380
381 // adjust local symbol table entries
382 macho_nlist<P>* lastLocal = &symbolTable[_dynSymTabCmd->ilocalsym()+_dynSymTabCmd->nlocalsym()];
383 for (macho_nlist<P>* entry = &symbolTable[_dynSymTabCmd->ilocalsym()]; entry < lastLocal; ++entry) {
384 if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) )
385 entry->set_n_value(entry->n_value() + slideForOrigAddress(entry->n_value()));
386 }
387 }
388
389 template <typename P>
390 void Adjustor<P>::slidePointer(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersForASLR)
391 {
392 pint_t* mappedAddrP = (pint_t*)((uint8_t*)_cacheBuffer + _mappingInfo[segIndex].dstCacheOffset + segOffset);
393 uint32_t* mappedAddr32 = (uint32_t*)mappedAddrP;
394 pint_t valueP;
395 uint32_t value32;
396 switch ( type ) {
397 case REBASE_TYPE_POINTER:
398 valueP = (pint_t)P::getP(*mappedAddrP);
399 P::setP(*mappedAddrP, valueP + slideForOrigAddress(valueP));
400 pointersForASLR.push_back(mappedAddrP);
401 break;
402
403 case REBASE_TYPE_TEXT_ABSOLUTE32:
404 value32 = P::E::get32(*mappedAddr32);
405 P::E::set32(*mappedAddr32, value32 + (uint32_t)slideForOrigAddress(value32));
406 break;
407
408 case REBASE_TYPE_TEXT_PCREL32:
409 // general text relocs not support
410 default:
411 _diagnostics.error("unknown rebase type 0x%02X in %s", type, _installName);
412 }
413 }
414
415
416 static bool isThumbMovw(uint32_t instruction)
417 {
418 return ( (instruction & 0x8000FBF0) == 0x0000F240 );
419 }
420
421 static bool isThumbMovt(uint32_t instruction)
422 {
423 return ( (instruction & 0x8000FBF0) == 0x0000F2C0 );
424 }
425
426 static uint16_t getThumbWord(uint32_t instruction)
427 {
428 uint32_t i = ((instruction & 0x00000400) >> 10);
429 uint32_t imm4 = (instruction & 0x0000000F);
430 uint32_t imm3 = ((instruction & 0x70000000) >> 28);
431 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
432 return ((imm4 << 12) | (i << 11) | (imm3 << 8) | imm8);
433 }
434
435 static uint32_t setThumbWord(uint32_t instruction, uint16_t word) {
436 uint32_t imm4 = (word & 0xF000) >> 12;
437 uint32_t i = (word & 0x0800) >> 11;
438 uint32_t imm3 = (word & 0x0700) >> 8;
439 uint32_t imm8 = word & 0x00FF;
440 return (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
441 }
442
443 static bool isArmMovw(uint32_t instruction)
444 {
445 return (instruction & 0x0FF00000) == 0x03000000;
446 }
447
448 static bool isArmMovt(uint32_t instruction)
449 {
450 return (instruction & 0x0FF00000) == 0x03400000;
451 }
452
453 static uint16_t getArmWord(uint32_t instruction)
454 {
455 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
456 uint32_t imm12 = (instruction & 0x00000FFF);
457 return (imm4 << 12) | imm12;
458 }
459
460 static uint32_t setArmWord(uint32_t instruction, uint16_t word) {
461 uint32_t imm4 = (word & 0xF000) >> 12;
462 uint32_t imm12 = word & 0x0FFF;
463 return (instruction & 0xFFF0F000) | (imm4 << 16) | imm12;
464 }
465
466 template <typename P>
467 void Adjustor<P>::adjustReference(uint32_t kind, uint8_t* mappedAddr, uint64_t fromNewAddress, uint64_t toNewAddress,
468 int64_t adjust, int64_t targetSlide, uint64_t imageStartAddress, uint64_t imageEndAddress,
469 std::vector<void*>& pointersForASLR, uint32_t*& lastMappedAddr32, uint32_t& lastKind, uint64_t& lastToNewAddress)
470 {
471 uint64_t value64;
472 uint64_t* mappedAddr64 = 0;
473 uint32_t value32;
474 uint32_t* mappedAddr32 = 0;
475 uint32_t instruction;
476 int64_t offsetAdjust;
477 int64_t delta;
478 switch ( kind ) {
479 case DYLD_CACHE_ADJ_V2_DELTA_32:
480 mappedAddr32 = (uint32_t*)mappedAddr;
481 value32 = P::E::get32(*mappedAddr32);
482 delta = (int32_t)value32;
483 delta += adjust;
484 if ( (delta > 0x80000000) || (-delta > 0x80000000) ) {
485 _diagnostics.error("DYLD_CACHE_ADJ_V2_DELTA_32 can't be adjust by 0x%016llX in %s", adjust, _installName);
486 return;
487 }
488 P::E::set32(*mappedAddr32, (int32_t)delta);
489 break;
490 case DYLD_CACHE_ADJ_V2_POINTER_32:
491 mappedAddr32 = (uint32_t*)mappedAddr;
492 if ( toNewAddress != (E::get32(*mappedAddr32) + targetSlide) ) {
493 _diagnostics.error("bad DYLD_CACHE_ADJ_V2_POINTER_32 value not as expected at address 0x%llX in %s", fromNewAddress, _installName);
494 return;
495 }
496 E::set32(*mappedAddr32, (uint32_t)toNewAddress);
497 pointersForASLR.push_back(mappedAddr);
498 break;
499 case DYLD_CACHE_ADJ_V2_POINTER_64:
500 mappedAddr64 = (uint64_t*)mappedAddr;
501 if ( toNewAddress != (E::get64(*mappedAddr64) + targetSlide) ) {
502 _diagnostics.error("bad DYLD_CACHE_ADJ_V2_POINTER_64 value not as expected at address 0x%llX in %s", fromNewAddress, _installName);
503 return;
504 }
505 E::set64(*mappedAddr64, toNewAddress);
506 pointersForASLR.push_back(mappedAddr);
507 break;
508 case DYLD_CACHE_ADJ_V2_DELTA_64:
509 mappedAddr64 = (uint64_t*)mappedAddr;
510 value64 = P::E::get64(*mappedAddr64);
511 E::set64(*mappedAddr64, value64 + adjust);
512 break;
513 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
514 if ( adjust == 0 )
515 break;
516 mappedAddr32 = (uint32_t*)mappedAddr;
517 value32 = P::E::get32(*mappedAddr32);
518 value64 = toNewAddress - imageStartAddress;
519 if ( value64 > imageEndAddress ) {
520 _diagnostics.error("DYLD_CACHE_ADJ_V2_IMAGE_OFF_32 can't be adjust to 0x%016llX in %s", toNewAddress, _installName);
521 return;
522 }
523 P::E::set32(*mappedAddr32, (uint32_t)value64);
524 break;
525 case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
526 mappedAddr32 = (uint32_t*)mappedAddr;
527 instruction = P::E::get32(*mappedAddr32);
528 if ( (instruction & 0x9F000000) == 0x90000000 ) {
529 int64_t pageDistance = ((toNewAddress & ~0xFFF) - (fromNewAddress & ~0xFFF));
530 int64_t newPage21 = pageDistance >> 12;
531 if ( (newPage21 > 2097151) || (newPage21 < -2097151) ) {
532 _diagnostics.error("DYLD_CACHE_ADJ_V2_ARM64_ADRP can't be adjusted that far in %s", _installName);
533 return;
534 }
535 instruction = (instruction & 0x9F00001F) | ((newPage21 << 29) & 0x60000000) | ((newPage21 << 3) & 0x00FFFFE0);
536 P::E::set32(*mappedAddr32, instruction);
537 }
538 else {
539 // ADRP instructions are sometimes optimized to other instructions (e.g. ADR) after the split-seg-info is generated
540 }
541 break;
542 case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
543 mappedAddr32 = (uint32_t*)mappedAddr;
544 instruction = P::E::get32(*mappedAddr32);
545 offsetAdjust = (adjust & 0xFFF);
546 if ( offsetAdjust == 0 )
547 break;
548 if ( (instruction & 0x3B000000) == 0x39000000 ) {
549 // LDR/STR imm12
550 if ( offsetAdjust != 0 ) {
551 uint32_t encodedAddend = ((instruction & 0x003FFC00) >> 10);
552 uint32_t newAddend = 0;
553 switch ( instruction & 0xC0000000 ) {
554 case 0x00000000:
555 if ( (instruction & 0x04800000) == 0x04800000 ) {
556 if ( offsetAdjust & 0xF ) {
557 _diagnostics.error("can't adjust off12 scale=16 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust, mappedAddr, _installName);
558 return;
559 }
560 if ( encodedAddend*16 >= 4096 ) {
561 _diagnostics.error("off12 scale=16 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
562 }
563 newAddend = (encodedAddend + offsetAdjust/16) % 256;
564 }
565 else {
566 // scale=1
567 newAddend = (encodedAddend + (int32_t)offsetAdjust) % 4096;
568 }
569 break;
570 case 0x40000000:
571 if ( offsetAdjust & 1 ) {
572 _diagnostics.error("can't adjust off12 scale=2 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust, mappedAddr, _installName);
573 return;
574 }
575 if ( encodedAddend*2 >= 4096 ) {
576 _diagnostics.error("off12 scale=2 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
577 return;
578 }
579 newAddend = (encodedAddend + offsetAdjust/2) % 2048;
580 break;
581 case 0x80000000:
582 if ( offsetAdjust & 3 ) {
583 _diagnostics.error("can't adjust off12 scale=4 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust, mappedAddr, _installName);
584 return;
585 }
586 if ( encodedAddend*4 >= 4096 ) {
587 _diagnostics.error("off12 scale=4 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
588 return;
589 }
590 newAddend = (encodedAddend + offsetAdjust/4) % 1024;
591 break;
592 case 0xC0000000:
593 if ( offsetAdjust & 7 ) {
594 _diagnostics.error("can't adjust off12 scale=8 instruction by %lld bytes at mapped address=%p in %s", offsetAdjust, mappedAddr, _installName);
595 return;
596 }
597 if ( encodedAddend*8 >= 4096 ) {
598 _diagnostics.error("off12 scale=8 instruction points outside its page at mapped address=%p in %s", mappedAddr, _installName);
599 return;
600 }
601 newAddend = (encodedAddend + offsetAdjust/8) % 512;
602 break;
603 }
604 uint32_t newInstruction = (instruction & 0xFFC003FF) | (newAddend << 10);
605 P::E::set32(*mappedAddr32, newInstruction);
606 }
607 }
608 else if ( (instruction & 0xFFC00000) == 0x91000000 ) {
609 // ADD imm12
610 if ( instruction & 0x00C00000 ) {
611 _diagnostics.error("ADD off12 uses shift at mapped address=%p in %s", mappedAddr, _installName);
612 return;
613 }
614 uint32_t encodedAddend = ((instruction & 0x003FFC00) >> 10);
615 uint32_t newAddend = (encodedAddend + offsetAdjust) & 0xFFF;
616 uint32_t newInstruction = (instruction & 0xFFC003FF) | (newAddend << 10);
617 P::E::set32(*mappedAddr32, newInstruction);
618 }
619 else if ( instruction != 0xD503201F ) {
620 // ignore imm12 instructions optimized into a NOP, but warn about others
621 _diagnostics.error("unknown off12 instruction 0x%08X at 0x%0llX in %s", instruction, fromNewAddress, _installName);
622 return;
623 }
624 break;
625 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT:
626 mappedAddr32 = (uint32_t*)mappedAddr;
627 // to update a movw/movt pair we need to extract the 32-bit they will make,
628 // add the adjust and write back the new movw/movt pair.
629 if ( lastKind == kind ) {
630 if ( lastToNewAddress == toNewAddress ) {
631 uint32_t instruction1 = P::E::get32(*lastMappedAddr32);
632 uint32_t instruction2 = P::E::get32(*mappedAddr32);
633 if ( isThumbMovw(instruction1) && isThumbMovt(instruction2) ) {
634 uint16_t high = getThumbWord(instruction2);
635 uint16_t low = getThumbWord(instruction1);
636 uint32_t full = high << 16 | low;
637 full += adjust;
638 instruction1 = setThumbWord(instruction1, full & 0xFFFF);
639 instruction2 = setThumbWord(instruction2, full >> 16);
640 }
641 else if ( isThumbMovt(instruction1) && isThumbMovw(instruction2) ) {
642 uint16_t high = getThumbWord(instruction1);
643 uint16_t low = getThumbWord(instruction2);
644 uint32_t full = high << 16 | low;
645 full += adjust;
646 instruction2 = setThumbWord(instruction2, full & 0xFFFF);
647 instruction1 = setThumbWord(instruction1, full >> 16);
648 }
649 else {
650 _diagnostics.error("two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but not paried in %s", _installName);
651 return;
652 }
653 P::E::set32(*lastMappedAddr32, instruction1);
654 P::E::set32(*mappedAddr32, instruction2);
655 kind = 0;
656 }
657 else {
658 _diagnostics.error("two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but target different addresses in %s", _installName);
659 return;
660 }
661 }
662 break;
663 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT:
664 mappedAddr32 = (uint32_t*)mappedAddr;
665 // to update a movw/movt pair we need to extract the 32-bit they will make,
666 // add the adjust and write back the new movw/movt pair.
667 if ( lastKind == kind ) {
668 if ( lastToNewAddress == toNewAddress ) {
669 uint32_t instruction1 = P::E::get32(*lastMappedAddr32);
670 uint32_t instruction2 = P::E::get32(*mappedAddr32);
671 if ( isArmMovw(instruction1) && isArmMovt(instruction2) ) {
672 uint16_t high = getArmWord(instruction2);
673 uint16_t low = getArmWord(instruction1);
674 uint32_t full = high << 16 | low;
675 full += adjust;
676 instruction1 = setArmWord(instruction1, full & 0xFFFF);
677 instruction2 = setArmWord(instruction2, full >> 16);
678 }
679 else if ( isArmMovt(instruction1) && isArmMovw(instruction2) ) {
680 uint16_t high = getArmWord(instruction1);
681 uint16_t low = getArmWord(instruction2);
682 uint32_t full = high << 16 | low;
683 full += adjust;
684 instruction2 = setArmWord(instruction2, full & 0xFFFF);
685 instruction1 = setArmWord(instruction1, full >> 16);
686 }
687 else {
688 _diagnostics.error("two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but not paired in %s", _installName);
689 return;
690 }
691 P::E::set32(*lastMappedAddr32, instruction1);
692 P::E::set32(*mappedAddr32, instruction2);
693 kind = 0;
694 }
695 else {
696 _diagnostics.error("two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but target different addresses in %s", _installName);
697 return;
698 }
699 }
700 break;
701 case DYLD_CACHE_ADJ_V2_ARM64_BR26:
702 case DYLD_CACHE_ADJ_V2_THUMB_BR22:
703 case DYLD_CACHE_ADJ_V2_ARM_BR24:
704 // nothing to do with calls to stubs
705 break;
706 default:
707 _diagnostics.error("unknown split seg kind=%d in %s", kind, _installName);
708 return;
709 }
710 lastKind = kind;
711 lastToNewAddress = toNewAddress;
712 lastMappedAddr32 = mappedAddr32;
713 }
714
715 template <typename P>
716 void Adjustor<P>::adjustReferencesUsingInfoV2(std::vector<void*>& pointersForASLR)
717 {
718 static const bool log = false;
719
720 const uint8_t* infoStart = &_linkeditBias[_splitSegInfoCmd->dataoff()];
721 const uint8_t* infoEnd = &infoStart[_splitSegInfoCmd->datasize()];
722 if ( *infoStart++ != DYLD_CACHE_ADJ_V2_FORMAT ) {
723 _diagnostics.error("malformed split seg info in %s", _installName);
724 return;
725 }
726 // build section arrays of slide and mapped address for each section
727 std::vector<uint64_t> sectionSlides;
728 std::vector<uint64_t> sectionNewAddress;
729 std::vector<uint8_t*> sectionMappedAddress;
730 sectionSlides.reserve(16);
731 sectionNewAddress.reserve(16);
732 sectionMappedAddress.reserve(16);
733 // section index 0 refers to mach_header
734 sectionMappedAddress.push_back((uint8_t*)_cacheBuffer + _mappingInfo[0].dstCacheOffset);
735 sectionSlides.push_back(_segSlides[0]);
736 sectionNewAddress.push_back(_mappingInfo[0].dstCacheAddress);
737 // section 1 and later refer to real sections
738 unsigned sectionIndex = 0;
739 for (unsigned segmentIndex=0; segmentIndex < _segCmds.size(); ++segmentIndex) {
740 macho_segment_command<P>* segCmd = _segCmds[segmentIndex];
741 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
742 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
743 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
744 sectionMappedAddress.push_back((uint8_t*)_cacheBuffer + _mappingInfo[segmentIndex].dstCacheOffset + sect->addr() - segCmd->vmaddr());
745 sectionSlides.push_back(_segSlides[segmentIndex]);
746 sectionNewAddress.push_back(_mappingInfo[segmentIndex].dstCacheAddress + sect->addr() - segCmd->vmaddr());
747 if (log) {
748 fprintf(stderr, " %s/%s, sectIndex=%d, mapped at=%p\n",
749 sect->segname(), sect->sectname(), sectionIndex, sectionMappedAddress.back());
750 }
751 ++sectionIndex;
752 }
753 }
754
755 // Whole :== <count> FromToSection+
756 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
757 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
758 // FromOffset :== <kind> <count> <from-sect-offset-delta>
759 const uint8_t* p = infoStart;
760 uint64_t sectionCount = read_uleb128(p, infoEnd);
761 for (uint64_t i=0; i < sectionCount; ++i) {
762 uint32_t* lastMappedAddr32 = NULL;
763 uint32_t lastKind = 0;
764 uint64_t lastToNewAddress = 0;
765 uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
766 uint64_t toSectionIndex = read_uleb128(p, infoEnd);
767 uint64_t toOffsetCount = read_uleb128(p, infoEnd);
768 uint64_t fromSectionSlide = sectionSlides[fromSectionIndex];
769 uint64_t fromSectionNewAddress = sectionNewAddress[fromSectionIndex];
770 uint8_t* fromSectionMappedAddress = sectionMappedAddress[fromSectionIndex];
771 uint64_t toSectionSlide = sectionSlides[toSectionIndex];
772 uint64_t toSectionNewAddress = sectionNewAddress[toSectionIndex];
773 if (log) printf(" from sect=%lld (mapped=%p), to sect=%lld (new addr=0x%llX):\n", fromSectionIndex, fromSectionMappedAddress, toSectionIndex, toSectionNewAddress);
774 uint64_t toSectionOffset = 0;
775 for (uint64_t j=0; j < toOffsetCount; ++j) {
776 uint64_t toSectionDelta = read_uleb128(p, infoEnd);
777 uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
778 toSectionOffset += toSectionDelta;
779 for (uint64_t k=0; k < fromOffsetCount; ++k) {
780 uint64_t kind = read_uleb128(p, infoEnd);
781 if ( kind > 12 ) {
782 _diagnostics.error("bad kind value (%llu) in %s", kind, _installName);
783 return;
784 }
785 uint64_t fromSectDeltaCount = read_uleb128(p, infoEnd);
786 uint64_t fromSectionOffset = 0;
787 for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
788 uint64_t delta = read_uleb128(p, infoEnd);
789 fromSectionOffset += delta;
790 int64_t deltaAdjust = toSectionSlide - fromSectionSlide;
791 //if (log) printf(" kind=%lld, from offset=0x%0llX, to offset=0x%0llX, adjust=0x%llX, targetSlide=0x%llX\n", kind, fromSectionOffset, toSectionOffset, deltaAdjust, toSectionSlide);
792 uint8_t* fromMappedAddr = fromSectionMappedAddress + fromSectionOffset;
793 uint64_t toNewAddress = toSectionNewAddress + toSectionOffset;
794 uint64_t fromNewAddress = fromSectionNewAddress + fromSectionOffset;
795 uint64_t imageStartAddress = sectionNewAddress.front();
796 uint64_t imageEndAddress = sectionNewAddress.back();
797 if ( toSectionIndex != 255 )
798 adjustReference((uint32_t)kind, fromMappedAddr, fromNewAddress, toNewAddress, deltaAdjust, toSectionSlide, imageStartAddress, imageEndAddress, pointersForASLR, lastMappedAddr32, lastKind, lastToNewAddress);
799 if ( _diagnostics.hasError() )
800 return;
801 }
802 }
803 }
804 }
805
806 }
807
808 template <typename P>
809 void Adjustor<P>::adjustDataPointers(std::vector<void*>& pointersForASLR)
810 {
811 const uint8_t* p = &_linkeditBias[_dyldInfo->rebase_off()];
812 const uint8_t* end = &p[_dyldInfo->rebase_size()];
813
814 uint8_t type = 0;
815 int segIndex = 0;
816 uint64_t segOffset = 0;
817 uint64_t count;
818 uint64_t skip;
819 bool done = false;
820 while ( !done && (p < end) ) {
821 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
822 uint8_t opcode = *p & REBASE_OPCODE_MASK;
823 ++p;
824 switch (opcode) {
825 case REBASE_OPCODE_DONE:
826 done = true;
827 break;
828 case REBASE_OPCODE_SET_TYPE_IMM:
829 type = immediate;
830 break;
831 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
832 segIndex = immediate;
833 segOffset = read_uleb128(p, end);
834 break;
835 case REBASE_OPCODE_ADD_ADDR_ULEB:
836 segOffset += read_uleb128(p, end);
837 break;
838 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
839 segOffset += immediate*sizeof(pint_t);
840 break;
841 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
842 for (int i=0; i < immediate; ++i) {
843 slidePointer(segIndex, segOffset, type, pointersForASLR);
844 segOffset += sizeof(pint_t);
845 }
846 break;
847 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
848 count = read_uleb128(p, end);
849 for (uint32_t i=0; i < count; ++i) {
850 slidePointer(segIndex, segOffset, type, pointersForASLR);
851 segOffset += sizeof(pint_t);
852 }
853 break;
854 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
855 slidePointer(segIndex, segOffset, type, pointersForASLR);
856 segOffset += read_uleb128(p, end) + sizeof(pint_t);
857 break;
858 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
859 count = read_uleb128(p, end);
860 skip = read_uleb128(p, end);
861 for (uint32_t i=0; i < count; ++i) {
862 slidePointer(segIndex, segOffset, type, pointersForASLR);
863 segOffset += skip + sizeof(pint_t);
864 }
865 break;
866 default:
867 _diagnostics.error("unknown rebase opcode 0x%02X in %s", opcode, _installName);
868 done = true;
869 break;
870 }
871 }
872 }
873
874
875 template <typename P>
876 void Adjustor<P>::adjustInstruction(uint8_t kind, uint64_t cacheOffset, uint64_t codeToDataDelta)
877 {
878 uint8_t* fixupLoc = (uint8_t*)_cacheBuffer + cacheOffset;
879 uint32_t* fixupLoc32 = (uint32_t*)fixupLoc;
880 uint64_t* fixupLoc64 = (uint64_t*)fixupLoc;
881 uint32_t instruction;
882 uint32_t value32;
883 uint64_t value64;
884
885 switch (kind) {
886 case 1: // 32-bit pointer (including x86_64 RIP-rel)
887 value32 = P::E::get32(*fixupLoc32);
888 value32 += codeToDataDelta;
889 P::E::set32(*fixupLoc32, value32);
890 break;
891 case 2: // 64-bit pointer
892 value64 = P::E::get64(*fixupLoc64);
893 value64 += codeToDataDelta;
894 P::E::set64(*fixupLoc64, value64);
895 break;
896 case 4: // only used for i386, a reference to something in the IMPORT segment
897 break;
898 case 5: // used by thumb2 movw
899 instruction = P::E::get32(*fixupLoc32);
900 // slide is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
901 value32 = (instruction & 0x0000000F) + ((uint32_t)codeToDataDelta >> 12);
902 instruction = (instruction & 0xFFFFFFF0) | (value32 & 0x0000000F);
903 P::E::set32(*fixupLoc32, instruction);
904 break;
905 case 6: // used by ARM movw
906 instruction = P::E::get32(*fixupLoc32);
907 // slide is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
908 value32 = ((instruction & 0x000F0000) >> 16) + ((uint32_t)codeToDataDelta >> 12);
909 instruction = (instruction & 0xFFF0FFFF) | ((value32 <<16) & 0x000F0000);
910 P::E::set32(*fixupLoc32, instruction);
911 break;
912 case 0x10:
913 case 0x11:
914 case 0x12:
915 case 0x13:
916 case 0x14:
917 case 0x15:
918 case 0x16:
919 case 0x17:
920 case 0x18:
921 case 0x19:
922 case 0x1A:
923 case 0x1B:
924 case 0x1C:
925 case 0x1D:
926 case 0x1E:
927 case 0x1F:
928 // used by thumb2 movt (low nibble of kind is high 4-bits of paired movw)
929 {
930 instruction = P::E::get32(*fixupLoc32);
931 assert((instruction & 0x8000FBF0) == 0x0000F2C0);
932 // extract 16-bit value from instruction
933 uint32_t i = ((instruction & 0x00000400) >> 10);
934 uint32_t imm4 = (instruction & 0x0000000F);
935 uint32_t imm3 = ((instruction & 0x70000000) >> 28);
936 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
937 uint32_t imm16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
938 // combine with codeToDataDelta and kind nibble
939 uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
940 uint32_t newTargetValue = targetValue + (uint32_t)codeToDataDelta;
941 // construct new bits slices
942 uint32_t imm4_ = (newTargetValue & 0xF0000000) >> 28;
943 uint32_t i_ = (newTargetValue & 0x08000000) >> 27;
944 uint32_t imm3_ = (newTargetValue & 0x07000000) >> 24;
945 uint32_t imm8_ = (newTargetValue & 0x00FF0000) >> 16;
946 // update instruction to match codeToDataDelta
947 uint32_t newInstruction = (instruction & 0x8F00FBF0) | imm4_ | (i_ << 10) | (imm3_ << 28) | (imm8_ << 16);
948 P::E::set32(*fixupLoc32, newInstruction);
949 }
950 break;
951 case 0x20:
952 case 0x21:
953 case 0x22:
954 case 0x23:
955 case 0x24:
956 case 0x25:
957 case 0x26:
958 case 0x27:
959 case 0x28:
960 case 0x29:
961 case 0x2A:
962 case 0x2B:
963 case 0x2C:
964 case 0x2D:
965 case 0x2E:
966 case 0x2F:
967 // used by arm movt (low nibble of kind is high 4-bits of paired movw)
968 {
969 instruction = P::E::get32(*fixupLoc32);
970 // extract 16-bit value from instruction
971 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
972 uint32_t imm12 = (instruction & 0x00000FFF);
973 uint32_t imm16 = (imm4 << 12) | imm12;
974 // combine with codeToDataDelta and kind nibble
975 uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
976 uint32_t newTargetValue = targetValue + (uint32_t)codeToDataDelta;
977 // construct new bits slices
978 uint32_t imm4_ = (newTargetValue & 0xF0000000) >> 28;
979 uint32_t imm12_ = (newTargetValue & 0x0FFF0000) >> 16;
980 // update instruction to match codeToDataDelta
981 uint32_t newInstruction = (instruction & 0xFFF0F000) | (imm4_ << 16) | imm12_;
982 P::E::set32(*fixupLoc32, newInstruction);
983 }
984 break;
985 case 3: // used for arm64 ADRP
986 instruction = P::E::get32(*fixupLoc32);
987 if ( (instruction & 0x9F000000) == 0x90000000 ) {
988 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
989 value64 = ((instruction & 0x60000000) >> 17) | ((instruction & 0x00FFFFE0) << 9);
990 value64 += codeToDataDelta;
991 instruction = (instruction & 0x9F00001F) | ((value64 << 17) & 0x60000000) | ((value64 >> 9) & 0x00FFFFE0);
992 P::E::set32(*fixupLoc32, instruction);
993 }
994 break;
995 default:
996 break;
997 }
998 }
999
1000 template <typename P>
1001 void Adjustor<P>::adjustCode()
1002 {
1003 // find compressed info on how code needs to be updated
1004 const uint8_t* infoStart = &_linkeditBias[_splitSegInfoCmd->dataoff()];
1005 const uint8_t* infoEnd = &infoStart[_splitSegInfoCmd->datasize()];;
1006
1007 // This encoding only works if all data segments slide by the same amount
1008 uint64_t codeToDataDelta = _segSlides[1] - _segSlides[0];
1009
1010 // compressed data is: [ <kind> [uleb128-delta]+ <0> ] + <0>
1011 for (const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
1012 uint8_t kind = *p++;
1013 uint64_t cacheOffset = _mappingInfo[0].dstCacheOffset;
1014 while (uint64_t delta = read_uleb128(p, infoEnd)) {
1015 cacheOffset += delta;
1016 adjustInstruction(kind, cacheOffset, codeToDataDelta);
1017 }
1018 }
1019 }
1020
1021
1022 template <typename P>
1023 void Adjustor<P>::adjustExportsTrie(std::vector<uint8_t>& newTrieBytes)
1024 {
1025 // if no export info, nothing to adjust
1026 if ( _dyldInfo->export_size() == 0 )
1027 return;
1028
1029 // since export info addresses are offsets from mach_header, everything in __TEXT is fine
1030 // only __DATA addresses need to be updated
1031 const uint8_t* start = &_linkeditBias[_dyldInfo->export_off()];
1032 const uint8_t* end = &start[_dyldInfo->export_size()];
1033 std::vector<ExportInfoTrie::Entry> originalExports;
1034 if ( !ExportInfoTrie::parseTrie(start, end, originalExports) ) {
1035 _diagnostics.error("malformed exports trie in %s", _installName);
1036 return;
1037 }
1038
1039 std::vector<ExportInfoTrie::Entry> newExports;
1040 newExports.reserve(originalExports.size());
1041 uint64_t baseAddress = _segOrigStartAddresses[0];
1042 uint64_t baseAddressSlide = slideForOrigAddress(baseAddress);
1043 for (auto& entry: originalExports) {
1044 // remove symbols used by the static linker only
1045 if ( (strncmp(entry.name.c_str(), "$ld$", 4) == 0)
1046 || (strncmp(entry.name.c_str(), ".objc_class_name",16) == 0)
1047 || (strncmp(entry.name.c_str(), ".objc_category_name",19) == 0) ) {
1048 continue;
1049 }
1050 // adjust symbols in slid segments
1051 if ( (entry.info.flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) != EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE )
1052 entry.info.address += (slideForOrigAddress(entry.info.address + baseAddress) - baseAddressSlide);
1053 newExports.push_back(entry);
1054 }
1055
1056 // rebuild export trie
1057 newTrieBytes.reserve(_dyldInfo->export_size());
1058
1059 ExportInfoTrie(newExports).emit(newTrieBytes);
1060 // align
1061 while ( (newTrieBytes.size() % sizeof(pint_t)) != 0 )
1062 newTrieBytes.push_back(0);
1063 }
1064
1065
1066 } // anonymous namespace
1067
1068
1069 void adjustDylibSegments(DyldSharedCache* cache, bool is64, mach_header* mhInCache, const std::vector<CacheBuilder::SegmentMappingInfo>& mappingInfo, std::vector<void*>& pointersForASLR, Diagnostics& diag)
1070 {
1071 if ( is64 ) {
1072 Adjustor<Pointer64<LittleEndian>> adjustor64(cache, (macho_header<Pointer64<LittleEndian>>*)mhInCache, mappingInfo, diag);
1073 adjustor64.adjustImageForNewSegmentLocations(pointersForASLR);
1074 }
1075 else {
1076 Adjustor<Pointer32<LittleEndian>> adjustor32(cache, (macho_header<Pointer32<LittleEndian>>*)mhInCache, mappingInfo, diag);
1077 adjustor32.adjustImageForNewSegmentLocations(pointersForASLR);
1078 }
1079 }
1080
1081
1082
1083
1084