]> git.saurik.com Git - apple/dyld.git/blob - launch-cache/MachORebaser.hpp
4493cc3f2abb04b21c451faf7a40e8e971431f56
[apple/dyld.git] / launch-cache / MachORebaser.hpp
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>
41 #include <mach-o/x86_64/reloc.h>
42 #include <mach-o/arm/reloc.h>
43 #include <vector>
44 #include <set>
45
46 #include "MachOFileAbstraction.hpp"
47 #include "Architectures.hpp"
48 #include "MachOLayout.hpp"
49 #include "MachOTrie.hpp"
50
51
52
53 class AbstractRebaser
54 {
55 public:
56 virtual cpu_type_t getArchitecture() const = 0;
57 virtual uint64_t getBaseAddress() const = 0;
58 virtual uint64_t getVMSize() const = 0;
59 virtual void rebase(std::vector<void*>&) = 0;
60 };
61
62
63 template <typename A>
64 class Rebaser : public AbstractRebaser
65 {
66 public:
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;
73 virtual void rebase(std::vector<void*>&);
74
75 protected:
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);
82
83 private:
84 void calculateRelocBase();
85 void adjustLoadCommands();
86 void adjustSymbolTable();
87 void optimzeStubs();
88 void makeNoPicStub(uint8_t* stub, pint_t logicalAddress);
89 void adjustDATA();
90 void adjustCode();
91 void applyRebaseInfo(std::vector<void*>& pointersInData);
92 void adjustExportInfo();
93 void doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData);
94 void adjustSegmentLoadCommand(macho_segment_command<P>* seg);
95 pint_t getSlideForVMAddress(pint_t vmaddress);
96 pint_t* mappedAddressForVMAddress(pint_t vmaddress);
97 pint_t* mappedAddressForRelocAddress(pint_t r_address);
98 void adjustRelocBaseAddresses();
99 const uint8_t* doCodeUpdateForEachULEB128Address(const uint8_t* p, uint8_t kind, uint64_t orgBaseAddress, int64_t codeToDataDelta, int64_t codeToImportDelta);
100 void doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta);
101 void doLocalRelocation(const macho_relocation_info<P>* reloc);
102 bool unequalSlides() const;
103
104 protected:
105 const macho_header<P>* fHeader;
106 uint8_t* fLinkEditBase; // add file offset to this to get linkedit content
107 const MachOLayoutAbstraction& fLayout;
108 private:
109 pint_t fOrignalVMRelocBaseAddress; // add reloc address to this to get original address reloc referred to
110 const macho_symtab_command<P>* fSymbolTable;
111 const macho_dysymtab_command<P>* fDynamicSymbolTable;
112 const macho_dyld_info_command<P>* fDyldInfo;
113 bool fSplittingSegments;
114 bool fOrignalVMRelocBaseAddressValid;
115 pint_t fSkipSplitSegInfoStart;
116 pint_t fSkipSplitSegInfoEnd;
117 };
118
119
120
121 template <typename A>
122 Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
123 : fLayout(layout), fOrignalVMRelocBaseAddress(0), fLinkEditBase(0),
124 fSymbolTable(NULL), fDynamicSymbolTable(NULL), fDyldInfo(NULL), fSplittingSegments(false),
125 fOrignalVMRelocBaseAddressValid(false), fSkipSplitSegInfoStart(0), fSkipSplitSegInfoEnd(0)
126 {
127 fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
128 switch ( fHeader->filetype() ) {
129 case MH_DYLIB:
130 case MH_BUNDLE:
131 break;
132 default:
133 throw "file is not a dylib or bundle";
134 }
135
136 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
137 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
138 const MachOLayoutAbstraction::Segment& seg = *it;
139 if ( strcmp(seg.name(), "__LINKEDIT") == 0 ) {
140 fLinkEditBase = (uint8_t*)seg.mappedAddress() - seg.fileOffset();
141 break;
142 }
143 }
144 if ( fLinkEditBase == NULL )
145 throw "no __LINKEDIT segment";
146
147 // get symbol table info
148 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
149 const uint32_t cmd_count = fHeader->ncmds();
150 const macho_load_command<P>* cmd = cmds;
151 for (uint32_t i = 0; i < cmd_count; ++i) {
152 switch (cmd->cmd()) {
153 case LC_SYMTAB:
154 fSymbolTable = (macho_symtab_command<P>*)cmd;
155 break;
156 case LC_DYSYMTAB:
157 fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
158 break;
159 case LC_DYLD_INFO:
160 case LC_DYLD_INFO_ONLY:
161 fDyldInfo = (macho_dyld_info_command<P>*)cmd;
162 break;
163 }
164 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
165 }
166
167 calculateRelocBase();
168
169 fSplittingSegments = layout.hasSplitSegInfo() && this->unequalSlides();
170 }
171
172 template <> cpu_type_t Rebaser<x86>::getArchitecture() const { return CPU_TYPE_I386; }
173 template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
174 template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
175
176 template <typename A>
177 bool Rebaser<A>::unequalSlides() const
178 {
179 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
180 uint64_t slide = segments[0].newAddress() - segments[0].address();
181 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
182 const MachOLayoutAbstraction::Segment& seg = *it;
183 if ( (seg.newAddress() - seg.address()) != slide )
184 return true;
185 }
186 return false;
187 }
188
189 template <typename A>
190 uint64_t Rebaser<A>::getBaseAddress() const
191 {
192 return fLayout.getSegments()[0].address();
193 }
194
195 template <typename A>
196 uint64_t Rebaser<A>::getVMSize() const
197 {
198 uint64_t highestVMAddress = 0;
199 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
200 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
201 const MachOLayoutAbstraction::Segment& seg = *it;
202 if ( seg.address() > highestVMAddress )
203 highestVMAddress = seg.address();
204 }
205 return (((highestVMAddress - getBaseAddress()) + 4095) & (-4096));
206 }
207
208
209
210 template <typename A>
211 void Rebaser<A>::rebase(std::vector<void*>& pointersInData)
212 {
213 // update writable segments that have internal pointers
214 if ( fDyldInfo != NULL )
215 this->applyRebaseInfo(pointersInData);
216 else
217 this->adjustDATA();
218
219 // if splitting segments, update code-to-data references
220 this->adjustCode();
221
222 // change address on relocs now that segments are split
223 this->adjustRelocBaseAddresses();
224
225 // update load commands
226 this->adjustLoadCommands();
227
228 // update symbol table
229 this->adjustSymbolTable();
230
231 // optimize stubs
232 this->optimzeStubs();
233
234 // update export info
235 if ( fDyldInfo != NULL )
236 this->adjustExportInfo();
237 }
238
239 template <>
240 void Rebaser<x86>::adjustSegmentLoadCommand(macho_segment_command<P>* seg)
241 {
242 // __IMPORT segments are not-writable in shared cache
243 if ( strcmp(seg->segname(), "__IMPORT") == 0 )
244 seg->set_initprot(VM_PROT_READ|VM_PROT_EXECUTE);
245 }
246
247 template <typename A>
248 void Rebaser<A>::adjustSegmentLoadCommand(macho_segment_command<P>* seg)
249 {
250 }
251
252
253 template <typename A>
254 void Rebaser<A>::adjustLoadCommands()
255 {
256 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
257 const uint32_t cmd_count = fHeader->ncmds();
258 const macho_load_command<P>* cmd = cmds;
259 for (uint32_t i = 0; i < cmd_count; ++i) {
260 switch ( cmd->cmd() ) {
261 case LC_ID_DYLIB:
262 if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
263 // clear timestamp so that any prebound clients are invalidated
264 macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
265 dylib->set_timestamp(1);
266 }
267 break;
268 case LC_LOAD_DYLIB:
269 case LC_LOAD_WEAK_DYLIB:
270 case LC_REEXPORT_DYLIB:
271 case LC_LOAD_UPWARD_DYLIB:
272 if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
273 // clear expected timestamps so that this image will load with invalid prebinding
274 macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
275 dylib->set_timestamp(2);
276 }
277 break;
278 case macho_routines_command<P>::CMD:
279 // update -init command
280 {
281 struct macho_routines_command<P>* routines = (struct macho_routines_command<P>*)cmd;
282 routines->set_init_address(routines->init_address() + this->getSlideForVMAddress(routines->init_address()));
283 }
284 break;
285 case macho_segment_command<P>::CMD:
286 // update segment commands
287 {
288 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
289 this->adjustSegmentLoadCommand(seg);
290 pint_t slide = this->getSlideForVMAddress(seg->vmaddr());
291 seg->set_vmaddr(seg->vmaddr() + slide);
292 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
293 macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
294 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
295 sect->set_addr(sect->addr() + slide);
296 }
297 }
298 break;
299 }
300 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
301 }
302 }
303
304
305
306 template <typename A>
307 typename A::P::uint_t Rebaser<A>::getSlideForVMAddress(pint_t vmaddress)
308 {
309 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
310 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
311 const MachOLayoutAbstraction::Segment& seg = *it;
312 if ( (seg.address() <= vmaddress) && (seg.size() != 0) && ((vmaddress < (seg.address()+seg.size())) || (seg.address() == vmaddress)) ) {
313 return seg.newAddress() - seg.address();
314 }
315 }
316 throwf("vm address 0x%08llX not found", (uint64_t)vmaddress);
317 }
318
319
320 template <typename A>
321 typename A::P::uint_t* Rebaser<A>::mappedAddressForVMAddress(pint_t vmaddress)
322 {
323 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
324 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
325 const MachOLayoutAbstraction::Segment& seg = *it;
326 if ( (seg.address() <= vmaddress) && (vmaddress < (seg.address()+seg.size())) ) {
327 return (pint_t*)((vmaddress - seg.address()) + (uint8_t*)seg.mappedAddress());
328 }
329 }
330 throwf("mappedAddressForVMAddress(0x%08llX) not found", (uint64_t)vmaddress);
331 }
332
333 template <typename A>
334 typename A::P::uint_t* Rebaser<A>::mappedAddressForNewAddress(pint_t vmaddress)
335 {
336 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
337 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
338 const MachOLayoutAbstraction::Segment& seg = *it;
339 if ( (seg.newAddress() <= vmaddress) && (vmaddress < (seg.newAddress()+seg.size())) ) {
340 return (pint_t*)((vmaddress - seg.newAddress()) + (uint8_t*)seg.mappedAddress());
341 }
342 }
343 throwf("mappedAddressForNewAddress(0x%08llX) not found", (uint64_t)vmaddress);
344 }
345
346 template <typename A>
347 typename A::P::uint_t Rebaser<A>::getSlideForNewAddress(pint_t newAddress)
348 {
349 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
350 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
351 const MachOLayoutAbstraction::Segment& seg = *it;
352 if ( (seg.newAddress() <= newAddress) && (newAddress < (seg.newAddress()+seg.size())) ) {
353 return seg.newAddress() - seg.address();
354 }
355 }
356 throwf("new address 0x%08llX not found", (uint64_t)newAddress);
357 }
358
359 template <typename A>
360 typename A::P::uint_t* Rebaser<A>::mappedAddressForRelocAddress(pint_t r_address)
361 {
362 if ( fOrignalVMRelocBaseAddressValid )
363 return this->mappedAddressForVMAddress(r_address + fOrignalVMRelocBaseAddress);
364 else
365 throw "can't apply relocation. Relocation base not known";
366 }
367
368
369 template <>
370 void Rebaser<arm>::makeNoPicStub(uint8_t* stub, pint_t logicalAddress)
371 {
372 uint32_t* instructions = (uint32_t*)stub;
373 if ( (LittleEndian::get32(instructions[0]) == 0xE59FC004) &&
374 (LittleEndian::get32(instructions[1]) == 0xE08FC00C) &&
375 (LittleEndian::get32(instructions[2]) == 0xE59CF000) ) {
376 uint32_t lazyPtrAddress = instructions[3] + logicalAddress + 12;
377 LittleEndian::set32(instructions[0], 0xE59FC000); // ldr ip, [pc, #0]
378 LittleEndian::set32(instructions[1], 0xE59CF000); // ldr pc, [ip]
379 LittleEndian::set32(instructions[2], lazyPtrAddress); // .long L_foo$lazy_ptr
380 LittleEndian::set32(instructions[3], 0xE1A00000); // nop
381 }
382 else
383 fprintf(stderr, "unoptimized stub in %s at 0x%08X\n", fLayout.getFilePath(), logicalAddress);
384 }
385
386
387 #if 0
388 // disable this optimization do allow cache to slide
389 template <>
390 void Rebaser<arm>::optimzeStubs()
391 {
392 // convert pic stubs to no-pic stubs in dyld shared cache
393 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
394 const uint32_t cmd_count = fHeader->ncmds();
395 const macho_load_command<P>* cmd = cmds;
396 for (uint32_t i = 0; i < cmd_count; ++i) {
397 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
398 macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
399 macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
400 macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
401 for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
402 if ( (sect->flags() & SECTION_TYPE) == S_SYMBOL_STUBS ) {
403 const uint32_t stubSize = sect->reserved2();
404 // ARM PIC stubs are 4 32-bit instructions long
405 if ( stubSize == 16 ) {
406 uint32_t stubCount = sect->size() / 16;
407 pint_t stubLogicalAddress = sect->addr();
408 uint8_t* stubMappedAddress = (uint8_t*)mappedAddressForNewAddress(stubLogicalAddress);
409 for(uint32_t s=0; s < stubCount; ++s) {
410 makeNoPicStub(stubMappedAddress, stubLogicalAddress);
411 stubLogicalAddress += 16;
412 stubMappedAddress += 16;
413 }
414 }
415 }
416 }
417 }
418 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
419 }
420 }
421 #endif
422
423 template <typename A>
424 void Rebaser<A>::optimzeStubs()
425 {
426 // other architectures don't need stubs changed in shared cache
427 }
428
429 template <typename A>
430 void Rebaser<A>::adjustSymbolTable()
431 {
432 macho_nlist<P>* symbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTable->symoff()]);
433
434 // walk all exports and slide their n_value
435 macho_nlist<P>* lastExport = &symbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
436 for (macho_nlist<P>* entry = &symbolTable[fDynamicSymbolTable->iextdefsym()]; entry < lastExport; ++entry) {
437 if ( (entry->n_type() & N_TYPE) == N_SECT )
438 entry->set_n_value(entry->n_value() + this->getSlideForVMAddress(entry->n_value()));
439 }
440
441 // walk all local symbols and slide their n_value (don't adjust any stabs)
442 macho_nlist<P>* lastLocal = &symbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
443 for (macho_nlist<P>* entry = &symbolTable[fDynamicSymbolTable->ilocalsym()]; entry < lastLocal; ++entry) {
444 if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) )
445 entry->set_n_value(entry->n_value() + this->getSlideForVMAddress(entry->n_value()));
446 }
447 }
448
449 template <typename A>
450 void Rebaser<A>::adjustExportInfo()
451 {
452 // if no export info, nothing to adjust
453 if ( fDyldInfo->export_size() == 0 )
454 return;
455
456 // since export info addresses are offsets from mach_header, everything in __TEXT is fine
457 // only __DATA addresses need to be updated
458 const uint8_t* start = fLayout.getDyldInfoExports();
459 const uint8_t* end = &start[fDyldInfo->export_size()];
460 std::vector<mach_o::trie::Entry> originalExports;
461 try {
462 parseTrie(start, end, originalExports);
463 }
464 catch (const char* msg) {
465 throwf("%s in %s", msg, fLayout.getFilePath());
466 }
467
468 std::vector<mach_o::trie::Entry> newExports;
469 newExports.reserve(originalExports.size());
470 pint_t baseAddress = this->getBaseAddress();
471 pint_t baseAddressSlide = this->getSlideForVMAddress(baseAddress);
472 for (std::vector<mach_o::trie::Entry>::iterator it=originalExports.begin(); it != originalExports.end(); ++it) {
473 // remove symbols used by the static linker only
474 if ( (strncmp(it->name, "$ld$", 4) == 0)
475 || (strncmp(it->name, ".objc_class_name",16) == 0)
476 || (strncmp(it->name, ".objc_category_name",19) == 0) ) {
477 //fprintf(stderr, "ignoring symbol %s\n", it->name);
478 continue;
479 }
480 // adjust symbols in slid segments
481 //uint32_t oldOffset = it->address;
482 it->address += (this->getSlideForVMAddress(it->address + baseAddress) - baseAddressSlide);
483 //fprintf(stderr, "orig=0x%08X, new=0x%08llX, sym=%s\n", oldOffset, it->address, it->name);
484 newExports.push_back(*it);
485 }
486
487 // rebuild export trie
488 std::vector<uint8_t> newExportTrieBytes;
489 newExportTrieBytes.reserve(fDyldInfo->export_size());
490 mach_o::trie::makeTrie(newExports, newExportTrieBytes);
491 // align
492 while ( (newExportTrieBytes.size() % sizeof(pint_t)) != 0 )
493 newExportTrieBytes.push_back(0);
494
495 // allocate new buffer and set export_off to use new buffer instead
496 uint32_t newExportsSize = newExportTrieBytes.size();
497 uint8_t* sideTrie = new uint8_t[newExportsSize];
498 memcpy(sideTrie, &newExportTrieBytes[0], newExportsSize);
499 fLayout.setDyldInfoExports(sideTrie);
500 ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_off(0); // invalidate old trie
501 ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
502 }
503
504
505
506 template <typename A>
507 void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta)
508 {
509 // begin hack for <rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
510 if ( (fSkipSplitSegInfoStart <= address) && (address < fSkipSplitSegInfoEnd) ) {
511 uint8_t* p = (uint8_t*)mappedAddressForVMAddress(address);
512 // only ignore split seg info for "push" instructions
513 if ( p[-1] == 0x68 )
514 return;
515 }
516 // end hack for <rdar://problem/8253549>
517
518 //fprintf(stderr, "doCodeUpdate(kind=%d, address=0x%0llX, dataDelta=0x%08llX, importDelta=0x%08llX, path=%s)\n",
519 // kind, address, codeToDataDelta, codeToImportDelta, fLayout.getFilePath());
520 uint32_t* p;
521 uint32_t instruction;
522 uint32_t value;
523 uint64_t value64;
524 switch (kind) {
525 case 1: // 32-bit pointer
526 p = (uint32_t*)mappedAddressForVMAddress(address);
527 value = A::P::E::get32(*p);
528 value += codeToDataDelta;
529 A::P::E::set32(*p, value);
530 break;
531 case 2: // 64-bit pointer
532 p = (uint32_t*)mappedAddressForVMAddress(address);
533 value64 = A::P::E::get64(*(uint64_t*)p);
534 value64 += codeToDataDelta;
535 A::P::E::set64(*(uint64_t*)p, value64);
536 break;
537 case 4: // only used for i386, a reference to something in the IMPORT segment
538 p = (uint32_t*)mappedAddressForVMAddress(address);
539 value = A::P::E::get32(*p);
540 value += codeToImportDelta;
541 A::P::E::set32(*p, value);
542 break;
543 case 5: // used by thumb2 movw
544 p = (uint32_t*)mappedAddressForVMAddress(address);
545 instruction = A::P::E::get32(*p);
546 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
547 value = (instruction & 0x0000000F) + (codeToDataDelta >> 12);
548 instruction = (instruction & 0xFFFFFFF0) | (value & 0x0000000F);
549 A::P::E::set32(*p, instruction);
550 break;
551 case 6: // used by ARM movw
552 p = (uint32_t*)mappedAddressForVMAddress(address);
553 instruction = A::P::E::get32(*p);
554 // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
555 value = ((instruction & 0x000F0000) >> 16) + (codeToDataDelta >> 12);
556 instruction = (instruction & 0xFFF0FFFF) | ((value <<16) & 0x000F0000);
557 A::P::E::set32(*p, instruction);
558 break;
559 case 0x10:
560 case 0x11:
561 case 0x12:
562 case 0x13:
563 case 0x14:
564 case 0x15:
565 case 0x16:
566 case 0x17:
567 case 0x18:
568 case 0x19:
569 case 0x1A:
570 case 0x1B:
571 case 0x1C:
572 case 0x1D:
573 case 0x1E:
574 case 0x1F:
575 // used by thumb2 movt (low nibble of kind is high 4-bits of paired movw)
576 {
577 p = (uint32_t*)mappedAddressForVMAddress(address);
578 instruction = A::P::E::get32(*p);
579 // extract 16-bit value from instruction
580 uint32_t i = ((instruction & 0x00000400) >> 10);
581 uint32_t imm4 = (instruction & 0x0000000F);
582 uint32_t imm3 = ((instruction & 0x70000000) >> 28);
583 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
584 uint32_t imm16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
585 // combine with codeToDataDelta and kind nibble
586 uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
587 uint32_t newTargetValue = targetValue + codeToDataDelta;
588 // construct new bits slices
589 uint32_t imm4_ = (newTargetValue & 0xF0000000) >> 28;
590 uint32_t i_ = (newTargetValue & 0x08000000) >> 27;
591 uint32_t imm3_ = (newTargetValue & 0x07000000) >> 24;
592 uint32_t imm8_ = (newTargetValue & 0x00FF0000) >> 16;
593 // update instruction to match codeToDataDelta
594 uint32_t newInstruction = (instruction & 0x8F00FBF0) | imm4_ | (i_ << 10) | (imm3_ << 28) | (imm8_ << 16);
595 A::P::E::set32(*p, newInstruction);
596 }
597 break;
598 case 0x20:
599 case 0x21:
600 case 0x22:
601 case 0x23:
602 case 0x24:
603 case 0x25:
604 case 0x26:
605 case 0x27:
606 case 0x28:
607 case 0x29:
608 case 0x2A:
609 case 0x2B:
610 case 0x2C:
611 case 0x2D:
612 case 0x2E:
613 case 0x2F:
614 // used by arm movt (low nibble of kind is high 4-bits of paired movw)
615 {
616 p = (uint32_t*)mappedAddressForVMAddress(address);
617 instruction = A::P::E::get32(*p);
618 // extract 16-bit value from instruction
619 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
620 uint32_t imm12 = (instruction & 0x00000FFF);
621 uint32_t imm16 = (imm4 << 12) | imm12;
622 // combine with codeToDataDelta and kind nibble
623 uint32_t targetValue = (imm16 << 16) | ((kind & 0xF) << 12);
624 uint32_t newTargetValue = targetValue + codeToDataDelta;
625 // construct new bits slices
626 uint32_t imm4_ = (newTargetValue & 0xF0000000) >> 28;
627 uint32_t imm12_ = (newTargetValue & 0x0FFF0000) >> 16;
628 // update instruction to match codeToDataDelta
629 uint32_t newInstruction = (instruction & 0xFFF0F000) | (imm4_ << 16) | imm12_;
630 A::P::E::set32(*p, newInstruction);
631 }
632 break;
633 case 3: // used only for ppc, an instruction that sets the hi16 of a register
634 default:
635 throwf("invalid kind=%d in split seg info", kind);
636 }
637 }
638
639 template <typename A>
640 const uint8_t* Rebaser<A>::doCodeUpdateForEachULEB128Address(const uint8_t* p, uint8_t kind, uint64_t orgBaseAddress, int64_t codeToDataDelta, int64_t codeToImportDelta)
641 {
642 uint64_t address = 0;
643 uint64_t delta = 0;
644 uint32_t shift = 0;
645 bool more = true;
646 do {
647 uint8_t byte = *p++;
648 delta |= ((byte & 0x7F) << shift);
649 shift += 7;
650 if ( byte < 0x80 ) {
651 if ( delta != 0 ) {
652 address += delta;
653 doCodeUpdate(kind, address+orgBaseAddress, codeToDataDelta, codeToImportDelta);
654 delta = 0;
655 shift = 0;
656 }
657 else {
658 more = false;
659 }
660 }
661 } while (more);
662 return p;
663 }
664
665 template <typename A>
666 void Rebaser<A>::adjustCode()
667 {
668 if ( fSplittingSegments ) {
669 // get uleb128 compressed runs of code addresses to update
670 const uint8_t* infoStart = NULL;
671 const uint8_t* infoEnd = NULL;
672 const macho_segment_command<P>* seg;
673 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
674 const uint32_t cmd_count = fHeader->ncmds();
675 const macho_load_command<P>* cmd = cmds;
676 for (uint32_t i = 0; i < cmd_count; ++i) {
677 switch (cmd->cmd()) {
678 case LC_SEGMENT_SPLIT_INFO:
679 {
680 const macho_linkedit_data_command<P>* segInfo = (macho_linkedit_data_command<P>*)cmd;
681 infoStart = &fLinkEditBase[segInfo->dataoff()];
682 infoEnd = &infoStart[segInfo->datasize()];
683 }
684 break;
685 // begin hack for <rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
686 case macho_segment_command<P>::CMD:
687 seg = (macho_segment_command<P>*)cmd;
688 if ( (getArchitecture() == CPU_TYPE_X86_64) && (strcmp(seg->segname(), "__TEXT") == 0) ) {
689 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
690 const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
691 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
692 if ( strcmp(sect->sectname(), "__stub_helper") == 0 ) {
693 fSkipSplitSegInfoStart = sect->addr();
694 fSkipSplitSegInfoEnd = sect->addr() + sect->size() - 16;
695 }
696 }
697 }
698 break;
699 // end hack for <rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
700 }
701 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
702 }
703 // calculate how much we need to slide writable segments
704 const uint64_t orgBaseAddress = this->getBaseAddress();
705 int64_t codeToDataDelta = 0;
706 int64_t codeToImportDelta = 0;
707 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
708 const MachOLayoutAbstraction::Segment& codeSeg = segments[0];
709 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
710 const MachOLayoutAbstraction::Segment& dataSeg = *it;
711 if ( strcmp(dataSeg.name(), "__IMPORT") == 0 )
712 codeToImportDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
713 else if ( dataSeg.writable() )
714 codeToDataDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
715 }
716 // decompress and call doCodeUpdate() on each address
717 for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
718 uint8_t kind = *p++;
719 p = this->doCodeUpdateForEachULEB128Address(p, kind, orgBaseAddress, codeToDataDelta, codeToImportDelta);
720 }
721 }
722 }
723
724 template <typename A>
725 void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData)
726 {
727 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
728 if ( segIndex > segments.size() )
729 throw "bad segment index in rebase info";
730 const MachOLayoutAbstraction::Segment& seg = segments[segIndex];
731 uint8_t* mappedAddr = (uint8_t*)seg.mappedAddress() + segOffset;
732 pint_t* mappedAddrP = (pint_t*)mappedAddr;
733 uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
734 pint_t valueP;
735 pint_t valuePnew;
736 uint32_t value32;
737 int32_t svalue32;
738 int32_t svalue32new;
739 switch ( type ) {
740 case REBASE_TYPE_POINTER:
741 valueP= P::getP(*mappedAddrP);
742 try {
743 P::setP(*mappedAddrP, valueP + this->getSlideForVMAddress(valueP));
744 }
745 catch (const char* msg) {
746 throwf("at offset=0x%08llX in seg=%s, pointer cannot be rebased because it does not point to __TEXT or __DATA. %s\n",
747 segOffset, seg.name(), msg);
748 }
749 break;
750
751 case REBASE_TYPE_TEXT_ABSOLUTE32:
752 value32 = E::get32(*mappedAddr32);
753 E::set32(*mappedAddr32, value32 + this->getSlideForVMAddress(value32));
754 break;
755
756 case REBASE_TYPE_TEXT_PCREL32:
757 svalue32 = E::get32(*mappedAddr32);
758 valueP = seg.address() + segOffset + 4 + svalue32;
759 valuePnew = valueP + this->getSlideForVMAddress(valueP);
760 svalue32new = seg.address() + segOffset + 4 - valuePnew;
761 E::set32(*mappedAddr32, svalue32new);
762 break;
763
764 default:
765 throw "bad rebase type";
766 }
767 pointersInData.push_back(mappedAddr);
768 }
769
770
771 template <typename A>
772 void Rebaser<A>::applyRebaseInfo(std::vector<void*>& pointersInData)
773 {
774 const uint8_t* p = &fLinkEditBase[fDyldInfo->rebase_off()];
775 const uint8_t* end = &p[fDyldInfo->rebase_size()];
776
777 uint8_t type = 0;
778 int segIndex;
779 uint64_t segOffset = 0;
780 uint32_t count;
781 uint32_t skip;
782 bool done = false;
783 while ( !done && (p < end) ) {
784 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
785 uint8_t opcode = *p & REBASE_OPCODE_MASK;
786 ++p;
787 switch (opcode) {
788 case REBASE_OPCODE_DONE:
789 done = true;
790 break;
791 case REBASE_OPCODE_SET_TYPE_IMM:
792 type = immediate;
793 break;
794 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
795 segIndex = immediate;
796 segOffset = read_uleb128(p, end);
797 break;
798 case REBASE_OPCODE_ADD_ADDR_ULEB:
799 segOffset += read_uleb128(p, end);
800 break;
801 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
802 segOffset += immediate*sizeof(pint_t);
803 break;
804 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
805 for (int i=0; i < immediate; ++i) {
806 doRebase(segIndex, segOffset, type, pointersInData);
807 segOffset += sizeof(pint_t);
808 }
809 break;
810 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
811 count = read_uleb128(p, end);
812 for (uint32_t i=0; i < count; ++i) {
813 doRebase(segIndex, segOffset, type, pointersInData);
814 segOffset += sizeof(pint_t);
815 }
816 break;
817 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
818 doRebase(segIndex, segOffset, type, pointersInData);
819 segOffset += read_uleb128(p, end) + sizeof(pint_t);
820 break;
821 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
822 count = read_uleb128(p, end);
823 skip = read_uleb128(p, end);
824 for (uint32_t i=0; i < count; ++i) {
825 doRebase(segIndex, segOffset, type, pointersInData);
826 segOffset += skip + sizeof(pint_t);
827 }
828 break;
829 default:
830 throwf("bad rebase opcode %d", *p);
831 }
832 }
833 }
834
835 template <typename A>
836 void Rebaser<A>::adjustDATA()
837 {
838 // walk all local relocations and slide every pointer
839 const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->locreloff()]);
840 const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
841 for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
842 this->doLocalRelocation(reloc);
843 }
844
845 // walk non-lazy-pointers and slide the ones that are LOCAL
846 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
847 const uint32_t cmd_count = fHeader->ncmds();
848 const macho_load_command<P>* cmd = cmds;
849 for (uint32_t i = 0; i < cmd_count; ++i) {
850 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
851 const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
852 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
853 const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
854 const uint32_t* const indirectTable = (uint32_t*)(&fLinkEditBase[fDynamicSymbolTable->indirectsymoff()]);
855 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
856 if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
857 const uint32_t indirectTableOffset = sect->reserved1();
858 uint32_t pointerCount = sect->size() / sizeof(pint_t);
859 pint_t* nonLazyPointerAddr = this->mappedAddressForVMAddress(sect->addr());
860 for (uint32_t j=0; j < pointerCount; ++j, ++nonLazyPointerAddr) {
861 if ( E::get32(indirectTable[indirectTableOffset + j]) == INDIRECT_SYMBOL_LOCAL ) {
862 pint_t value = A::P::getP(*nonLazyPointerAddr);
863 P::setP(*nonLazyPointerAddr, value + this->getSlideForVMAddress(value));
864 }
865 }
866 }
867 }
868 }
869 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
870 }
871 }
872
873
874 template <typename A>
875 void Rebaser<A>::adjustRelocBaseAddresses()
876 {
877 // split seg file need reloc base to be first writable segment
878 if ( fSplittingSegments && ((fHeader->flags() & MH_SPLIT_SEGS) == 0) ) {
879
880 // get amount to adjust reloc address
881 int32_t relocAddressAdjust = 0;
882 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
883 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
884 const MachOLayoutAbstraction::Segment& seg = *it;
885 if ( seg.writable() ) {
886 relocAddressAdjust = seg.address() - segments[0].address();
887 break;
888 }
889 }
890
891 // walk all local relocations and adjust every address
892 macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->locreloff()]);
893 macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
894 for (macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
895 reloc->set_r_address(reloc->r_address()-relocAddressAdjust);
896 }
897
898 // walk all external relocations and adjust every address
899 macho_relocation_info<P>* const externRelocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->extreloff()]);
900 macho_relocation_info<P>* const externRelocsEnd = &externRelocsStart[fDynamicSymbolTable->nextrel()];
901 for (macho_relocation_info<P>* reloc=externRelocsStart; reloc < externRelocsEnd; ++reloc) {
902 reloc->set_r_address(reloc->r_address()-relocAddressAdjust);
903 }
904 }
905 }
906
907 template <>
908 void Rebaser<x86_64>::adjustRelocBaseAddresses()
909 {
910 // x86_64 already have reloc base of first writable segment
911 }
912
913
914 template <>
915 void Rebaser<x86_64>::doLocalRelocation(const macho_relocation_info<x86_64::P>* reloc)
916 {
917 if ( reloc->r_type() == X86_64_RELOC_UNSIGNED ) {
918 pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
919 pint_t value = P::getP(*addr);
920 P::setP(*addr, value + this->getSlideForVMAddress(value));
921 }
922 else {
923 throw "invalid relocation type";
924 }
925 }
926
927 template <>
928 void Rebaser<x86>::doLocalRelocation(const macho_relocation_info<P>* reloc)
929 {
930 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
931 if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
932 pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
933 pint_t value = P::getP(*addr);
934 P::setP(*addr, value + this->getSlideForVMAddress(value));
935 }
936 }
937 else {
938 macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
939 if ( sreloc->r_type() == GENERIC_RELOC_PB_LA_PTR ) {
940 sreloc->set_r_value( sreloc->r_value() + this->getSlideForVMAddress(sreloc->r_value()) );
941 }
942 else {
943 throw "cannot rebase final linked image with scattered relocations";
944 }
945 }
946 }
947
948 template <typename A>
949 void Rebaser<A>::doLocalRelocation(const macho_relocation_info<P>* reloc)
950 {
951 if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
952 if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
953 pint_t* addr = this->mappedAddressForRelocAddress(reloc->r_address());
954 pint_t value = P::getP(*addr);
955 P::setP(*addr, value + this->getSlideForVMAddress(value));
956 }
957 }
958 else {
959 throw "cannot rebase final linked image with scattered relocations";
960 }
961 }
962
963
964 template <typename A>
965 void Rebaser<A>::calculateRelocBase()
966 {
967 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
968 if ( fHeader->flags() & MH_SPLIT_SEGS ) {
969 // reloc addresses are from the start of the first writable segment
970 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
971 const MachOLayoutAbstraction::Segment& seg = *it;
972 if ( seg.writable() ) {
973 // found first writable segment
974 fOrignalVMRelocBaseAddress = seg.address();
975 fOrignalVMRelocBaseAddressValid = true;
976 }
977 }
978 }
979 else {
980 // reloc addresses are from the start of the mapped file (base address)
981 fOrignalVMRelocBaseAddress = segments[0].address();
982 fOrignalVMRelocBaseAddressValid = true;
983 }
984 }
985
986
987 template <>
988 void Rebaser<x86_64>::calculateRelocBase()
989 {
990 // reloc addresses are always based from the start of the first writable segment
991 const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
992 for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
993 const MachOLayoutAbstraction::Segment& seg = *it;
994 if ( seg.writable() ) {
995 // found first writable segment
996 fOrignalVMRelocBaseAddress = seg.address();
997 fOrignalVMRelocBaseAddressValid = true;
998 }
999 }
1000 }
1001
1002
1003 #if 0
1004 class MultiArchRebaser
1005 {
1006 public:
1007 MultiArchRebaser::MultiArchRebaser(const char* path, bool writable=false)
1008 : fMappingAddress(0), fFileSize(0)
1009 {
1010 // map in whole file
1011 int fd = ::open(path, (writable ? O_RDWR : O_RDONLY), 0);
1012 if ( fd == -1 )
1013 throwf("can't open file, errno=%d", errno);
1014 struct stat stat_buf;
1015 if ( fstat(fd, &stat_buf) == -1)
1016 throwf("can't stat open file %s, errno=%d", path, errno);
1017 if ( stat_buf.st_size < 20 )
1018 throwf("file too small %s", path);
1019 const int prot = writable ? (PROT_READ | PROT_WRITE) : PROT_READ;
1020 const int flags = writable ? (MAP_FILE | MAP_SHARED) : (MAP_FILE | MAP_PRIVATE);
1021 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, prot, flags, fd, 0);
1022 if ( p == (uint8_t*)(-1) )
1023 throwf("can't map file %s, errno=%d", path, errno);
1024 ::close(fd);
1025
1026 // if fat file, process each architecture
1027 const fat_header* fh = (fat_header*)p;
1028 const mach_header* mh = (mach_header*)p;
1029 if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1030 // Fat header is always big-endian
1031 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1032 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1033 uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
1034 try {
1035 switch ( OSSwapBigToHostInt32(archs[i].cputype) ) {
1036 case CPU_TYPE_I386:
1037 fRebasers.push_back(new Rebaser<x86>(&p[fileOffset]));
1038 break;
1039 case CPU_TYPE_X86_64:
1040 fRebasers.push_back(new Rebaser<x86_64>(&p[fileOffset]));
1041 break;
1042 case CPU_TYPE_ARM:
1043 fRebasers.push_back(new Rebaser<arm>(&p[fileOffset]));
1044 break;
1045 default:
1046 throw "unknown file format";
1047 }
1048 }
1049 catch (const char* msg) {
1050 fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
1051 }
1052 }
1053 }
1054 else {
1055 try {
1056 if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
1057 fRebasers.push_back(new Rebaser<x86>(mh));
1058 }
1059 else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
1060 fRebasers.push_back(new Rebaser<x86_64>(mh));
1061 }
1062 else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
1063 fRebasers.push_back(new Rebaser<arm>(mh));
1064 }
1065 else {
1066 throw "unknown file format";
1067 }
1068 }
1069 catch (const char* msg) {
1070 fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
1071 }
1072 }
1073
1074 fMappingAddress = p;
1075 fFileSize = stat_buf.st_size;
1076 }
1077
1078
1079 ~MultiArchRebaser() {::munmap(fMappingAddress, fFileSize); }
1080
1081 const std::vector<AbstractRebaser*>& getArchs() const { return fRebasers; }
1082 void commit() { ::msync(fMappingAddress, fFileSize, MS_ASYNC); }
1083
1084 private:
1085 std::vector<AbstractRebaser*> fRebasers;
1086 void* fMappingAddress;
1087 uint64_t fFileSize;
1088 };
1089 #endif
1090
1091
1092 #endif // __MACHO_REBASER__
1093
1094
1095
1096