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