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 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; 59 virtual void rebase(std::vector<void*>&) = 0; 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; 73 virtual void rebase(std::vector<void*>&); 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); 82 83private: 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 104protected: 105 const macho_header<P>* fHeader; 106 uint8_t* fLinkEditBase; // add file offset to this to get linkedit content 107 const MachOLayoutAbstraction& fLayout; 108private: 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 121template <typename A> 122Rebaser<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 172template <> cpu_type_t Rebaser<x86>::getArchitecture() const { return CPU_TYPE_I386; } 173template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; } 174template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; } 175 176template <typename A> 177bool 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 189template <typename A> 190uint64_t Rebaser<A>::getBaseAddress() const 191{ 192 return fLayout.getSegments()[0].address(); 193} 194 195template <typename A> 196uint64_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 210template <typename A> 211void 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 239template <> 240void 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 247template <typename A> 248void Rebaser<A>::adjustSegmentLoadCommand(macho_segment_command<P>* seg) 249{ 250} 251 252 253template <typename A> 254void 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 = §ionsStart[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 306template <typename A> 307typename 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 320template <typename A> 321typename 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 333template <typename A> 334typename 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 346template <typename A> 347typename 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 359template <typename A> 360typename 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 369template <> 370void 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 389template <> 390void 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 = §ionsStart[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 423template <typename A> 424void Rebaser<A>::optimzeStubs() 425{ 426 // other architectures don't need stubs changed in shared cache 427} 428 429template <typename A> 430void 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 449template <typename A> 450void 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 506template <typename A> 507void 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 639template <typename A> 640const 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 665template <typename A> 666void 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 = §ionsStart[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 724template <typename A> 725void 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 771template <typename A> 772void 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 835template <typename A> 836void 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 = §ionsStart[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 874template <typename A> 875void 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 907template <> 908void Rebaser<x86_64>::adjustRelocBaseAddresses() 909{ 910 // x86_64 already have reloc base of first writable segment 911} 912 913 914template <> 915void 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 927template <> 928void 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 948template <typename A> 949void 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 964template <typename A> 965void 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 987template <> 988void 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 1004class MultiArchRebaser 1005{ 1006public: 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 1084private: 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 1097