]> git.saurik.com Git - apple/dyld.git/blame - launch-cache/MachORebaser.hpp
dyld-360.18.tar.gz
[apple/dyld.git] / launch-cache / MachORebaser.hpp
CommitLineData
bac542e6
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006 Apple Computer, 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#ifndef __MACHO_REBASER__
26#define __MACHO_REBASER__
27
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/mman.h>
31#include <mach/mach.h>
32#include <limits.h>
33#include <stdarg.h>
34#include <stdio.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <unistd.h>
38#include <mach-o/loader.h>
39#include <mach-o/fat.h>
40#include <mach-o/reloc.h>
bac542e6 41#include <mach-o/x86_64/reloc.h>
39a8cd10 42#include <mach-o/arm/reloc.h>
bac542e6
A
43#include <vector>
44#include <set>
45
46#include "MachOFileAbstraction.hpp"
47#include "Architectures.hpp"
48#include "MachOLayout.hpp"
39a8cd10 49#include "MachOTrie.hpp"
bac542e6
A
50
51
52
53class AbstractRebaser
54{
55public:
56 virtual cpu_type_t getArchitecture() const = 0;
57 virtual uint64_t getBaseAddress() const = 0;
58 virtual uint64_t getVMSize() const = 0;
df9d6cf7 59 virtual bool rebase(std::vector<void*>&) = 0;
bac542e6
A
60};
61
62
63template <typename A>
64class Rebaser : public AbstractRebaser
65{
66public:
67 Rebaser(const MachOLayoutAbstraction&);
68 virtual ~Rebaser() {}
69
70 virtual cpu_type_t getArchitecture() const;
71 virtual uint64_t getBaseAddress() const;
72 virtual uint64_t getVMSize() const;
df9d6cf7 73 virtual bool rebase(std::vector<void*>&);
bac542e6
A
74
75protected:
76 typedef typename A::P P;
77 typedef typename A::P::E E;
78 typedef typename A::P::uint_t pint_t;
79
80 pint_t* mappedAddressForNewAddress(pint_t vmaddress);
81 pint_t getSlideForNewAddress(pint_t newAddress);
df9d6cf7 82
bac542e6 83private:
bac542e6
A
84 void adjustLoadCommands();
85 void adjustSymbolTable();
86 void adjustDATA();
87 void adjustCode();
412ebb8e 88 void applyRebaseInfo(std::vector<void*>& pointersInData);
df9d6cf7
A
89 void adjustReferencesUsingInfoV2(std::vector<void*>& pointersInData);
90 void adjustReference(uint32_t kind, uint8_t* mappedAddr, uint64_t fromNewAddress, uint64_t toNewAddress, int64_t adjust, int64_t targetSlide,
91 uint64_t imageStartAddress, uint64_t imageEndAddress, std::vector<void*>& pointersInData);
92 bool adjustExportInfo();
412ebb8e 93 void doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData);
bac542e6 94 pint_t getSlideForVMAddress(pint_t vmaddress);
19894a12 95 pint_t maskedVMAddress(pint_t vmaddress);
bac542e6 96 pint_t* mappedAddressForVMAddress(pint_t vmaddress);
bac542e6
A
97 const uint8_t* doCodeUpdateForEachULEB128Address(const uint8_t* p, uint8_t kind, uint64_t orgBaseAddress, int64_t codeToDataDelta, int64_t codeToImportDelta);
98 void doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta);
99 void doLocalRelocation(const macho_relocation_info<P>* reloc);
100 bool unequalSlides() const;
101
102protected:
103 const macho_header<P>* fHeader;
104 uint8_t* fLinkEditBase; // add file offset to this to get linkedit content
105 const MachOLayoutAbstraction& fLayout;
106private:
39a8cd10
A
107 const macho_symtab_command<P>* fSymbolTable;
108 const macho_dysymtab_command<P>* fDynamicSymbolTable;
109 const macho_dyld_info_command<P>* fDyldInfo;
df9d6cf7 110 const macho_linkedit_data_command<P>* fSplitSegInfo;
bac542e6 111 bool fSplittingSegments;
df9d6cf7
A
112 bool fHasSplitSegInfoV2;
113 std::vector<uint64_t> fSectionOffsetsInSegment;
bac542e6
A
114};
115
116
bac542e6
A
117template <typename A>
118Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
df9d6cf7
A
119 : fLayout(layout), fLinkEditBase(0), fSymbolTable(NULL), fDynamicSymbolTable(NULL),
120 fDyldInfo(NULL), fSplitSegInfo(NULL), fSplittingSegments(false), fHasSplitSegInfoV2(false)
bac542e6
A
121{
122 fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
123 switch ( fHeader->filetype() ) {
124 case MH_DYLIB:
125 case MH_BUNDLE:
126 break;
127 default:
128 throw "file is not a dylib or bundle";
129 }
130
131 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
132 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
133 const MachOLayoutAbstraction::Segment& seg = *it;
134 if ( strcmp(seg.name(), "__LINKEDIT") == 0 ) {
135 fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
136 break;
137 }
138 }
139 if ( fLinkEditBase == NULL )
140 throw "no __LINKEDIT segment";
141
39a8cd10
A
142 // get symbol table info
143 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
144 const uint32_t cmd_count = fHeader->ncmds();
145 const macho_load_command<P>* cmd = cmds;
146 for (uint32_t i = 0; i < cmd_count; ++i) {
147 switch (cmd->cmd()) {
148 case LC_SYMTAB:
149 fSymbolTable = (macho_symtab_command<P>*)cmd;
150 break;
151 case LC_DYSYMTAB:
152 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
153 break;
154 case LC_DYLD_INFO:
155 case LC_DYLD_INFO_ONLY:
156 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
157 break;
df9d6cf7
A
158 case LC_SEGMENT_SPLIT_INFO:
159 fSplitSegInfo = (macho_linkedit_data_command<P>*)cmd;
160 break;
161 case macho_segment_command<P>::CMD: {
162 // update segment/section file offsets
163 macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
164 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
165 macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
166 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
167 fSectionOffsetsInSegment.push_back(sect->addr() - segCmd->vmaddr());
168 }
169 }
39a8cd10
A
170 }
171 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
172 }
173
df9d6cf7
A
174 if ( fDyldInfo == NULL )
175 throw "no LC_DYLD_INFO load command";
bac542e6
A
176
177 fSplittingSegments = layout.hasSplitSegInfo() && this->unequalSlides();
df9d6cf7
A
178
179 if ( fSplitSegInfo != NULL ) {
180 const uint8_t* infoStart = &fLinkEditBase[fSplitSegInfo->dataoff()];
181 fHasSplitSegInfoV2 = ( *infoStart == DYLD_CACHE_ADJ_V2_FORMAT );
182 }
bac542e6
A
183}
184
bac542e6
A
185template <> cpu_type_t Rebaser<x86>::getArchitecture() const { return CPU_TYPE_I386; }
186template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
39a8cd10 187template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
19894a12 188template <> cpu_type_t Rebaser<arm64>::getArchitecture() const { return CPU_TYPE_ARM64; }
bac542e6
A
189
190template <typename A>
191bool Rebaser<A>::unequalSlides() const
192{
193 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
194 uint64_t slide = segments[0].newAddress() - segments[0].address();
195 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
196 const MachOLayoutAbstraction::Segment& seg = *it;
197 if ( (seg.newAddress() - seg.address()) != slide )
198 return true;
199 }
200 return false;
201}
202
203template <typename A>
204uint64_t Rebaser<A>::getBaseAddress() const
205{
206 return fLayout.getSegments()[0].address();
207}
208
209template <typename A>
210uint64_t Rebaser<A>::getVMSize() const
211{
212 uint64_t highestVMAddress = 0;
213 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
214 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
215 const MachOLayoutAbstraction::Segment& seg = *it;
216 if ( seg.address() > highestVMAddress )
217 highestVMAddress = seg.address();
218 }
219 return (((highestVMAddress - getBaseAddress()) + 4095) & (-4096));
220}
221
222
223
224template <typename A>
df9d6cf7
A
225bool Rebaser<A>::rebase(std::vector<void*>& pointersInData)
226{
227 if ( fHasSplitSegInfoV2 ) {
228 this->adjustReferencesUsingInfoV2(pointersInData);
229 }
230 else {
231 //fprintf(stderr, "warning: dylib with old split-seg info: %s\n", fLayout.getFilePath());
232 // update writable segments that have internal pointers
412ebb8e 233 this->applyRebaseInfo(pointersInData);
bac542e6 234
df9d6cf7
A
235 // if splitting segments, update code-to-data references
236 this->adjustCode();
237 }
238
bac542e6
A
239 // update load commands
240 this->adjustLoadCommands();
df9d6cf7 241
bac542e6
A
242 // update symbol table
243 this->adjustSymbolTable();
bac542e6 244
df9d6cf7
A
245 // update export info
246 return this->adjustExportInfo();
bac542e6
A
247}
248
bac542e6
A
249template <typename A>
250void Rebaser<A>::adjustLoadCommands()
251{
252 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
253 const uint32_t cmd_count = fHeader->ncmds();
254 const macho_load_command<P>* cmd = cmds;
255 for (uint32_t i = 0; i < cmd_count; ++i) {
256 switch ( cmd->cmd() ) {
257 case LC_ID_DYLIB:
258 if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
259 // clear timestamp so that any prebound clients are invalidated
260 macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
261 dylib->set_timestamp(1);
262 }
263 break;
264 case LC_LOAD_DYLIB:
265 case LC_LOAD_WEAK_DYLIB:
266 case LC_REEXPORT_DYLIB:
412ebb8e 267 case LC_LOAD_UPWARD_DYLIB:
bac542e6
A
268 if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
269 // clear expected timestamps so that this image will load with invalid prebinding
270 macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
271 dylib->set_timestamp(2);
272 }
273 break;
274 case macho_routines_command<P>::CMD:
275 // update -init command
276 {
277 struct macho_routines_command<P>* routines = (struct macho_routines_command<P>*)cmd;
278 routines->set_init_address(routines->init_address() + this->getSlideForVMAddress(routines->init_address()));
279 }
280 break;
281 case macho_segment_command<P>::CMD:
282 // update segment commands
283 {
284 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
bac542e6
A
285 pint_t slide = this->getSlideForVMAddress(seg->vmaddr());
286 seg->set_vmaddr(seg->vmaddr() + slide);
287 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
288 macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
289 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
290 sect->set_addr(sect->addr() + slide);
291 }
292 }
293 break;
294 }
295 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
296 }
297}
298
19894a12
A
299template <>
300uint64_t Rebaser<arm64>::maskedVMAddress(pint_t vmaddress)
301{
302 return (vmaddress & 0x0FFFFFFFFFFFFFFF);
303}
304
305template <typename A>
306typename A::P::uint_t Rebaser<A>::maskedVMAddress(pint_t vmaddress)
307{
308 return vmaddress;
309}
bac542e6
A
310
311
312template <typename A>
313typename A::P::uint_t Rebaser<A>::getSlideForVMAddress(pint_t vmaddress)
314{
19894a12 315 pint_t vmaddr = this->maskedVMAddress(vmaddress);
bac542e6
A
316 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
317 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
318 const MachOLayoutAbstraction::Segment& seg = *it;
19894a12 319 if ( (seg.address() <= vmaddr) && (seg.size() != 0) && ((vmaddr < (seg.address()+seg.size())) || (seg.address() == vmaddr)) ) {
bac542e6
A
320 return seg.newAddress() - seg.address();
321 }
322 }
19894a12 323 throwf("vm address 0x%08llX not found", (uint64_t)vmaddr);
bac542e6
A
324}
325
326
327template <typename A>
328typename A::P::uint_t* Rebaser<A>::mappedAddressForVMAddress(pint_t vmaddress)
329{
19894a12 330 pint_t vmaddr = this->maskedVMAddress(vmaddress);
bac542e6
A
331 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
332 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
333 const MachOLayoutAbstraction::Segment& seg = *it;
19894a12
A
334 if ( (seg.address() <= vmaddr) && (vmaddr < (seg.address()+seg.size())) ) {
335 return (pint_t*)((vmaddr - seg.address()) + (uint8_t*)seg.mappedAddress());
bac542e6
A
336 }
337 }
19894a12 338 throwf("mappedAddressForVMAddress(0x%08llX) not found", (uint64_t)vmaddr);
bac542e6
A
339}
340
341template <typename A>
342typename A::P::uint_t* Rebaser<A>::mappedAddressForNewAddress(pint_t vmaddress)
343{
344 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
345 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
346 const MachOLayoutAbstraction::Segment& seg = *it;
347 if ( (seg.newAddress() <= vmaddress) && (vmaddress < (seg.newAddress()+seg.size())) ) {
348 return (pint_t*)((vmaddress - seg.newAddress()) + (uint8_t*)seg.mappedAddress());
349 }
350 }
351 throwf("mappedAddressForNewAddress(0x%08llX) not found", (uint64_t)vmaddress);
352}
353
354template <typename A>
355typename A::P::uint_t Rebaser<A>::getSlideForNewAddress(pint_t newAddress)
356{
357 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
358 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
359 const MachOLayoutAbstraction::Segment& seg = *it;
360 if ( (seg.newAddress() <= newAddress) && (newAddress < (seg.newAddress()+seg.size())) ) {
361 return seg.newAddress() - seg.address();
362 }
363 }
364 throwf("new address 0x%08llX not found", (uint64_t)newAddress);
365}
366
bac542e6
A
367template <typename A>
368void Rebaser<A>::adjustSymbolTable()
369{
39a8cd10 370 macho_nlist<P>* symbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTable->symoff()]);
bac542e6
A
371
372 // walk all exports and slide their n_value
39a8cd10
A
373 macho_nlist<P>* lastExport = &symbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
374 for (macho_nlist<P>* entry = &symbolTable[fDynamicSymbolTable->iextdefsym()]; entry < lastExport; ++entry) {
bac542e6
A
375 if ( (entry->n_type() & N_TYPE) == N_SECT )
376 entry->set_n_value(entry->n_value() + this->getSlideForVMAddress(entry->n_value()));
377 }
378
39a8cd10
A
379 // walk all local symbols and slide their n_value (don't adjust any stabs)
380 macho_nlist<P>* lastLocal = &symbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
381 for (macho_nlist<P>* entry = &symbolTable[fDynamicSymbolTable->ilocalsym()]; entry < lastLocal; ++entry) {
bac542e6
A
382 if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) )
383 entry->set_n_value(entry->n_value() + this->getSlideForVMAddress(entry->n_value()));
384 }
385}
386
39a8cd10 387template <typename A>
df9d6cf7 388bool Rebaser<A>::adjustExportInfo()
39a8cd10
A
389{
390 // if no export info, nothing to adjust
391 if ( fDyldInfo->export_size() == 0 )
df9d6cf7 392 return true;
39a8cd10
A
393
394 // since export info addresses are offsets from mach_header, everything in __TEXT is fine
395 // only __DATA addresses need to be updated
df9d6cf7 396 const uint8_t* start = fLayout.getDyldInfoExports();
39a8cd10
A
397 const uint8_t* end = &start[fDyldInfo->export_size()];
398 std::vector<mach_o::trie::Entry> originalExports;
399 try {
400 parseTrie(start, end, originalExports);
401 }
402 catch (const char* msg) {
403 throwf("%s in %s", msg, fLayout.getFilePath());
404 }
405
406 std::vector<mach_o::trie::Entry> newExports;
407 newExports.reserve(originalExports.size());
408 pint_t baseAddress = this->getBaseAddress();
409 pint_t baseAddressSlide = this->getSlideForVMAddress(baseAddress);
410 for (std::vector<mach_o::trie::Entry>::iterator it=originalExports.begin(); it != originalExports.end(); ++it) {
411 // remove symbols used by the static linker only
412 if ( (strncmp(it->name, "$ld$", 4) == 0)
413 || (strncmp(it->name, ".objc_class_name",16) == 0)
414 || (strncmp(it->name, ".objc_category_name",19) == 0) ) {
415 //fprintf(stderr, "ignoring symbol %s\n", it->name);
416 continue;
417 }
418 // adjust symbols in slid segments
419 //uint32_t oldOffset = it->address;
420 it->address += (this->getSlideForVMAddress(it->address + baseAddress) - baseAddressSlide);
421 //fprintf(stderr, "orig=0x%08X, new=0x%08llX, sym=%s\n", oldOffset, it->address, it->name);
422 newExports.push_back(*it);
423 }
424
425 // rebuild export trie
426 std::vector<uint8_t> newExportTrieBytes;
427 newExportTrieBytes.reserve(fDyldInfo->export_size());
428 mach_o::trie::makeTrie(newExports, newExportTrieBytes);
429 // align
430 while ( (newExportTrieBytes.size() % sizeof(pint_t)) != 0 )
431 newExportTrieBytes.push_back(0);
432
39a8cd10 433 uint32_t newExportsSize = newExportTrieBytes.size();
df9d6cf7
A
434 if ( newExportsSize <= fDyldInfo->export_size() ) {
435 // override existing trie in place
436 uint8_t *realStart = &fLinkEditBase[fDyldInfo->export_off()];
437 bzero(realStart, fDyldInfo->export_size());
438 memcpy(realStart, &newExportTrieBytes[0], newExportsSize);
439 fLayout.setDyldInfoExports(realStart);
440 return true;
441 }
442 else {
443 // allocate new buffer and set export_off in layout object to use new buffer instead
444 uint8_t* sideTrie = new uint8_t[newExportsSize];
445 memcpy(sideTrie, &newExportTrieBytes[0], newExportsSize);
446 fLayout.setDyldInfoExports(sideTrie);
447 ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_off(0); // invalidate old trie
448 ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
449 return false;
450 }
39a8cd10 451}
bac542e6
A
452
453
454
455template <typename A>
456void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta)
457{
412ebb8e
A
458 //fprintf(stderr, "doCodeUpdate(kind=%d, address=0x%0llX, dataDelta=0x%08llX, importDelta=0x%08llX, path=%s)\n",
459 // kind, address, codeToDataDelta, codeToImportDelta, fLayout.getFilePath());
bac542e6
A
460 uint32_t* p;
461 uint32_t instruction;
462 uint32_t value;
463 uint64_t value64;
464 switch (kind) {
465 case 1: // 32-bit pointer
466 p = (uint32_t*)mappedAddressForVMAddress(address);
467 value = A::P::E::get32(*p);
468 value += codeToDataDelta;
469 A::P::E::set32(*p, value);
470 break;
471 case 2: // 64-bit pointer
472 p = (uint32_t*)mappedAddressForVMAddress(address);
473 value64 = A::P::E::get64(*(uint64_t*)p);
474 value64 += codeToDataDelta;
475 A::P::E::set64(*(uint64_t*)p, value64);
476 break;
bac542e6
A
477 case 4: // only used for i386, a reference to something in the IMPORT segment
478 p = (uint32_t*)mappedAddressForVMAddress(address);
479 value = A::P::E::get32(*p);
480 value += codeToImportDelta;
481 A::P::E::set32(*p, value);
832b6fce
A
482 break;
483 case 5: // used by thumb2 movw
484 p = (uint32_t*)mappedAddressForVMAddress(address);
485 instruction = A::P::E::get32(*p);
486 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
487 value = (instruction & 0x0000000F) + (codeToDataDelta >> 12);
488 instruction = (instruction & 0xFFFFFFF0) | (value & 0x0000000F);
489 A::P::E::set32(*p, instruction);
490 break;
491 case 6: // used by ARM movw
492 p = (uint32_t*)mappedAddressForVMAddress(address);
493 instruction = A::P::E::get32(*p);
494 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
495 value = ((instruction & 0x000F0000) >> 16) + (codeToDataDelta >> 12);
496 instruction = (instruction & 0xFFF0FFFF) | ((value <<16) & 0x000F0000);
497 A::P::E::set32(*p, instruction);
bac542e6 498 break;
832b6fce
A
499 case 0x10:
500 case 0x11:
501 case 0x12:
502 case 0x13:
503 case 0x14:
504 case 0x15:
505 case 0x16:
506 case 0x17:
507 case 0x18:
508 case 0x19:
509 case 0x1A:
510 case 0x1B:
511 case 0x1C:
512 case 0x1D:
513 case 0x1E:
514 case 0x1F:
515 // used by thumb2 movt (low nibble of kind is high 4-bits of paired movw)
516 {
517 p = (uint32_t*)mappedAddressForVMAddress(address);
518 instruction = A::P::E::get32(*p);
519 // extract 16-bit value from instruction
520 uint32_t i = ((instruction & 0x00000400) >> 10);
521 uint32_t imm4 = (instruction & 0x0000000F);
522 uint32_t imm3 = ((instruction & 0x70000000) >> 28);
523 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
524 uint32_t imm16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
525 // combine with codeToDataDelta and kind nibble
526 uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
527 uint32_t newTargetValue = targetValue + codeToDataDelta;
528 // construct new bits slices
529 uint32_t imm4_ = (newTargetValue & 0xF0000000) >> 28;
530 uint32_t i_ = (newTargetValue & 0x08000000) >> 27;
531 uint32_t imm3_ = (newTargetValue & 0x07000000) >> 24;
532 uint32_t imm8_ = (newTargetValue & 0x00FF0000) >> 16;
533 // update instruction to match codeToDataDelta
534 uint32_t newInstruction = (instruction & 0x8F00FBF0) | imm4_ | (i_ << 10) | (imm3_ << 28) | (imm8_ << 16);
535 A::P::E::set32(*p, newInstruction);
536 }
537 break;
538 case 0x20:
539 case 0x21:
540 case 0x22:
541 case 0x23:
542 case 0x24:
543 case 0x25:
544 case 0x26:
545 case 0x27:
546 case 0x28:
547 case 0x29:
548 case 0x2A:
549 case 0x2B:
550 case 0x2C:
551 case 0x2D:
552 case 0x2E:
553 case 0x2F:
554 // used by arm movt (low nibble of kind is high 4-bits of paired movw)
555 {
556 p = (uint32_t*)mappedAddressForVMAddress(address);
557 instruction = A::P::E::get32(*p);
558 // extract 16-bit value from instruction
559 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
560 uint32_t imm12 = (instruction & 0x00000FFF);
561 uint32_t imm16 = (imm4 << 12) | imm12;
562 // combine with codeToDataDelta and kind nibble
563 uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
564 uint32_t newTargetValue = targetValue + codeToDataDelta;
565 // construct new bits slices
566 uint32_t imm4_ = (newTargetValue & 0xF0000000) >> 28;
567 uint32_t imm12_ = (newTargetValue & 0x0FFF0000) >> 16;
568 // update instruction to match codeToDataDelta
569 uint32_t newInstruction = (instruction & 0xFFF0F000) | (imm4_ << 16) | imm12_;
570 A::P::E::set32(*p, newInstruction);
571 }
572 break;
19894a12
A
573 case 3: // used for arm64 ADRP
574 p = (uint32_t*)mappedAddressForVMAddress(address);
575 instruction = A::P::E::get32(*p);
576 if ( (instruction & 0x9F000000) == 0x90000000 ) {
577 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
578 value64 = ((instruction & 0x60000000) >> 17) | ((instruction & 0x00FFFFE0) << 9);
579 value64 += codeToDataDelta;
580 instruction = (instruction & 0x9F00001F) | ((value64 << 17) & 0x60000000) | ((value64 >> 9) & 0x00FFFFE0);
581 A::P::E::set32(*p, instruction);
582 }
583 break;
bac542e6
A
584 default:
585 throwf("invalid kind=%d in split seg info", kind);
586 }
587}
588
589template <typename A>
590const uint8_t* Rebaser<A>::doCodeUpdateForEachULEB128Address(const uint8_t* p, uint8_t kind, uint64_t orgBaseAddress, int64_t codeToDataDelta, int64_t codeToImportDelta)
591{
592 uint64_t address = 0;
593 uint64_t delta = 0;
594 uint32_t shift = 0;
595 bool more = true;
596 do {
597 uint8_t byte = *p++;
598 delta |= ((byte & 0x7F) << shift);
599 shift += 7;
600 if ( byte < 0x80 ) {
601 if ( delta != 0 ) {
602 address += delta;
603 doCodeUpdate(kind, address+orgBaseAddress, codeToDataDelta, codeToImportDelta);
604 delta = 0;
605 shift = 0;
606 }
607 else {
608 more = false;
609 }
610 }
611 } while (more);
612 return p;
613}
614
615template <typename A>
616void Rebaser<A>::adjustCode()
617{
618 if ( fSplittingSegments ) {
619 // get uleb128 compressed runs of code addresses to update
df9d6cf7
A
620 const uint8_t* infoStart = &fLinkEditBase[fSplitSegInfo->dataoff()];
621 const uint8_t* infoEnd = &infoStart[fSplitSegInfo->datasize()];;
bac542e6
A
622 // calculate how much we need to slide writable segments
623 const uint64_t orgBaseAddress = this->getBaseAddress();
624 int64_t codeToDataDelta = 0;
625 int64_t codeToImportDelta = 0;
626 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
627 const MachOLayoutAbstraction::Segment& codeSeg = segments[0];
628 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
629 const MachOLayoutAbstraction::Segment& dataSeg = *it;
df9d6cf7 630 if ( dataSeg.writable() ) {
19894a12
A
631 if ( (strcmp(dataSeg.name(), "__DATA") != 0) && (strcmp(dataSeg.name(), "__OBJC") != 0) )
632 throwf("only one rw segment named '__DATA' can be used in dylibs placed in the dyld shared cache (%s)", fLayout.getFilePath());
bac542e6 633 codeToDataDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
19894a12 634 }
bac542e6
A
635 }
636 // decompress and call doCodeUpdate() on each address
412ebb8e 637 for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
bac542e6
A
638 uint8_t kind = *p++;
639 p = this->doCodeUpdateForEachULEB128Address(p, kind, orgBaseAddress, codeToDataDelta, codeToImportDelta);
640 }
641 }
642}
643
bac542e6 644template <typename A>
412ebb8e 645void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData)
bac542e6 646{
39a8cd10
A
647 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
648 if ( segIndex > segments.size() )
649 throw "bad segment index in rebase info";
650 const MachOLayoutAbstraction::Segment& seg = segments[segIndex];
651 uint8_t* mappedAddr = (uint8_t*)seg.mappedAddress() + segOffset;
652 pint_t* mappedAddrP = (pint_t*)mappedAddr;
653 uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
654 pint_t valueP;
655 pint_t valuePnew;
656 uint32_t value32;
657 int32_t svalue32;
658 int32_t svalue32new;
659 switch ( type ) {
660 case REBASE_TYPE_POINTER:
661 valueP= P::getP(*mappedAddrP);
832b6fce
A
662 try {
663 P::setP(*mappedAddrP, valueP + this->getSlideForVMAddress(valueP));
664 }
665 catch (const char* msg) {
666 throwf("at offset=0x%08llX in seg=%s, pointer cannot be rebased because it does not point to __TEXT or __DATA. %s\n",
667 segOffset, seg.name(), msg);
668 }
39a8cd10
A
669 break;
670
671 case REBASE_TYPE_TEXT_ABSOLUTE32:
672 value32 = E::get32(*mappedAddr32);
673 E::set32(*mappedAddr32, value32 + this->getSlideForVMAddress(value32));
674 break;
675
676 case REBASE_TYPE_TEXT_PCREL32:
677 svalue32 = E::get32(*mappedAddr32);
678 valueP = seg.address() + segOffset + 4 + svalue32;
679 valuePnew = valueP + this->getSlideForVMAddress(valueP);
680 svalue32new = seg.address() + segOffset + 4 - valuePnew;
681 E::set32(*mappedAddr32, svalue32new);
682 break;
683
684 default:
685 throw "bad rebase type";
686 }
412ebb8e 687 pointersInData.push_back(mappedAddr);
39a8cd10 688}
bac542e6 689
39a8cd10
A
690
691template <typename A>
412ebb8e 692void Rebaser<A>::applyRebaseInfo(std::vector<void*>& pointersInData)
39a8cd10
A
693{
694 const uint8_t* p = &fLinkEditBase[fDyldInfo->rebase_off()];
695 const uint8_t* end = &p[fDyldInfo->rebase_size()];
696
697 uint8_t type = 0;
698 int segIndex;
699 uint64_t segOffset = 0;
700 uint32_t count;
701 uint32_t skip;
702 bool done = false;
703 while ( !done && (p < end) ) {
704 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
705 uint8_t opcode = *p & REBASE_OPCODE_MASK;
706 ++p;
707 switch (opcode) {
708 case REBASE_OPCODE_DONE:
709 done = true;
710 break;
711 case REBASE_OPCODE_SET_TYPE_IMM:
712 type = immediate;
bac542e6 713 break;
39a8cd10
A
714 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
715 segIndex = immediate;
716 segOffset = read_uleb128(p, end);
717 break;
718 case REBASE_OPCODE_ADD_ADDR_ULEB:
719 segOffset += read_uleb128(p, end);
720 break;
721 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
722 segOffset += immediate*sizeof(pint_t);
723 break;
724 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
725 for (int i=0; i < immediate; ++i) {
412ebb8e 726 doRebase(segIndex, segOffset, type, pointersInData);
39a8cd10
A
727 segOffset += sizeof(pint_t);
728 }
729 break;
730 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
731 count = read_uleb128(p, end);
732 for (uint32_t i=0; i < count; ++i) {
412ebb8e 733 doRebase(segIndex, segOffset, type, pointersInData);
39a8cd10
A
734 segOffset += sizeof(pint_t);
735 }
736 break;
737 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
412ebb8e 738 doRebase(segIndex, segOffset, type, pointersInData);
39a8cd10
A
739 segOffset += read_uleb128(p, end) + sizeof(pint_t);
740 break;
741 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
742 count = read_uleb128(p, end);
743 skip = read_uleb128(p, end);
744 for (uint32_t i=0; i < count; ++i) {
412ebb8e 745 doRebase(segIndex, segOffset, type, pointersInData);
39a8cd10
A
746 segOffset += skip + sizeof(pint_t);
747 }
748 break;
749 default:
750 throwf("bad rebase opcode %d", *p);
bac542e6 751 }
bac542e6 752 }
39a8cd10 753}
bac542e6 754
df9d6cf7
A
755template <>
756void Rebaser<arm64>::adjustReference(uint32_t kind, uint8_t* mappedAddr, uint64_t fromNewAddress, uint64_t toNewAddress, int64_t adjust, int64_t targetSlide,
757 uint64_t imageStartAddress, uint64_t imageEndAddress, std::vector<void*>& pointersInData)
39a8cd10 758{
df9d6cf7
A
759 uint64_t value64;
760 uint64_t* mappedAddr64;
761 uint32_t value32;
762 uint32_t* mappedAddr32;
763 uint32_t instruction;
764 int64_t offsetAdjust;
765 switch ( kind ) {
766 case DYLD_CACHE_ADJ_V2_DELTA_32:
767 mappedAddr32 = (uint32_t*)mappedAddr;
768 value32 = arm64::P::E::get32(*mappedAddr32);
769 E::set32(*mappedAddr32, value32 + adjust);
770 break;
771 case DYLD_CACHE_ADJ_V2_POINTER_64:
772 mappedAddr64 = (uint64_t*)mappedAddr;
773 if ( toNewAddress != (E::get64(*mappedAddr64) + targetSlide) )
774 throwf("bad DYLD_CACHE_ADJ_V2_POINTER_64 value not as expected at address 0x%llX\n", fromNewAddress);
775 E::set64(*mappedAddr64, toNewAddress);
776 pointersInData.push_back(mappedAddr);
777 break;
778 case DYLD_CACHE_ADJ_V2_DELTA_64:
779 mappedAddr64 = (uint64_t*)mappedAddr;
780 value64 = arm64::P::E::get64(*mappedAddr64);
781 E::set64(*mappedAddr64, value64 + adjust);
782 break;
783 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
784 mappedAddr32 = (uint32_t*)mappedAddr;
785 value64 = toNewAddress - imageStartAddress;
786 E::set32(*mappedAddr32, (uint32_t)value64);
787 break;
788 case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
789 mappedAddr32 = (uint32_t*)mappedAddr;
790 instruction = arm64::P::E::get32(*mappedAddr32);
791 if ( (instruction & 0x9F000000) == 0x90000000 ) {
792 //value64 = ((instruction & 0x60000000) >> 17) | ((instruction & 0x00FFFFE0) << 9);
793 uint32_t newPage21 = ((toNewAddress & ~0xFFF) - (fromNewAddress & ~0xFFF)) >> 12;
794 instruction = (instruction & 0x9F00001F) | ((newPage21 << 29) & 0x60000000) | ((newPage21 << 3) & 0x00FFFFE0);
795 arm64::P::E::set32(*mappedAddr32, instruction);
796 }
797 else {
798 // ADRP instructions are sometimes optimized to other instructions (e.g. ADR) after the split-seg-info is generated
799 }
800 break;
801 case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
802 mappedAddr32 = (uint32_t*)mappedAddr;
803 instruction = arm64::P::E::get32(*mappedAddr32);
804 offsetAdjust = (adjust & 0xFFF);
805 if ( offsetAdjust == 0 )
806 break;
807 if ( (instruction & 0x3B000000) == 0x39000000 ) {
808 // LDR/STR imm12
809 if ( offsetAdjust != 0 ) {
810 uint32_t encodedAddend = ((instruction & 0x003FFC00) >> 10);
811 uint32_t newAddend;
812 switch ( instruction & 0xC0000000 ) {
813 case 0x00000000:
814 if ( (instruction & 0x04800000) == 0x04800000 ) {
815 if ( offsetAdjust & 0xF )
816 throwf("can't adjust off12 scale=16 instruction by %lld bytes at mapped address=%p", offsetAdjust, mappedAddr);
817 if ( encodedAddend*16 >= 4096 )
818 throwf("off12 scale=16 instruction points outside its page at mapped address=%p", mappedAddr);
819 newAddend = (encodedAddend + offsetAdjust/16) % 256;
820 }
821 else {
822 // scale=1
823 newAddend = encodedAddend + offsetAdjust;
824 }
825 break;
826 case 0x40000000:
827 if ( offsetAdjust & 1 )
828 throwf("can't adjust off12 scale=2 instruction by %lld bytes at mapped address=%p", offsetAdjust, mappedAddr);
829 if ( encodedAddend*2 >= 4096 )
830 throwf("off12 scale=2 instruction points outside its page at mapped address=%p", mappedAddr);
831 newAddend = (encodedAddend + offsetAdjust/2) % 2048;
832 break;
833 case 0x80000000:
834 if ( offsetAdjust & 3 )
835 throwf("can't adjust off12 scale=4 instruction by %lld bytes at mapped address=%p", offsetAdjust, mappedAddr);
836 if ( encodedAddend*4 >= 4096 )
837 throwf("off12 scale=4 instruction points outside its page at mapped address=%p", mappedAddr);
838 newAddend = (encodedAddend + offsetAdjust/4) % 1024;
839 break;
840 case 0xC0000000:
841 if ( offsetAdjust & 7 )
842 throwf("can't adjust off12 scale=8 instruction by %lld bytes at mapped address=%p", offsetAdjust, mappedAddr);
843 if ( encodedAddend*8 >= 4096 )
844 throwf("off12 scale=8 instruction points outside its page at mapped address=%p", mappedAddr);
845 newAddend = (encodedAddend + offsetAdjust/8) % 512;
846 break;
bac542e6 847 }
df9d6cf7
A
848 uint32_t newInstruction = (instruction & 0xFFC003FF) | (newAddend << 10);
849 arm64::P::E::set32(*mappedAddr32, newInstruction);
bac542e6
A
850 }
851 }
df9d6cf7
A
852 else if ( (instruction & 0xFFC00000) == 0x91000000 ) {
853 // ADD imm12
854 if ( instruction & 0x00C00000 )
855 throwf("ADD off12 uses shift at mapped address=%p", mappedAddr);
856 uint32_t encodedAddend = ((instruction & 0x003FFC00) >> 10);
857 uint32_t newAddend = (encodedAddend + offsetAdjust) & 0xFFF;
858 uint32_t newInstruction = (instruction & 0xFFC003FF) | (newAddend << 10);
859 arm64::P::E::set32(*mappedAddr32, newInstruction);
bac542e6 860 }
df9d6cf7
A
861 else if ( instruction != 0xD503201F ) {
862 // ignore imm12 instructions optimized into a NOP, but warn about others
863 fprintf(stderr, "unknown off12 instruction 0x%08X at 0x%0llX in %s\n", instruction, fromNewAddress, fLayout.getFilePath());
864 }
865 break;
866 case DYLD_CACHE_ADJ_V2_ARM64_BR26:
867 // nothing to do with calls to stubs
868 break;
869 default:
870 throwf("unknown split seg kind=%d", kind);
bac542e6
A
871 }
872}
873
df9d6cf7 874static bool isThumbMovw(uint32_t instruction)
bac542e6 875{
df9d6cf7 876 return ( (instruction & 0x8000FBF0) == 0x0000F240 );
bac542e6
A
877}
878
df9d6cf7 879static bool isThumbMovt(uint32_t instruction)
bac542e6 880{
df9d6cf7 881 return ( (instruction & 0x8000FBF0) == 0x0000F2C0 );
bac542e6
A
882}
883
df9d6cf7 884static uint16_t getThumbWord(uint32_t instruction)
bac542e6 885{
df9d6cf7
A
886 uint32_t i = ((instruction & 0x00000400) >> 10);
887 uint32_t imm4 = (instruction & 0x0000000F);
888 uint32_t imm3 = ((instruction & 0x70000000) >> 28);
889 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
890 return ((imm4 << 12) | (i << 11) | (imm3 << 8) | imm8);
bac542e6
A
891}
892
df9d6cf7
A
893static uint32_t setThumbWord(uint32_t instruction, uint16_t word) {
894 uint32_t imm4 = (word & 0xF000) >> 12;
895 uint32_t i = (word & 0x0800) >> 11;
896 uint32_t imm3 = (word & 0x0700) >> 8;
897 uint32_t imm8 = word & 0x00FF;
898 return (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
bac542e6
A
899}
900
df9d6cf7 901static bool isArmMovw(uint32_t instruction)
bac542e6 902{
df9d6cf7 903 return (instruction & 0x0FF00000) == 0x03000000;
bac542e6
A
904}
905
df9d6cf7
A
906static bool isArmMovt(uint32_t instruction)
907{
908 return (instruction & 0x0FF00000) == 0x03400000;
909}
bac542e6 910
df9d6cf7 911static uint16_t getArmWord(uint32_t instruction)
bac542e6 912{
df9d6cf7
A
913 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
914 uint32_t imm12 = (instruction & 0x00000FFF);
915 return (imm4 << 12) | imm12;
916}
917
918static uint32_t setArmWord(uint32_t instruction, uint16_t word) {
919 uint32_t imm4 = (word & 0xF000) >> 12;
920 uint32_t imm12 = word & 0x0FFF;
921 return (instruction & 0xFFF0F000) | (imm4 << 16) | imm12;
bac542e6
A
922}
923
924
df9d6cf7
A
925template <>
926void Rebaser<arm>::adjustReference(uint32_t kind, uint8_t* mappedAddr, uint64_t fromNewAddress, uint64_t toNewAddress, int64_t adjust, int64_t targetSlide,
927 uint64_t imageStartAddress, uint64_t imageEndAddress, std::vector<void*>& pointersInData)
bac542e6 928{
df9d6cf7
A
929 uint32_t value32;
930 uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
931 static uint32_t* lastMappedAddr32 = NULL;
932 static uint32_t lastKind = 0;
933 static uint32_t lastToNewAddress = 0;
934 switch ( kind ) {
935 case DYLD_CACHE_ADJ_V2_DELTA_32:
936 value32 = arm64::P::E::get32(*mappedAddr32);
937 E::set32(*mappedAddr32, value32 + adjust);
938 break;
939 case DYLD_CACHE_ADJ_V2_POINTER_32:
940 if ( toNewAddress != (E::get32(*mappedAddr32) + targetSlide) )
941 throwf("bad DYLD_CACHE_ADJ_V2_POINTER_32 value not as expected at address 0x%llX\n", fromNewAddress);
942 E::set32(*mappedAddr32, toNewAddress);
943 pointersInData.push_back( mappedAddr);
944 break;
945 case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
946 mappedAddr32 = (uint32_t*)mappedAddr;
947 value32 = (uint32_t)(toNewAddress - imageStartAddress);
948 E::set32(*mappedAddr32, value32);
949 break;
950 case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT:
951 // to update a movw/movt pair we need to extract the 32-bit they will make,
952 // add the adjust and write back the new movw/movt pair.
953 if ( lastKind == kind ) {
954 if ( lastToNewAddress == toNewAddress ) {
955 uint32_t instruction1 = E::get32(*lastMappedAddr32);
956 uint32_t instruction2 = E::get32(*mappedAddr32);
957 if ( isThumbMovw(instruction1) && isThumbMovt(instruction2) ) {
958 uint16_t high = getThumbWord(instruction2);
959 uint16_t low = getThumbWord(instruction1);
960 uint32_t full = high << 16 | low;
961 full += adjust;
962 instruction1 = setThumbWord(instruction1, full & 0xFFFF);
963 instruction2 = setThumbWord(instruction2, full >> 16);
964 }
965 else if ( isThumbMovt(instruction1) && isThumbMovw(instruction2) ) {
966 uint16_t high = getThumbWord(instruction1);
967 uint16_t low = getThumbWord(instruction2);
968 uint32_t full = high << 16 | low;
969 full += adjust;
970 instruction2 = setThumbWord(instruction2, full & 0xFFFF);
971 instruction1 = setThumbWord(instruction1, full >> 16);
bac542e6 972 }
df9d6cf7
A
973 else {
974 throw "two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but not";
bac542e6 975 }
df9d6cf7
A
976 E::set32(*lastMappedAddr32, instruction1);
977 E::set32(*mappedAddr32, instruction2);
978 kind = 0;
979 }
980 else {
981 throw "two DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT in a row but target different addresses";
bac542e6
A
982 }
983 }
df9d6cf7
A
984 break;
985 case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT:
986 // to update a movw/movt pair we need to extract the 32-bit they will make,
987 // add the adjust and write back the new movw/movt pair.
988 if ( lastKind == kind ) {
989 if ( lastToNewAddress == toNewAddress ) {
990 uint32_t instruction1 = E::get32(*lastMappedAddr32);
991 uint32_t instruction2 = E::get32(*mappedAddr32);
992 if ( isArmMovw(instruction1) && isArmMovt(instruction2) ) {
993 uint16_t high = getArmWord(instruction2);
994 uint16_t low = getArmWord(instruction1);
995 uint32_t full = high << 16 | low;
996 full += adjust;
997 instruction1 = setArmWord(instruction1, full & 0xFFFF);
998 instruction2 = setArmWord(instruction2, full >> 16);
bac542e6 999 }
df9d6cf7
A
1000 else if ( isArmMovt(instruction1) && isArmMovw(instruction2) ) {
1001 uint16_t high = getArmWord(instruction1);
1002 uint16_t low = getArmWord(instruction2);
1003 uint32_t full = high << 16 | low;
1004 full += adjust;
1005 instruction2 = setArmWord(instruction2, full & 0xFFFF);
1006 instruction1 = setArmWord(instruction1, full >> 16);
39a8cd10 1007 }
bac542e6 1008 else {
df9d6cf7 1009 throw "two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but not";
bac542e6 1010 }
df9d6cf7
A
1011 E::set32(*lastMappedAddr32, instruction1);
1012 E::set32(*mappedAddr32, instruction2);
1013 kind = 0;
bac542e6 1014 }
df9d6cf7
A
1015 else {
1016 throw "two DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT in a row but target different addresses";
bac542e6
A
1017 }
1018 }
df9d6cf7
A
1019 break;
1020 case DYLD_CACHE_ADJ_V2_ARM_BR24:
1021 case DYLD_CACHE_ADJ_V2_THUMB_BR22:
1022 // nothing to do with calls to stubs
1023 break;
1024 default:
1025 throwf("v2 split seg info kind (%d) not supported yet", kind);
1026 }
1027 lastKind = kind;
1028 lastToNewAddress = toNewAddress;
1029 lastMappedAddr32 = mappedAddr32;
1030}
bac542e6
A
1031
1032
df9d6cf7
A
1033template <typename A>
1034void Rebaser<A>::adjustReference(uint32_t kind, uint8_t* mappedAddr, uint64_t fromNewAddress, uint64_t toNewAddress, int64_t adjust, int64_t targetSlide,
1035 uint64_t imageStartAddress, uint64_t imageEndAddress, std::vector<void*>& pointersInData)
1036{
1037 throw "v2 split seg info not supported yet";
1038}
bac542e6 1039
bac542e6 1040
df9d6cf7
A
1041template <typename A>
1042void Rebaser<A>::adjustReferencesUsingInfoV2(std::vector<void*>& pointersInData)
1043{
1044 static const bool log = false;
1045
1046 const uint8_t* infoStart = &fLinkEditBase[fSplitSegInfo->dataoff()];
1047 const uint8_t* infoEnd = &infoStart[fSplitSegInfo->datasize()];;
1048 if ( *infoStart++ != DYLD_CACHE_ADJ_V2_FORMAT )
1049 throw "malformed split seg info";
1050
1051 // build section arrays of slide and mapped address for each section
1052 std::vector<uint64_t> sectionSlides;
1053 std::vector<uint64_t> sectionNewAddress;
1054 std::vector<uint8_t*> sectionMappedAddress;
1055 sectionSlides.reserve(16);
1056 sectionNewAddress.reserve(16);
1057 sectionMappedAddress.reserve(16);
1058 // section index 0 refers to mach_header
1059 const MachOLayoutAbstraction::Segment& textSeg = fLayout.getSegments().front();
1060 sectionMappedAddress.push_back((uint8_t*)textSeg.mappedAddress());
1061 sectionSlides.push_back(textSeg.newAddress() - textSeg.address());
1062 sectionNewAddress.push_back(textSeg.newAddress());
1063 // section 1 and later refer to real sections
1064 unsigned sectionIndex = 0;
1065 for (const MachOLayoutAbstraction::Segment& seg : fLayout.getSegments()) {
1066 uint64_t segSlide = seg.newAddress() - seg.address();
1067 for (uint32_t i=0; i < seg.sectionCount(); ++i) {
1068 if (log) fprintf(stderr, "seg=%s, sectIndex=%d, mapped at=%p, offsetInSeg=0x%08llX\n", seg.name(), sectionIndex, seg.mappedAddress(), fSectionOffsetsInSegment[sectionIndex]);
1069 sectionMappedAddress.push_back((uint8_t*)seg.mappedAddress() + fSectionOffsetsInSegment[sectionIndex]);
1070 sectionSlides.push_back(segSlide);
1071 sectionNewAddress.push_back(seg.newAddress() + fSectionOffsetsInSegment[sectionIndex]);
1072 ++sectionIndex;
1073 }
1074 }
bac542e6 1075
df9d6cf7
A
1076 // Whole :== <count> FromToSection+
1077 // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
1078 // ToOffset :== <to-sect-offset-delta> <count> FromOffset+
1079 // FromOffset :== <kind> <count> <from-sect-offset-delta>
1080 const uint8_t* p = infoStart;
1081 uint64_t sectionCount = read_uleb128(p, infoEnd);
1082 for (uint64_t i=0; i < sectionCount; ++i) {
1083 uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
1084 uint64_t toSectionIndex = read_uleb128(p, infoEnd);
1085 uint64_t toOffsetCount = read_uleb128(p, infoEnd);
1086 uint64_t fromSectionSlide = sectionSlides[fromSectionIndex];
1087 uint64_t fromSectionNewAddress = sectionNewAddress[fromSectionIndex];
1088 uint8_t* fromSectionMappedAddress = sectionMappedAddress[fromSectionIndex];
1089 uint64_t toSectionSlide = sectionSlides[toSectionIndex];
1090 uint64_t toSectionNewAddress = sectionNewAddress[toSectionIndex];
1091 if (log) printf("from sect=%lld (mapped=%p), to sect=%lld (new addr=0x%llX):\n", fromSectionIndex, fromSectionMappedAddress, toSectionIndex, toSectionNewAddress);
1092 uint64_t toSectionOffset = 0;
1093 for (uint64_t j=0; j < toOffsetCount; ++j) {
1094 uint64_t toSectionDelta = read_uleb128(p, infoEnd);
1095 uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
1096 toSectionOffset += toSectionDelta;
1097 for (uint64_t k=0; k < fromOffsetCount; ++k) {
1098 uint64_t kind = read_uleb128(p, infoEnd);
1099 uint64_t fromSectDeltaCount = read_uleb128(p, infoEnd);
1100 uint64_t fromSectionOffset = 0;
1101 for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
1102 uint64_t delta = read_uleb128(p, infoEnd);
1103 fromSectionOffset += delta;
1104 int64_t deltaAdjust = toSectionSlide - fromSectionSlide;
1105 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);
1106 uint8_t* fromMappedAddr = fromSectionMappedAddress + fromSectionOffset;
1107 uint64_t toNewAddress = toSectionNewAddress + toSectionOffset;
1108 uint64_t fromNewAddress = fromSectionNewAddress + fromSectionOffset;
1109 adjustReference(kind, fromMappedAddr, fromNewAddress, toNewAddress, deltaAdjust, toSectionSlide, sectionNewAddress.front(), sectionNewAddress.back(), pointersInData);
1110 }
1111 }
1112 }
1113 }
1114
1115
1116}
bac542e6
A
1117
1118#endif // __MACHO_REBASER__
1119
1120
1121
1122