1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2012 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
28 #include <mach/mach.h>
40 #include "MachOFileAbstraction.hpp"
41 #include "Architectures.hpp"
43 static bool verbose
= false;
45 __attribute__((noreturn
))
46 void throwf(const char* format
, ...)
50 va_start(list
, format
);
51 vasprintf(&p
, format
, list
);
62 virtual cpu_type_t
getArchitecture() const = 0;
63 virtual uint64_t getBaseAddress() const = 0;
64 virtual uint64_t getVMSize() const = 0;
65 virtual void setBaseAddress(uint64_t) = 0;
70 class Rebaser
: public AbstractRebaser
73 Rebaser(const void* machHeader
);
76 virtual cpu_type_t
getArchitecture() const;
77 virtual uint64_t getBaseAddress() const;
78 virtual uint64_t getVMSize() const;
79 virtual void setBaseAddress(uint64_t);
82 typedef typename
A::P P
;
83 typedef typename
A::P::E E
;
84 typedef typename
A::P::uint_t pint_t
;
86 struct vmmap
{ pint_t vmaddr
; pint_t vmsize
; pint_t fileoff
; };
89 void buildSectionTable();
90 void adjustLoadCommands();
91 void adjustSymbolTable();
93 void doLocalRelocation(const macho_relocation_info
<P
>* reloc
);
94 pint_t
* mappedAddressForVMAddress(uint32_t vmaddress
);
95 void rebaseAt(int segIndex
, uint64_t offset
, uint8_t type
);
97 const macho_header
<P
>* fHeader
;
98 pint_t fOrignalVMRelocBaseAddress
;
100 std::vector
<vmmap
> fVMMApping
;
105 class MultiArchRebaser
108 MultiArchRebaser(const char* path
, bool writable
=false);
111 const std::vector
<AbstractRebaser
*>& getArchs() const { return fRebasers
; }
115 std::vector
<AbstractRebaser
*> fRebasers
;
116 void* fMappingAddress
;
122 MultiArchRebaser::MultiArchRebaser(const char* path
, bool writable
)
123 : fMappingAddress(0), fFileSize(0)
126 int fd
= ::open(path
, (writable
? O_RDWR
: O_RDONLY
), 0);
128 throwf("can't open file %s, errno=%d", path
, errno
);
129 struct stat stat_buf
;
130 if ( fstat(fd
, &stat_buf
) == -1)
131 throwf("can't stat open file %s, errno=%d", path
, errno
);
132 if ( stat_buf
.st_size
< 20 )
133 throwf("file too small %s", path
);
134 const int prot
= writable
? (PROT_READ
| PROT_WRITE
) : PROT_READ
;
135 const int flags
= writable
? (MAP_FILE
| MAP_SHARED
) : (MAP_FILE
| MAP_PRIVATE
);
136 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, prot
, flags
, fd
, 0);
137 if ( p
== (uint8_t*)(-1) )
138 throwf("can't map file %s, errno=%d", path
, errno
);
141 // if fat file, process each architecture
142 const fat_header
* fh
= (fat_header
*)p
;
143 const mach_header
* mh
= (mach_header
*)p
;
144 if ( fh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
145 // Fat header is always big-endian
146 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
147 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
148 uint32_t fileOffset
= OSSwapBigToHostInt32(archs
[i
].offset
);
150 switch ( OSSwapBigToHostInt32(archs
[i
].cputype
) ) {
151 case CPU_TYPE_POWERPC
:
152 fRebasers
.push_back(new Rebaser
<ppc
>(&p
[fileOffset
]));
154 case CPU_TYPE_POWERPC64
:
155 fRebasers
.push_back(new Rebaser
<ppc64
>(&p
[fileOffset
]));
158 fRebasers
.push_back(new Rebaser
<x86
>(&p
[fileOffset
]));
160 case CPU_TYPE_X86_64
:
161 fRebasers
.push_back(new Rebaser
<x86_64
>(&p
[fileOffset
]));
164 fRebasers
.push_back(new Rebaser
<arm
>(&p
[fileOffset
]));
167 throw "unknown file format";
170 catch (const char* msg
) {
171 fprintf(stderr
, "rebase warning: %s for %s\n", msg
, path
);
177 if ( (OSSwapBigToHostInt32(mh
->magic
) == MH_MAGIC
) && (OSSwapBigToHostInt32(mh
->cputype
) == CPU_TYPE_POWERPC
)) {
178 fRebasers
.push_back(new Rebaser
<ppc
>(mh
));
180 else if ( (OSSwapBigToHostInt32(mh
->magic
) == MH_MAGIC_64
) && (OSSwapBigToHostInt32(mh
->cputype
) == CPU_TYPE_POWERPC64
)) {
181 fRebasers
.push_back(new Rebaser
<ppc64
>(mh
));
183 else if ( (OSSwapLittleToHostInt32(mh
->magic
) == MH_MAGIC
) && (OSSwapLittleToHostInt32(mh
->cputype
) == CPU_TYPE_I386
)) {
184 fRebasers
.push_back(new Rebaser
<x86
>(mh
));
186 else if ( (OSSwapLittleToHostInt32(mh
->magic
) == MH_MAGIC_64
) && (OSSwapLittleToHostInt32(mh
->cputype
) == CPU_TYPE_X86_64
)) {
187 fRebasers
.push_back(new Rebaser
<x86_64
>(mh
));
189 else if ( (OSSwapLittleToHostInt32(mh
->magic
) == MH_MAGIC
) && (OSSwapLittleToHostInt32(mh
->cputype
) == CPU_TYPE_ARM
)) {
190 fRebasers
.push_back(new Rebaser
<arm
>(mh
));
193 throw "unknown file format";
196 catch (const char* msg
) {
197 fprintf(stderr
, "rebase warning: %s for %s\n", msg
, path
);
202 fFileSize
= stat_buf
.st_size
;
206 MultiArchRebaser::~MultiArchRebaser()
208 ::munmap(fMappingAddress
, fFileSize
);
211 void MultiArchRebaser::commit()
213 ::msync(fMappingAddress
, fFileSize
, MS_ASYNC
);
218 template <typename A
>
219 Rebaser
<A
>::Rebaser(const void* machHeader
)
220 : fHeader((const macho_header
<P
>*)machHeader
)
222 switch ( fHeader
->filetype() ) {
224 if ( (fHeader
->flags() & MH_SPLIT_SEGS
) != 0 )
225 throw "split-seg dylibs cannot be rebased";
230 throw "file is not a dylib or bundle";
235 template <> cpu_type_t Rebaser
<ppc
>::getArchitecture() const { return CPU_TYPE_POWERPC
; }
236 template <> cpu_type_t Rebaser
<ppc64
>::getArchitecture() const { return CPU_TYPE_POWERPC64
; }
237 template <> cpu_type_t Rebaser
<x86
>::getArchitecture() const { return CPU_TYPE_I386
; }
238 template <> cpu_type_t Rebaser
<x86_64
>::getArchitecture() const { return CPU_TYPE_X86_64
; }
239 template <> cpu_type_t Rebaser
<arm
>::getArchitecture() const { return CPU_TYPE_ARM
; }
241 template <typename A
>
242 uint64_t Rebaser
<A
>::getBaseAddress() const
244 uint64_t lowestSegmentAddress
= LLONG_MAX
;
245 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
246 const uint32_t cmd_count
= fHeader
->ncmds();
247 const macho_load_command
<P
>* cmd
= cmds
;
248 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
249 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
250 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
251 if ( segCmd
->vmaddr() < lowestSegmentAddress
) {
252 lowestSegmentAddress
= segCmd
->vmaddr();
255 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
257 return lowestSegmentAddress
;
260 template <typename A
>
261 uint64_t Rebaser
<A
>::getVMSize() const
263 const macho_segment_command
<P
>* highestSegmentCmd
= NULL
;
264 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
265 const uint32_t cmd_count
= fHeader
->ncmds();
266 const macho_load_command
<P
>* cmd
= cmds
;
267 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
268 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
269 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
270 if ( (highestSegmentCmd
== NULL
) || (segCmd
->vmaddr() > highestSegmentCmd
->vmaddr()) ) {
271 highestSegmentCmd
= segCmd
;
274 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
277 return ((highestSegmentCmd
->vmaddr() + highestSegmentCmd
->vmsize() - this->getBaseAddress() + 4095) & (-4096));
281 template <typename A
>
282 void Rebaser
<A
>::setBaseAddress(uint64_t addr
)
285 fSlide
= addr
- this->getBaseAddress();
287 // compute base address for relocations
288 this->setRelocBase();
290 // build cache of section index to section
291 this->buildSectionTable();
293 // update load commands
294 this->adjustLoadCommands();
296 // update symbol table
297 this->adjustSymbolTable();
299 // update writable segments that have internal pointers
303 template <typename A
>
304 void Rebaser
<A
>::adjustLoadCommands()
306 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
307 const uint32_t cmd_count
= fHeader
->ncmds();
308 const macho_load_command
<P
>* cmd
= cmds
;
309 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
310 switch ( cmd
->cmd() ) {
312 if ( (fHeader
->flags() & MH_PREBOUND
) != 0 ) {
313 // clear timestamp so that any prebound clients are invalidated
314 macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
315 dylib
->set_timestamp(1);
319 case LC_LOAD_WEAK_DYLIB
:
320 case LC_REEXPORT_DYLIB
:
321 case LC_LOAD_UPWARD_DYLIB
:
322 if ( (fHeader
->flags() & MH_PREBOUND
) != 0 ) {
323 // clear expected timestamps so that this image will load with invalid prebinding
324 macho_dylib_command
<P
>* dylib
= (macho_dylib_command
<P
>*)cmd
;
325 dylib
->set_timestamp(2);
328 case macho_routines_command
<P
>::CMD
:
329 // update -init command
331 macho_routines_command
<P
>* routines
= (macho_routines_command
<P
>*)cmd
;
332 routines
->set_init_address(routines
->init_address() + fSlide
);
335 case macho_segment_command
<P
>::CMD
:
336 // update segment commands
338 macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
339 seg
->set_vmaddr(seg
->vmaddr() + fSlide
);
340 macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
341 macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
342 for(macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
343 sect
->set_addr(sect
->addr() + fSlide
);
348 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
353 template <typename A
>
354 void Rebaser
<A
>::buildSectionTable()
356 // build vector of sections
357 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
358 const uint32_t cmd_count
= fHeader
->ncmds();
359 const macho_load_command
<P
>* cmd
= cmds
;
360 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
361 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
362 const macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
364 mapping
.vmaddr
= seg
->vmaddr();
365 mapping
.vmsize
= seg
->vmsize();
366 mapping
.fileoff
= seg
->fileoff();
367 fVMMApping
.push_back(mapping
);
369 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
374 template <typename A
>
375 void Rebaser
<A
>::adjustSymbolTable()
377 const macho_dysymtab_command
<P
>* dysymtab
= NULL
;
378 macho_nlist
<P
>* symbolTable
= NULL
;
379 const char* strings
= NULL
;
381 // get symbol table info
382 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
383 const uint32_t cmd_count
= fHeader
->ncmds();
384 const macho_load_command
<P
>* cmd
= cmds
;
385 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
386 switch (cmd
->cmd()) {
389 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
390 symbolTable
= (macho_nlist
<P
>*)(((uint8_t*)fHeader
) + symtab
->symoff());
391 strings
= (char*)(((uint8_t*)fHeader
) + symtab
->stroff());
395 dysymtab
= (macho_dysymtab_command
<P
>*)cmd
;
398 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
401 // walk all exports and slide their n_value
402 macho_nlist
<P
>* lastExport
= &symbolTable
[dysymtab
->iextdefsym()+dysymtab
->nextdefsym()];
403 for (macho_nlist
<P
>* entry
= &symbolTable
[dysymtab
->iextdefsym()]; entry
< lastExport
; ++entry
) {
404 if ( (entry
->n_type() & N_TYPE
) == N_SECT
)
405 entry
->set_n_value(entry
->n_value() + fSlide
);
408 // walk all local symbols and slide their n_value
409 macho_nlist
<P
>* lastLocal
= &symbolTable
[dysymtab
->ilocalsym()+dysymtab
->nlocalsym()];
410 for (macho_nlist
<P
>* entry
= &symbolTable
[dysymtab
->ilocalsym()]; entry
< lastLocal
; ++entry
) {
411 if ( ((entry
->n_type() & N_STAB
) == 0) && ((entry
->n_type() & N_TYPE
) == N_SECT
) ) {
412 entry
->set_n_value(entry
->n_value() + fSlide
);
414 else if ( entry
->n_type() & N_STAB
) {
415 // some stabs need to be slid too
416 switch ( entry
->n_type() ) {
418 // don't slide end-of-function FUN which is FUN with no string
419 if ( (entry
->n_strx() == 0) || (strings
[entry
->n_strx()] == '\0') )
424 entry
->set_n_value(entry
->n_value() + fSlide
);
430 // FIXME ¥¥¥ adjust dylib_module if it exists
433 static uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
439 throwf("malformed uleb128");
441 uint64_t slice
= *p
& 0x7f;
443 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
444 throwf("uleb128 too big");
446 result
|= (slice
<< bit
);
454 template <typename A
>
455 void Rebaser
<A
>::rebaseAt(int segIndex
, uint64_t offset
, uint8_t type
)
457 //fprintf(stderr, "rebaseAt(seg=%d, offset=0x%08llX, type=%d\n", segIndex, offset, type);
458 static int lastSegIndex
= -1;
459 static uint8_t* lastSegMappedStart
= NULL
;
460 if ( segIndex
!= lastSegIndex
) {
461 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
462 const uint32_t cmd_count
= fHeader
->ncmds();
463 const macho_load_command
<P
>* cmd
= cmds
;
465 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
466 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
467 if ( segIndex
== segCount
) {
468 const macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
469 lastSegMappedStart
= (uint8_t*)fHeader
+ seg
->fileoff();
470 lastSegIndex
= segCount
;
475 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
479 pint_t
* locationToFix
= (pint_t
*)(lastSegMappedStart
+offset
);
480 uint32_t* locationToFix32
= (uint32_t*)(lastSegMappedStart
+offset
);
482 case REBASE_TYPE_POINTER
:
483 P::setP(*locationToFix
, A::P::getP(*locationToFix
) + fSlide
);
485 case REBASE_TYPE_TEXT_ABSOLUTE32
:
486 E::set32(*locationToFix32
, E::get32(*locationToFix32
) + fSlide
);
489 throwf("bad rebase type %d", type
);
494 template <typename A
>
495 void Rebaser
<A
>::adjustDATA()
497 const macho_dysymtab_command
<P
>* dysymtab
= NULL
;
498 const macho_dyld_info_command
<P
>* dyldInfo
= NULL
;
500 // get symbol table info
501 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
502 const uint32_t cmd_count
= fHeader
->ncmds();
503 const macho_load_command
<P
>* cmd
= cmds
;
504 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
505 switch (cmd
->cmd()) {
507 dysymtab
= (macho_dysymtab_command
<P
>*)cmd
;
510 case LC_DYLD_INFO_ONLY
:
511 dyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
514 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
517 // use new encoding of rebase info if present
518 if ( dyldInfo
!= NULL
) {
519 if ( dyldInfo
->rebase_size() != 0 ) {
520 const uint8_t* p
= (uint8_t*)fHeader
+ dyldInfo
->rebase_off();
521 const uint8_t* end
= &p
[dyldInfo
->rebase_size()];
529 while ( !done
&& (p
< end
) ) {
530 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
531 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
534 case REBASE_OPCODE_DONE
:
537 case REBASE_OPCODE_SET_TYPE_IMM
:
540 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
541 segIndex
= immediate
;
542 offset
= read_uleb128(p
, end
);
544 case REBASE_OPCODE_ADD_ADDR_ULEB
:
545 offset
+= read_uleb128(p
, end
);
547 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
548 offset
+= immediate
*sizeof(pint_t
);
550 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
:
551 for (int i
=0; i
< immediate
; ++i
) {
552 rebaseAt(segIndex
, offset
, type
);
553 offset
+= sizeof(pint_t
);
556 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
557 count
= read_uleb128(p
, end
);
558 for (uint32_t i
=0; i
< count
; ++i
) {
559 rebaseAt(segIndex
, offset
, type
);
560 offset
+= sizeof(pint_t
);
563 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
564 rebaseAt(segIndex
, offset
, type
);
565 offset
+= read_uleb128(p
, end
) + sizeof(pint_t
);
567 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
568 count
= read_uleb128(p
, end
);
569 skip
= read_uleb128(p
, end
);
570 for (uint32_t i
=0; i
< count
; ++i
) {
571 rebaseAt(segIndex
, offset
, type
);
572 offset
+= skip
+ sizeof(pint_t
);
576 throwf("bad rebase opcode %d", *p
);
585 // walk all local relocations and slide every pointer
586 const macho_relocation_info
<P
>* const relocsStart
= (macho_relocation_info
<P
>*)(((uint8_t*)fHeader
) + dysymtab
->locreloff());
587 const macho_relocation_info
<P
>* const relocsEnd
= &relocsStart
[dysymtab
->nlocrel()];
588 for (const macho_relocation_info
<P
>* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
589 this->doLocalRelocation(reloc
);
592 // walk non-lazy-pointers and slide the ones that are LOCAL
594 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
595 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
596 const macho_segment_command
<P
>* seg
= (macho_segment_command
<P
>*)cmd
;
597 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)seg
+ sizeof(macho_segment_command
<P
>));
598 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[seg
->nsects()];
599 const uint32_t* const indirectTable
= (uint32_t*)(((uint8_t*)fHeader
) + dysymtab
->indirectsymoff());
600 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
601 if ( (sect
->flags() & SECTION_TYPE
) == S_NON_LAZY_SYMBOL_POINTERS
) {
602 const uint32_t indirectTableOffset
= sect
->reserved1();
603 uint32_t pointerCount
= sect
->size() / sizeof(pint_t
);
604 pint_t
* nonLazyPointer
= (pint_t
*)(((uint8_t*)fHeader
) + sect
->offset());
605 for (uint32_t i
=0; i
< pointerCount
; ++i
, ++nonLazyPointer
) {
606 if ( E::get32(indirectTable
[indirectTableOffset
+ i
]) == INDIRECT_SYMBOL_LOCAL
) {
607 P::setP(*nonLazyPointer
, A::P::getP(*nonLazyPointer
) + fSlide
);
613 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
619 template <typename A
>
620 typename
A::P::uint_t
* Rebaser
<A
>::mappedAddressForVMAddress(uint32_t vmaddress
)
622 for(typename
std::vector
<vmmap
>::iterator it
= fVMMApping
.begin(); it
!= fVMMApping
.end(); ++it
) {
623 //fprintf(stderr, "vmaddr=0x%08lX, vmsize=0x%08lX\n", it->vmaddr, it->vmsize);
624 if ( (vmaddress
>= it
->vmaddr
) && (vmaddress
< (it
->vmaddr
+it
->vmsize
)) ) {
625 return (pint_t
*)((vmaddress
- it
->vmaddr
) + it
->fileoff
+ (uint8_t*)fHeader
);
628 throwf("reloc address 0x%08X not found", vmaddress
);
633 void Rebaser
<x86_64
>::doLocalRelocation(const macho_relocation_info
<x86_64::P
>* reloc
)
635 if ( reloc
->r_type() == X86_64_RELOC_UNSIGNED
) {
636 pint_t
* addr
= mappedAddressForVMAddress(reloc
->r_address() + fOrignalVMRelocBaseAddress
);
637 P::setP(*addr
, P::getP(*addr
) + fSlide
);
640 throw "invalid relocation type";
645 void Rebaser
<ppc
>::doLocalRelocation(const macho_relocation_info
<P
>* reloc
)
647 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
648 if ( reloc
->r_type() == GENERIC_RELOC_VANILLA
) {
649 pint_t
* addr
= mappedAddressForVMAddress(reloc
->r_address() + fOrignalVMRelocBaseAddress
);
650 P::setP(*addr
, P::getP(*addr
) + fSlide
);
654 throw "cannot rebase final linked image with scattered relocations";
659 void Rebaser
<x86
>::doLocalRelocation(const macho_relocation_info
<P
>* reloc
)
661 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
662 if ( reloc
->r_type() == GENERIC_RELOC_VANILLA
) {
663 pint_t
* addr
= mappedAddressForVMAddress(reloc
->r_address() + fOrignalVMRelocBaseAddress
);
664 P::setP(*addr
, P::getP(*addr
) + fSlide
);
668 macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
669 if ( sreloc
->r_type() == GENERIC_RELOC_PB_LA_PTR
) {
670 sreloc
->set_r_value( sreloc
->r_value() + fSlide
);
673 throw "cannot rebase final linked image with scattered relocations";
678 #if SUPPORT_ARCH_arm_any
680 void Rebaser
<arm
>::doLocalRelocation(const macho_relocation_info
<P
>* reloc
)
682 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
683 if ( reloc
->r_type() == ARM_RELOC_VANILLA
) {
684 pint_t
* addr
= mappedAddressForVMAddress(reloc
->r_address() + fOrignalVMRelocBaseAddress
);
685 P::setP(*addr
, P::getP(*addr
) + fSlide
);
689 macho_scattered_relocation_info
<P
>* sreloc
= (macho_scattered_relocation_info
<P
>*)reloc
;
690 if ( sreloc
->r_type() == ARM_RELOC_PB_LA_PTR
) {
691 sreloc
->set_r_value( sreloc
->r_value() + fSlide
);
694 throw "cannot rebase final linked image with scattered relocations";
700 template <typename A
>
701 void Rebaser
<A
>::doLocalRelocation(const macho_relocation_info
<P
>* reloc
)
703 if ( (reloc
->r_address() & R_SCATTERED
) == 0 ) {
704 if ( reloc
->r_type() == GENERIC_RELOC_VANILLA
) {
705 pint_t
* addr
= mappedAddressForVMAddress(reloc
->r_address() + fOrignalVMRelocBaseAddress
);
706 P::setP(*addr
, P::getP(*addr
) + fSlide
);
710 throw "cannot rebase final linked image with scattered relocations";
715 template <typename A
>
716 void Rebaser
<A
>::setRelocBase()
718 // reloc addresses are from the start of the mapped file (base address)
719 fOrignalVMRelocBaseAddress
= this->getBaseAddress();
720 //fprintf(stderr, "fOrignalVMRelocBaseAddress=0x%08X\n", fOrignalVMRelocBaseAddress);
724 void Rebaser
<ppc64
>::setRelocBase()
726 // reloc addresses either:
727 // 1) from the base address if no writable segment is > 4GB from base address
728 // 2) from start of first writable segment
729 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
730 const uint32_t cmd_count
= fHeader
->ncmds();
731 const macho_load_command
<P
>* cmd
= cmds
;
732 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
733 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
734 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
735 if ( segCmd
->initprot() & VM_PROT_WRITE
) {
736 if ( (segCmd
->vmaddr() + segCmd
->vmsize() - this->getBaseAddress()) > 0x100000000ULL
) {
737 // found writable segment with address > 4GB past base address
738 fOrignalVMRelocBaseAddress
= segCmd
->vmaddr();
743 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
745 // just use base address
746 fOrignalVMRelocBaseAddress
= this->getBaseAddress();
750 void Rebaser
<x86_64
>::setRelocBase()
752 // reloc addresses are always based from the start of the first writable segment
753 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
754 const uint32_t cmd_count
= fHeader
->ncmds();
755 const macho_load_command
<P
>* cmd
= cmds
;
756 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
757 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
758 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
759 if ( segCmd
->initprot() & VM_PROT_WRITE
) {
760 fOrignalVMRelocBaseAddress
= segCmd
->vmaddr();
764 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
766 throw "no writable segment";
770 static void copyFile(const char* srcFile
, const char* dstFile
)
773 int src
= open(srcFile
, O_RDONLY
);
775 throwf("can't open file %s, errno=%d", srcFile
, errno
);
776 struct stat stat_buf
;
777 if ( fstat(src
, &stat_buf
) == -1)
778 throwf("can't stat open file %s, errno=%d", srcFile
, errno
);
780 // create new file with all same permissions to hold copy of dylib
782 int dst
= open(dstFile
, O_CREAT
| O_RDWR
| O_TRUNC
, stat_buf
.st_mode
);
784 throwf("can't create temp file %s, errnor=%d", dstFile
, errno
);
786 // mark source as "don't cache"
787 (void)fcntl(src
, F_NOCACHE
, 1);
788 // we want to cache the dst because we are about to map it in and modify it
790 // copy permission bits
791 if ( chmod(dstFile
, stat_buf
.st_mode
& 07777) == -1 )
792 throwf("can't chmod temp file %s, errno=%d", dstFile
, errno
);
793 if ( chown(dstFile
, stat_buf
.st_uid
, stat_buf
.st_gid
) == -1)
794 throwf("can't chown temp file %s, errno=%d", dstFile
, errno
);
798 const uint32_t kBufferSize
= 128*1024;
799 static uint8_t* buffer
= NULL
;
800 if ( buffer
== NULL
) {
801 vm_address_t addr
= 0;
802 if ( vm_allocate(mach_task_self(), &addr
, kBufferSize
, true /*find range*/) == KERN_SUCCESS
)
803 buffer
= (uint8_t*)addr
;
805 throw "can't allcoate copy buffer";
807 while ( (len
= read(src
, buffer
, kBufferSize
)) > 0 ) {
808 if ( write(dst
, buffer
, len
) == -1 )
809 throwf("write failure copying feil %s, errno=%d", dstFile
, errno
);
813 int result1
= close(dst
);
814 int result2
= close(src
);
815 if ( (result1
!= 0) || (result2
!= 0) )
816 throw "can't close file";
820 // scan dylibs and collect size info
821 // calculate new base address for each dylib
823 // copy to temp and mmap
837 fileInfo(const char* p
) : path(p
) {}
840 std::vector
<archInfo
> archs
;
844 // add archInfos to fileInfo for every slice of a fat file
845 // for ppc, there may be duplicate architectures (with different sub-types)
847 static void setSizes(fileInfo
& info
, const std::set
<cpu_type_t
>& onlyArchs
)
849 const MultiArchRebaser
mar(info
.path
);
850 const std::vector
<AbstractRebaser
*>& rebasers
= mar
.getArchs();
851 for(std::set
<cpu_type_t
>::iterator ait
=onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
852 for(std::vector
<AbstractRebaser
*>::const_iterator rit
=rebasers
.begin(); rit
!= rebasers
.end(); ++rit
) {
853 AbstractRebaser
* rebaser
= *rit
;
854 if ( rebaser
->getArchitecture() == *ait
) {
857 ai
.vmSize
= rebaser
->getVMSize();
858 ai
.orgBase
= rebaser
->getBaseAddress();
860 //fprintf(stderr, "base=0x%llX, size=0x%llX\n", ai.orgBase, ai.vmSize);
861 info
.archs
.push_back(ai
);
867 static const char* nameForArch(cpu_type_t arch
)
870 case CPU_TYPE_POWERPC
:
872 case CPU_TYPE_POWERPC64
:
876 case CPU_TYPE_X86_64
:
884 static void rebase(const fileInfo
& info
)
886 // generate temp file name
887 char realFilePath
[PATH_MAX
];
888 if ( realpath(info
.path
, realFilePath
) == NULL
) {
889 throwf("realpath() failed on %s, errno=%d", info
.path
, errno
);
891 const char* tempPath
;
892 asprintf((char**)&tempPath
, "%s_rebase", realFilePath
);
894 // copy whole file to temp file
895 copyFile(info
.path
, tempPath
);
899 MultiArchRebaser
mar(tempPath
, true);
900 const std::vector
<AbstractRebaser
*>& rebasers
= mar
.getArchs();
901 for(std::vector
<archInfo
>::const_iterator fait
=info
.archs
.begin(); fait
!= info
.archs
.end(); ++fait
) {
902 for(std::vector
<AbstractRebaser
*>::const_iterator rit
=rebasers
.begin(); rit
!= rebasers
.end(); ++rit
) {
903 if ( (*rit
)->getArchitecture() == fait
->arch
) {
904 (*rit
)->setBaseAddress(fait
->newBase
);
906 printf("%8s 0x%0llX -> 0x%0llX %s\n", nameForArch(fait
->arch
), fait
->orgBase
, fait
->newBase
, info
.path
);
911 // flush temp file out to disk
915 int result
= rename(tempPath
, info
.path
);
917 throwf("can't swap temporary rebased file: rename(%s,%s) returned errno=%d", tempPath
, info
.path
, errno
);
920 // make sure every really gets out to disk
923 catch (const char* msg
) {
927 // throw exception with file name added
929 asprintf((char**)&newMsg
, "%s for file %s", msg
, info
.path
);
934 static uint64_t totalVMSize(cpu_type_t arch
, std::vector
<fileInfo
>& files
)
936 uint64_t totalSize
= 0;
937 for(std::vector
<fileInfo
>::iterator fit
=files
.begin(); fit
!= files
.end(); ++fit
) {
939 for(std::vector
<archInfo
>::iterator fait
=fi
.archs
.begin(); fait
!= fi
.archs
.end(); ++fait
) {
940 if ( fait
->arch
== arch
)
941 totalSize
+= fait
->vmSize
;
947 static uint64_t startAddress(cpu_type_t arch
, std::vector
<fileInfo
>& files
, uint64_t lowAddress
, uint64_t highAddress
)
949 if ( lowAddress
!= 0 )
951 else if ( highAddress
!= 0 ) {
952 uint64_t totalSize
= totalVMSize(arch
, files
);
953 if ( highAddress
< totalSize
)
954 throwf("cannot use -high_address 0x%X because total size of images is greater: 0x%X", highAddress
, totalSize
);
955 return highAddress
- totalSize
;
958 if ( (arch
== CPU_TYPE_I386
) || (arch
== CPU_TYPE_POWERPC
) ) {
959 // place dylibs below dyld
960 uint64_t topAddr
= 0x8FE00000;
961 uint64_t totalSize
= totalVMSize(arch
, files
);
962 if ( totalSize
> topAddr
)
963 throwf("total size of images (0x%X) does not fit below 0x8FE00000", totalSize
);
964 return topAddr
- totalSize
;
966 else if ( arch
== CPU_TYPE_POWERPC64
) {
967 return 0x200000000ULL
;
969 else if ( arch
== CPU_TYPE_X86_64
) {
970 return 0x200000000ULL
;
972 else if ( arch
== CPU_TYPE_ARM
) {
973 // place dylibs below dyld
974 uint64_t topAddr
= 0x2FE00000;
975 uint64_t totalSize
= totalVMSize(arch
, files
);
976 if ( totalSize
> topAddr
)
977 throwf("total size of images (0x%X) does not fit below 0x2FE00000", totalSize
);
978 return topAddr
- totalSize
;
981 throw "unknown architecture";
987 fprintf(stderr
, "rebase [-low_address] [-high_address] [-v] [-arch <arch>] files...\n");
991 int main(int argc
, const char* argv
[])
993 std::vector
<fileInfo
> files
;
994 std::set
<cpu_type_t
> onlyArchs
;
995 uint64_t lowAddress
= 0;
996 uint64_t highAddress
= 0;
999 // parse command line options
1001 for(int i
=1; i
< argc
; ++i
) {
1002 const char* arg
= argv
[i
];
1003 if ( arg
[0] == '-' ) {
1004 if ( strcmp(arg
, "-v") == 0 ) {
1007 else if ( strcmp(arg
, "-low_address") == 0 ) {
1008 lowAddress
= strtoull(argv
[++i
], &endptr
, 16);
1010 else if ( strcmp(arg
, "-high_address") == 0 ) {
1011 highAddress
= strtoull(argv
[++i
], &endptr
, 16);
1013 else if ( strcmp(arg
, "-arch") == 0 ) {
1014 const char* archName
= argv
[++i
];
1015 if ( archName
== NULL
)
1016 throw "-arch missing architecture name";
1018 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
1019 if ( strcmp(t
->archName
,archName
) == 0 ) {
1020 onlyArchs
.insert(t
->cpuType
);
1025 throwf("unknown architecture %s", archName
);
1029 throwf("unknown option: %s\n", arg
);
1033 files
.push_back(fileInfo(arg
));
1037 if ( files
.size() == 0 )
1038 throw "no files specified";
1040 // use all architectures if no restrictions specified
1041 if ( onlyArchs
.size() == 0 ) {
1042 onlyArchs
.insert(CPU_TYPE_POWERPC
);
1043 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
1044 onlyArchs
.insert(CPU_TYPE_I386
);
1045 onlyArchs
.insert(CPU_TYPE_X86_64
);
1046 onlyArchs
.insert(CPU_TYPE_ARM
);
1049 // scan files and collect sizes
1050 for(std::vector
<fileInfo
>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
1051 setSizes(*it
, onlyArchs
);
1054 // assign new base address for each arch
1055 for(std::set
<cpu_type_t
>::iterator ait
=onlyArchs
.begin(); ait
!= onlyArchs
.end(); ++ait
) {
1056 cpu_type_t arch
= *ait
;
1057 uint64_t baseAddress
= startAddress(arch
, files
, lowAddress
, highAddress
);
1058 for(std::vector
<fileInfo
>::iterator fit
=files
.begin(); fit
!= files
.end(); ++fit
) {
1059 fileInfo
& fi
= *fit
;
1060 for(std::vector
<archInfo
>::iterator fait
=fi
.archs
.begin(); fait
!= fi
.archs
.end(); ++fait
) {
1061 if ( fait
->arch
== arch
) {
1062 fait
->newBase
= baseAddress
;
1063 baseAddress
+= fait
->vmSize
;
1064 baseAddress
= (baseAddress
+ 4095) & (-4096); // page align
1070 // rebase each file if it contains something rebaseable
1071 for(std::vector
<fileInfo
>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
1073 if ( fi
.archs
.size() > 0 )
1078 catch (const char* msg
) {
1079 fprintf(stderr
, "rebase failed: %s\n", msg
);