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