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 = &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
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 = &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
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 = &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
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 = &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
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