1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006-2011 Apple 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_BINDER__
26#define __MACHO_BINDER__
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
41#include <vector>
42#include <set>
43#include <unordered_map>
44#include <unordered_set>
45
46#include "MachOFileAbstraction.hpp"
47#include "Architectures.hpp"
48#include "MachOLayout.hpp"
49#include "MachORebaser.hpp"
50#include "MachOTrie.hpp"
51
52#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
53	#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
54#endif
55
56#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
57	#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
58#endif
59
60
61template <typename A>
62class Binder : public Rebaser<A>
63{
64public:
65	class CStringHash {
66	public:
67		size_t operator()(const char* __s) const {
68			size_t __h = 0;
69			for ( ; *__s; ++__s)
70				__h = 5 * __h + *__s;
71			return __h;
72		};
73	};
74	struct CStringEquals {
75		bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
76	};
77	typedef std::unordered_map<const char*, class Binder<A>*, CStringHash, CStringEquals> Map;
78
79
80												Binder(const MachOLayoutAbstraction&, uint64_t dyldBaseAddress);
81	virtual										~Binder() {}
82
83	const char*									getDylibID() const;
84	void										setDependentBinders(const Map& map);
85	void										bind(std::vector<void*>&);
86	void										optimize();
87    void                                        addResolverClient(Binder<A>* clientDylib, const char* symbolName);
88private:
89	typedef typename A::P					P;
90	typedef typename A::P::E				E;
91	typedef typename A::P::uint_t			pint_t;
92	struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; };
93	struct SymbolReExport { const char* exportName; int dylibOrdinal; const char* importName; };
94	typedef std::unordered_map<const char*, pint_t, CStringHash, CStringEquals> NameToAddrMap;
95	typedef std::unordered_set<const char*, CStringHash, CStringEquals> NameSet;
96    struct ClientAndSymbol { Binder<A>* client; const char* symbolName; };
97    struct SymbolAndLazyPointer { const char* symbolName; pint_t lpVMAddr; };
98
99	static bool									isPublicLocation(const char* pth);
100	void										doBindExternalRelocations();
101	void										doBindIndirectSymbols();
102	void										doSetUpDyldSection();
103	void										doSetPreboundUndefines();
104	void										hoistPrivateRexports();
105	int											ordinalOfDependentBinder(Binder<A>* dep);
106	void										doBindDyldInfo(std::vector<void*>& pointersInData);
107	void										doBindDyldLazyInfo(std::vector<void*>& pointersInData);
108	void										bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type,
109																int libraryOrdinal, int64_t addend,
110																const char* symbolName, bool lazyPointer, bool weakImport,
111																std::vector<void*>& pointersInData);
112	pint_t										resolveUndefined(const macho_nlist<P>* undefinedSymbol);
113	bool										findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn,
114																			bool* isResolverSymbol, bool* isAbsolute);
115	void										bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
116	const char*									parentUmbrella();
117	pint_t										runtimeAddressFromNList(const macho_nlist<P>* sym);
118    void                                        optimizeStub(const char* symbolName, pint_t lpVMAddr);
119    void                                        optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr);
120    pint_t                                      findLazyPointerFor(const char* symbolName);
121
122
123	static uint8_t								pointerRelocSize();
124	static uint8_t								pointerRelocType();
125
126	std::vector<BinderAndReExportFlag>			fDependentDylibs;
127	NameToAddrMap								fHashTable;
128	NameSet										fSymbolResolvers;
129	NameSet										fAbsoluteSymbols;
130	std::vector<SymbolReExport>					fReExportedSymbols;
131	uint64_t									fDyldBaseAddress;
132	const macho_nlist<P>*						fSymbolTable;
133	const char*									fStrings;
134	const macho_dysymtab_command<P>*			fDynamicInfo;
135	const macho_segment_command<P>*				fFristWritableSegment;
136	const macho_dylib_command<P>*				fDylibID;
137	const macho_dylib_command<P>*				fParentUmbrella;
138	const macho_dyld_info_command<P>*			fDyldInfo;
139	bool										fOriginallyPrebound;
140	bool										fReExportedSymbolsResolved;
141    std::vector<ClientAndSymbol>                fClientAndSymbols;
142	NameToAddrMap								fResolverLazyPointers;
143};
144
145template <>
146uint32_t Binder<arm>::runtimeAddressFromNList(const macho_nlist<Pointer32<LittleEndian> >* sym)
147{
148	if (sym->n_desc() & N_ARM_THUMB_DEF)
149		return sym->n_value() + 1;
150	else
151		return sym->n_value();
152}
153
154template <typename A>
155typename A::P::uint_t	Binder<A>::runtimeAddressFromNList(const macho_nlist<P>* sym)
156{
157	return sym->n_value();
158}
159
160
161template <typename A>
162Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress)
163	: Rebaser<A>(layout), fDyldBaseAddress(dyldBaseAddress),
164	  fSymbolTable(NULL), fStrings(NULL), fDynamicInfo(NULL),
165	  fFristWritableSegment(NULL), fDylibID(NULL), fDyldInfo(NULL),
166	  fParentUmbrella(NULL), fReExportedSymbolsResolved(false)
167{
168	fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
169	// update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
170	((macho_header<P>*)this->fHeader)->set_flags(this->fHeader->flags() | MH_PREBOUND | MH_SPLIT_SEGS | 0x80000000);
171
172	// calculate fDynamicInfo, fStrings, fSymbolTable
173	const macho_symtab_command<P>* symtab;
174	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
175	const uint32_t cmd_count = this->fHeader->ncmds();
176	const macho_load_command<P>* cmd = cmds;
177	for (uint32_t i = 0; i < cmd_count; ++i) {
178		switch (cmd->cmd()) {
179			case LC_SYMTAB:
180				symtab = (macho_symtab_command<P>*)cmd;
181				fSymbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
182				fStrings = (const char*)&this->fLinkEditBase[symtab->stroff()];
183				break;
184			case LC_DYSYMTAB:
185				fDynamicInfo = (macho_dysymtab_command<P>*)cmd;
186				break;
187			case LC_ID_DYLIB:
188				((macho_dylib_command<P>*)cmd)->set_timestamp(0);
189				fDylibID = (macho_dylib_command<P>*)cmd;
190				break;
191			case LC_LOAD_DYLIB:
192			case LC_LOAD_WEAK_DYLIB:
193			case LC_REEXPORT_DYLIB:
194			case LC_LOAD_UPWARD_DYLIB:
195				((macho_dylib_command<P>*)cmd)->set_timestamp(0);
196				break;
197			case LC_SUB_FRAMEWORK:
198				fParentUmbrella = (macho_dylib_command<P>*)cmd;
199				break;
200			case LC_DYLD_INFO:
201			case LC_DYLD_INFO_ONLY:
202				fDyldInfo = (macho_dyld_info_command<P>*)cmd;
203				break;
204			case LC_RPATH:
205				throwf("dyld shared cache does not support LC_RPATH found in %s", layout.getFilePath());
206				break;
207			default:
208				if ( cmd->cmd() & LC_REQ_DYLD )
209					throwf("unknown required load command 0x%08X", cmd->cmd());
210		}
211		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
212	}
213	if ( fDynamicInfo == NULL )
214		throw "no LC_DYSYMTAB";
215	if ( fSymbolTable == NULL )
216		throw "no LC_SYMTAB";
217	// build hash table
218//	fprintf(stderr, "exports for %s\n", layout.getFilePath());
219	if ( fDyldInfo != NULL ) {
220		std::vector<mach_o::trie::Entry> exports;
221		const uint8_t* exportsStart = layout.getDyldInfoExports();
222		const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
223		mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
224		pint_t baseAddress = layout.getSegments()[0].newAddress();
225		for(std::vector<mach_o::trie::Entry>::iterator it = exports.begin(); it != exports.end(); ++it) {
226			switch ( it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK ) {
227				case EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
228					if ( (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
229						fSymbolResolvers.insert(it->name);
230					}
231					if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
232						//fprintf(stderr, "found re-export %s in %s\n", sym.exportName, this->getDylibID());
233						SymbolReExport sym;
234						sym.exportName = it->name;
235						sym.dylibOrdinal = it->other;
236						sym.importName = it->importName;
237						if ( (sym.importName == NULL) || (sym.importName[0] == '\0') )
238							sym.importName = sym.exportName;
239						fReExportedSymbols.push_back(sym);
240						// fHashTable entry will be added in first call to findExportedSymbolAddress()
241					}
242					else {
243						fHashTable[it->name] = it->address + baseAddress;
244					}
245					break;
246				case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
247					fHashTable[it->name] = it->address + baseAddress;
248					break;
249				case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE:
250					fHashTable[it->name] = it->address;
251					fAbsoluteSymbols.insert(it->name);
252					break;
253				default:
254					throwf("non-regular symbol binding not supported for %s in %s", it->name, layout.getFilePath());
255					break;
256			}
257			//fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
258		}
259	}
260	else {
261		if ( fDynamicInfo->tocoff() == 0 ) {
262			const macho_nlist<P>* start = &fSymbolTable[fDynamicInfo->iextdefsym()];
263			const macho_nlist<P>* end = &start[fDynamicInfo->nextdefsym()];
264			fHashTable.reserve(fDynamicInfo->nextdefsym()); // set initial bucket count
265			for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
266				const char* name = &fStrings[sym->n_strx()];
267				fHashTable[name] = runtimeAddressFromNList(sym);
268				//fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
269			}
270		}
271		else {
272			int32_t count = fDynamicInfo->ntoc();
273			fHashTable.reserve(count); // set initial bucket count
274			const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)&this->fLinkEditBase[fDynamicInfo->tocoff()];
275			for (int32_t i = 0; i < count; ++i) {
276				const uint32_t index = E::get32(toc[i].symbol_index);
277				const macho_nlist<P>* sym = &fSymbolTable[index];
278				const char* name = &fStrings[sym->n_strx()];
279				fHashTable[name] = runtimeAddressFromNList(sym);
280				//fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
281			}
282		}
283	}
284}
285
286template <> uint8_t	Binder<x86>::pointerRelocSize()   { return 2; }
287template <> uint8_t	Binder<x86_64>::pointerRelocSize() { return 3; }
288template <> uint8_t	Binder<arm>::pointerRelocSize() { return 2; }
289
290template <> uint8_t	Binder<x86>::pointerRelocType()   { return GENERIC_RELOC_VANILLA; }
291template <> uint8_t	Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
292template <> uint8_t	Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
293
294
295template <typename A>
296const char* Binder<A>::getDylibID() const
297{
298	if ( fDylibID != NULL )
299		return fDylibID->name();
300	else
301		return NULL;
302}
303
304template <typename A>
305const char* Binder<A>::parentUmbrella()
306{
307	if ( fParentUmbrella != NULL )
308		return fParentUmbrella->name();
309	else
310		return NULL;
311}
312
313
314template <typename A>
315bool Binder<A>::isPublicLocation(const char* pth)
316{
317	// /usr/lib is a public location
318	if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
319		return true;
320
321	// /System/Library/Frameworks/ is a public location
322	if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
323		const char* frameworkDot = strchr(&pth[27], '.');
324		// but only top level framework
325		// /System/Library/Frameworks/Foo.framework/Versions/A/Foo                 ==> true
326		// /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib         ==> false
327		// /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar   ==> false
328		// /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
329		if ( frameworkDot != NULL ) {
330			int frameworkNameLen = frameworkDot - &pth[27];
331			if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
332				return true;
333		}
334	}
335
336	return false;
337}
338
339template <typename A>
340void Binder<A>::setDependentBinders(const Map& map)
341{
342	// first pass to build vector of dylibs
343	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
344	const uint32_t cmd_count = this->fHeader->ncmds();
345	const macho_load_command<P>* cmd = cmds;
346	for (uint32_t i = 0; i < cmd_count; ++i) {
347		switch (cmd->cmd()) {
348			case LC_LOAD_DYLIB:
349			case LC_LOAD_WEAK_DYLIB:
350			case LC_REEXPORT_DYLIB:
351			case LC_LOAD_UPWARD_DYLIB:
352				const char* path = ((struct macho_dylib_command<P>*)cmd)->name();
353				typename Map::const_iterator pos = map.find(path);
354				if ( pos != map.end() ) {
355					BinderAndReExportFlag entry;
356					entry.binder = pos->second;
357					entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
358					fDependentDylibs.push_back(entry);
359				}
360				else {
361					// the load command string does not match the install name of any loaded dylib
362					// this could happen if there was not a world build and some dylib changed its
363					// install path to be some symlinked path
364
365					// use realpath() and walk map looking for a realpath match
366					bool found = false;
367					char targetPath[PATH_MAX];
368					if ( realpath(path, targetPath) != NULL ) {
369						for(typename Map::const_iterator it=map.begin(); it != map.end(); ++it) {
370							char aPath[PATH_MAX];
371							if ( realpath(it->first, aPath) != NULL ) {
372								if ( strcmp(targetPath, aPath) == 0 ) {
373									BinderAndReExportFlag entry;
374									entry.binder = it->second;
375									entry.reExport = ( cmd->cmd() == LC_REEXPORT_DYLIB );
376									fDependentDylibs.push_back(entry);
377									found = true;
378									fprintf(stderr, "update_dyld_shared_cache: warning mismatched install path in %s for %s\n",
379										this->getDylibID(), path);
380									break;
381								}
382							}
383						}
384					}
385					if ( ! found ) {
386						if ( cmd->cmd() == LC_LOAD_WEAK_DYLIB ) {
387							BinderAndReExportFlag entry;
388							entry.binder = NULL;
389							entry.reExport = false;
390							fDependentDylibs.push_back(entry);
391							break;
392						}
393						else {
394							throwf("in %s can't find dylib %s", this->getDylibID(), path);
395						}
396					}
397				}
398				break;
399		}
400		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
401	}
402	// handle pre-10.5 re-exports
403	if ( (this->fHeader->flags() & MH_NO_REEXPORTED_DYLIBS) == 0 ) {
404		cmd = cmds;
405		// LC_SUB_LIBRARY means re-export one with matching leaf name
406		const char* dylibBaseName;
407		const char* frameworkLeafName;
408		for (uint32_t i = 0; i < cmd_count; ++i) {
409			switch ( cmd->cmd() ) {
410				case LC_SUB_LIBRARY:
411					dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
412					for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
413						const char* dylibName = it->binder->getDylibID();
414						const char* lastSlash = strrchr(dylibName, '/');
415						const char* leafStart = &lastSlash[1];
416						if ( lastSlash == NULL )
417							leafStart = dylibName;
418						const char* firstDot = strchr(leafStart, '.');
419						int len = strlen(leafStart);
420						if ( firstDot != NULL )
421							len = firstDot - leafStart;
422						if ( strncmp(leafStart, dylibBaseName, len) == 0 )
423							it->reExport = true;
424					}
425					break;
426				case LC_SUB_UMBRELLA:
427					frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
428					for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
429						const char* dylibName = it->binder->getDylibID();
430						const char* lastSlash = strrchr(dylibName, '/');
431						if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
432							it->reExport = true;
433					}
434					break;
435			}
436			cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
437		}
438		// ask dependents if they re-export through me
439		const char* thisName = this->getDylibID();
440		if ( thisName != NULL ) {
441			const char* thisLeafName = strrchr(thisName, '/');
442			if ( thisLeafName != NULL )
443				++thisLeafName;
444			for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
445				if ( ! it->reExport ) {
446					Binder<A>* dep = it->binder;
447					if ( dep != NULL ) {
448						const char* parentUmbrellaName = dep->parentUmbrella();
449						if ( parentUmbrellaName != NULL ) {
450							if ( strcmp(parentUmbrellaName, thisLeafName) == 0 )
451								it->reExport = true;
452						}
453					}
454				}
455			}
456		}
457	}
458
459}
460
461template <typename A>
462int Binder<A>::ordinalOfDependentBinder(Binder<A>* dep)
463{
464	for (int i=0; i < fDependentDylibs.size(); ++i) {
465		if ( fDependentDylibs[i].binder == dep )
466			return i+1;
467	}
468	throw "dependend dylib not found";
469}
470
471template <typename A>
472void Binder<A>::hoistPrivateRexports()
473{
474	std::vector<Binder<A>*> privateReExportedDylibs;
475	for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
476		if ( it->reExport && ! isPublicLocation(it->binder->getDylibID()) )
477			privateReExportedDylibs.push_back(it->binder);
478	}
479	if ( privateReExportedDylibs.size() != 0 ) {
480		// parse export info into vector of exports
481		const uint8_t* exportsStart = this->fLayout.getDyldInfoExports();
482		const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
483		std::vector<mach_o::trie::Entry> exports;
484		mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
485		//fprintf(stderr, "%s exports %lu symbols from trie of size %u \n", this->fLayout.getFilePath(), exports.size(), fDyldInfo->export_size());
486
487		// add re-exports for each export from an re-exported dylib
488		for(typename std::vector<Binder<A>*>::iterator it = privateReExportedDylibs.begin(); it != privateReExportedDylibs.end(); ++it) {
489			Binder<A>* binder = *it;
490			int ordinal = ordinalOfDependentBinder(binder);
491			const uint8_t* aDylibsExportsStart = binder->fLayout.getDyldInfoExports();
492			const uint8_t* aDylibsExportsEnd = &aDylibsExportsStart[binder->fDyldInfo->export_size()];
493			std::vector<mach_o::trie::Entry> aDylibsExports;
494			mach_o::trie::parseTrie(aDylibsExportsStart, aDylibsExportsEnd, aDylibsExports);
495			//fprintf(stderr, "%s re-exports %lu symbols from %s\n", this->fLayout.getFilePath(), aDylibsExports.size(), binder->getDylibID());
496			for(std::vector<mach_o::trie::Entry>::iterator eit = aDylibsExports.begin(); eit != aDylibsExports.end(); ++eit) {
497				mach_o::trie::Entry entry = *eit;
498				entry.flags |= EXPORT_SYMBOL_FLAGS_REEXPORT;
499				entry.other = ordinal;
500				entry.importName = NULL;
501				exports.push_back(entry);
502			}
503		}
504		// rebuild new combined trie
505		std::vector<uint8_t> newExportTrieBytes;
506		newExportTrieBytes.reserve(fDyldInfo->export_size());
507		mach_o::trie::makeTrie(exports, newExportTrieBytes);
508		//fprintf(stderr, "%s now exports %lu symbols from trie of size %lu\n", this->fLayout.getFilePath(), exports.size(), newExportTrieBytes.size());
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		this->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 Binder<A>::bind(std::vector<void*>& pointersInData)
523{
524	this->doSetUpDyldSection();
525	if ( fDyldInfo != NULL ) {
526		this->doBindDyldInfo(pointersInData);
527		this->doBindDyldLazyInfo(pointersInData);
528		this->hoistPrivateRexports();
529		// weak bind info is processed at launch time
530	}
531	else {
532		this->doBindExternalRelocations();
533		this->doBindIndirectSymbols();
534		this->doSetPreboundUndefines();
535	}
536}
537
538
539template <typename A>
540void Binder<A>::doSetUpDyldSection()
541{
542	// find __DATA __dyld section
543	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
544	const uint32_t cmd_count = this->fHeader->ncmds();
545	const macho_load_command<P>* cmd = cmds;
546	for (uint32_t i = 0; i < cmd_count; ++i) {
547		if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
548			const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
549			if ( strcmp(seg->segname(), "__DATA") == 0 ) {
550				const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
551				const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
552				for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
553					if ( (strcmp(sect->sectname(), "__dyld") == 0) && (sect->size() >= 2*sizeof(pint_t)) ) {
554						// set two values in __dyld section to point into dyld
555						pint_t* lazyBinder = this->mappedAddressForNewAddress(sect->addr());
556						pint_t* dyldFuncLookup = this->mappedAddressForNewAddress(sect->addr()+sizeof(pint_t));
557						A::P::setP(*lazyBinder, fDyldBaseAddress + 0x1000);
558						A::P::setP(*dyldFuncLookup, fDyldBaseAddress + 0x1008);
559					}
560				}
561			}
562		}
563		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
564	}
565}
566
567template <typename A>
568void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal,
569							int64_t addend, const char* symbolName, bool lazyPointer, bool weakImport, std::vector<void*>& pointersInData)
570{
571	//printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
572	const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
573	if ( segmentIndex > segments.size() )
574		throw "bad segment index in rebase info";
575
576	if ( libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
577		throw "dynamic lookup linkage not allowed in dyld shared cache";
578
579	if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
580		throw "linkage to main executable not allowed in dyld shared cache";
581
582	if ( libraryOrdinal < 0 )
583		throw "bad mach-o binary, special library ordinal not allowd in dyld shared cache";
584
585	if ( (unsigned)libraryOrdinal > fDependentDylibs.size() )
586		throw "bad mach-o binary, library ordinal too big";
587
588	Binder<A>* binder;
589	if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF )
590		binder = this;
591	else
592		binder = fDependentDylibs[libraryOrdinal-1].binder;
593	pint_t targetSymbolAddress;
594	bool isResolverSymbol = false;
595	bool isAbsolute = false;
596    Binder<A>* foundIn;
597	if ( weakImport && (binder == NULL) ) {
598		targetSymbolAddress = 0;
599		foundIn = NULL;
600	}
601	else {
602		if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol, &isAbsolute) )
603			throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
604	}
605
606	// don't bind lazy pointers to resolver stubs in shared cache
607	if ( lazyPointer && isResolverSymbol ) {
608        if ( foundIn != this ) {
609			// record that this dylib has a lazy pointer to a resolver function
610            foundIn->addResolverClient(this, symbolName);
611           // fprintf(stderr, "have lazy pointer to resolver %s in %s\n", symbolName, this->getDylibID());
612        }
613		return;
614    }
615
616	// do actual update
617	const MachOLayoutAbstraction::Segment& seg = segments[segmentIndex];
618	uint8_t*  mappedAddr = (uint8_t*)seg.mappedAddress() + segmentOffset;
619	pint_t*   mappedAddrP = (pint_t*)mappedAddr;
620	uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
621	int32_t svalue32new;
622	switch ( type ) {
623		case BIND_TYPE_POINTER:
624			P::setP(*mappedAddrP, targetSymbolAddress + addend);
625			break;
626
627		case BIND_TYPE_TEXT_ABSOLUTE32:
628			E::set32(*mappedAddr32, targetSymbolAddress + addend);
629			break;
630
631		case BIND_TYPE_TEXT_PCREL32:
632			svalue32new = seg.address() + segmentOffset + 4 - (targetSymbolAddress + addend);
633			E::set32(*mappedAddr32, svalue32new);
634			break;
635
636		default:
637			throw "bad bind type";
638	}
639	if ( !isAbsolute )
640		pointersInData.push_back(mappedAddr);
641}
642
643
644
645template <typename A>
646void Binder<A>::doBindDyldLazyInfo(std::vector<void*>& pointersInData)
647{
648	const uint8_t* p = &this->fLinkEditBase[fDyldInfo->lazy_bind_off()];
649	const uint8_t* end = &p[fDyldInfo->lazy_bind_size()];
650
651	uint8_t type = BIND_TYPE_POINTER;
652	uint64_t segmentOffset = 0;
653	uint8_t segmentIndex = 0;
654	const char* symbolName = NULL;
655	int libraryOrdinal = 0;
656	int64_t addend = 0;
657	bool weakImport = false;
658	while ( p < end ) {
659		uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
660		uint8_t opcode = *p & BIND_OPCODE_MASK;
661		++p;
662		switch (opcode) {
663			case BIND_OPCODE_DONE:
664				// this opcode marks the end of each lazy pointer binding
665				break;
666			case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
667				libraryOrdinal = immediate;
668				break;
669			case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
670				libraryOrdinal = read_uleb128(p, end);
671				break;
672			case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
673				// the special ordinals are negative numbers
674				if ( immediate == 0 )
675					libraryOrdinal = 0;
676				else {
677					int8_t signExtended = BIND_OPCODE_MASK | immediate;
678					libraryOrdinal = signExtended;
679				}
680				break;
681			case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
682				weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
683				symbolName = (char*)p;
684				while (*p != '\0')
685					++p;
686				++p;
687				break;
688			case BIND_OPCODE_SET_ADDEND_SLEB:
689				addend = read_sleb128(p, end);
690				break;
691			case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
692				segmentIndex = immediate;
693				segmentOffset = read_uleb128(p, end);
694				break;
695			case BIND_OPCODE_DO_BIND:
696				bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, true, weakImport, pointersInData);
697				segmentOffset += sizeof(pint_t);
698				break;
699			case BIND_OPCODE_SET_TYPE_IMM:
700			case BIND_OPCODE_ADD_ADDR_ULEB:
701			case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
702			case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
703			case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
704			default:
705				throwf("bad lazy bind opcode %d", *p);
706		}
707	}
708
709
710}
711
712template <typename A>
713void Binder<A>::doBindDyldInfo(std::vector<void*>& pointersInData)
714{
715	const uint8_t* p = &this->fLinkEditBase[fDyldInfo->bind_off()];
716	const uint8_t* end = &p[fDyldInfo->bind_size()];
717
718	uint8_t type = 0;
719	uint64_t segmentOffset = 0;
720	uint8_t segmentIndex = 0;
721	const char* symbolName = NULL;
722	int libraryOrdinal = 0;
723	int64_t addend = 0;
724	uint32_t count;
725	uint32_t skip;
726	bool weakImport = false;
727	bool done = false;
728	while ( !done && (p < end) ) {
729		uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
730		uint8_t opcode = *p & BIND_OPCODE_MASK;
731		++p;
732		switch (opcode) {
733			case BIND_OPCODE_DONE:
734				done = true;
735				break;
736			case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
737				libraryOrdinal = immediate;
738				break;
739			case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
740				libraryOrdinal = read_uleb128(p, end);
741				break;
742			case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
743				// the special ordinals are negative numbers
744				if ( immediate == 0 )
745					libraryOrdinal = 0;
746				else {
747					int8_t signExtended = BIND_OPCODE_MASK | immediate;
748					libraryOrdinal = signExtended;
749				}
750				break;
751			case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
752				weakImport = ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 );
753				symbolName = (char*)p;
754				while (*p != '\0')
755					++p;
756				++p;
757				break;
758			case BIND_OPCODE_SET_TYPE_IMM:
759				type = immediate;
760				break;
761			case BIND_OPCODE_SET_ADDEND_SLEB:
762				addend = read_sleb128(p, end);
763				break;
764			case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
765				segmentIndex = immediate;
766				segmentOffset = read_uleb128(p, end);
767				break;
768			case BIND_OPCODE_ADD_ADDR_ULEB:
769				segmentOffset += read_uleb128(p, end);
770				break;
771			case BIND_OPCODE_DO_BIND:
772				bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
773				segmentOffset += sizeof(pint_t);
774				break;
775			case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
776				bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
777				segmentOffset += read_uleb128(p, end) + sizeof(pint_t);
778				break;
779			case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
780				bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
781				segmentOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
782				break;
783			case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
784				count = read_uleb128(p, end);
785				skip = read_uleb128(p, end);
786				for (uint32_t i=0; i < count; ++i) {
787					bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, weakImport, pointersInData);
788					segmentOffset += skip + sizeof(pint_t);
789				}
790				break;
791			default:
792				throwf("bad bind opcode %d", *p);
793		}
794	}
795
796
797
798}
799
800
801template <typename A>
802void Binder<A>::doSetPreboundUndefines()
803{
804	const macho_dysymtab_command<P>* dysymtab = NULL;
805	macho_nlist<P>* symbolTable = NULL;
806
807	// get symbol table info
808	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
809	const uint32_t cmd_count = this->fHeader->ncmds();
810	const macho_load_command<P>* cmd = cmds;
811	for (uint32_t i = 0; i < cmd_count; ++i) {
812		switch (cmd->cmd()) {
813			case LC_SYMTAB:
814				{
815					const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
816					symbolTable = (macho_nlist<P>*)(&this->fLinkEditBase[symtab->symoff()]);
817				}
818				break;
819			case LC_DYSYMTAB:
820				dysymtab = (macho_dysymtab_command<P>*)cmd;
821				break;
822		}
823		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
824	}
825
826	// walk all undefines and set their prebound n_value
827	macho_nlist<P>* const lastUndefine = &symbolTable[dysymtab->iundefsym()+dysymtab->nundefsym()];
828	for (macho_nlist<P>* entry = &symbolTable[dysymtab->iundefsym()]; entry < lastUndefine; ++entry) {
829		if ( entry->n_type() & N_EXT ) {
830			//fprintf(stderr, "doSetPreboundUndefines: r_sym=%s, pbaddr=0x%08X, in %s\n",
831			//	&fStrings[entry->n_strx()], pbaddr, this->getDylibID());
832			pint_t pbaddr = this->resolveUndefined(entry);
833			entry->set_n_value(pbaddr);
834		}
835	}
836}
837
838
839template <typename A>
840void Binder<A>::doBindExternalRelocations()
841{
842	// get where reloc addresses start
843	// these address are always relative to first writable segment because they are in cache which always
844	// has writable segments far from read-only segments
845	pint_t firstWritableSegmentBaseAddress = 0;
846	const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
847	for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
848		const MachOLayoutAbstraction::Segment& seg = *it;
849		if ( seg.writable() ) {
850			firstWritableSegmentBaseAddress = seg.newAddress();
851			break;
852		}
853	}
854
855	// loop through all external relocation records and bind each
856	const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&this->fLinkEditBase[fDynamicInfo->extreloff()]);
857	const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicInfo->nextrel()];
858	for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
859		if ( reloc->r_length() != pointerRelocSize() )
860			throw "bad external relocation length";
861		if ( reloc->r_type() != pointerRelocType() )
862			throw "unknown external relocation type";
863		if ( reloc->r_pcrel() )
864			throw "r_pcrel external relocaiton not supported";
865
866		const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
867		pint_t* location;
868		try {
869			location = this->mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
870		}
871		catch (const char* msg) {
872			throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
873		}
874		pint_t addend =  P::getP(*location);
875		if ( fOriginallyPrebound ) {
876			// in a prebound binary, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
877			// so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
878			// if mach-o relocation structs had an "addend" field this complication would not be necessary.
879			addend -= undefinedSymbol->n_value();
880			// To further complicate things, if this is defined symbol, then its n_value has already been adjust to the
881			// new base address, so we need to back off the slide too..
882			if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
883				addend += this->getSlideForNewAddress(undefinedSymbol->n_value());
884			}
885		}
886		pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
887		//fprintf(stderr, "external reloc: r_address=0x%08X, r_sym=%s, symAddr=0x%08llX, addend=0x%08llX in %s\n",
888		//		reloc->r_address(), &fStrings[undefinedSymbol->n_strx()], (uint64_t)symbolAddr, (uint64_t)addend, this->getDylibID());
889		P::setP(*location, symbolAddr + addend);
890	}
891}
892
893
894// most architectures use pure code, unmodifiable stubs
895template <typename A>
896void Binder<A>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
897{
898	// do nothing
899}
900
901// x86 supports fast stubs
902template <>
903void Binder<x86>::bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value)
904{
905	// if the stub is not 5-bytes, it is an old slow stub
906	if ( elementSize == 5 ) {
907		uint32_t rel32 = value - (vmlocation + 5);
908		location[0] = 0xE9; // JMP rel32
909		location[1] = rel32 & 0xFF;
910		location[2] = (rel32 >> 8) & 0xFF;
911		location[3] = (rel32 >> 16) & 0xFF;
912		location[4] = (rel32 >> 24) & 0xFF;
913	}
914}
915
916template <typename A>
917void Binder<A>::doBindIndirectSymbols()
918{
919	const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
920	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
921	const uint32_t cmd_count = this->fHeader->ncmds();
922	const macho_load_command<P>* cmd = cmds;
923	//fprintf(stderr, "doBindIndirectSymbols() %s\n", this->fLayout.getFilePath());
924	for (uint32_t i = 0; i < cmd_count; ++i) {
925		if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
926			const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
927			const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
928			const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
929			for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
930				uint8_t elementSize = 0;
931				uint8_t sectionType = sect->flags() & SECTION_TYPE;
932				switch ( sectionType ) {
933					case S_SYMBOL_STUBS:
934						elementSize = sect->reserved2();
935						break;
936					case S_NON_LAZY_SYMBOL_POINTERS:
937					case S_LAZY_SYMBOL_POINTERS:
938						elementSize = sizeof(pint_t);
939						break;
940				}
941				if ( elementSize != 0 ) {
942					uint32_t elementCount = sect->size() / elementSize;
943					const uint32_t indirectTableOffset = sect->reserved1();
944					uint8_t* location = NULL;
945					if ( sect->size() != 0 )
946						location = (uint8_t*)this->mappedAddressForNewAddress(sect->addr());
947					pint_t vmlocation = sect->addr();
948					for (uint32_t j=0; j < elementCount; ++j, location += elementSize, vmlocation += elementSize) {
949						uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
950						switch ( symbolIndex ) {
951							case INDIRECT_SYMBOL_ABS:
952							case INDIRECT_SYMBOL_LOCAL:
953								break;
954							default:
955								const macho_nlist<P>* undefinedSymbol = &fSymbolTable[symbolIndex];
956								//fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
957								pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
958								switch ( sectionType ) {
959									case S_NON_LAZY_SYMBOL_POINTERS:
960									case S_LAZY_SYMBOL_POINTERS:
961										P::setP(*((pint_t*)location), symbolAddr);
962										break;
963									case S_SYMBOL_STUBS:
964										this->bindStub(elementSize, location, vmlocation, symbolAddr);
965											break;
966								}
967								break;
968						}
969					}
970				}
971			}
972		}
973		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
974	}
975}
976
977
978
979
980template <typename A>
981typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefinedSymbol)
982{
983	if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
984		if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
985			// is a multi-module private_extern internal reference that the linker did not optimize away
986			return runtimeAddressFromNList(undefinedSymbol);
987		}
988		if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
989			// is a weak definition, we should prebind to this one in the same linkage unit
990			return runtimeAddressFromNList(undefinedSymbol);
991		}
992	}
993	const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
994	if ( (this->fHeader->flags() & MH_TWOLEVEL) == 0 ) {
995		// flat namespace binding
996		throw "flat namespace not supported";
997	}
998	else {
999		uint8_t ordinal = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc());
1000		Binder<A>* binder = NULL;
1001		switch ( ordinal ) {
1002			case EXECUTABLE_ORDINAL:
1003			case DYNAMIC_LOOKUP_ORDINAL:
1004				throw "magic ordineal not supported";
1005			case SELF_LIBRARY_ORDINAL:
1006				binder = this;
1007				break;
1008			default:
1009				if ( ordinal > fDependentDylibs.size() )
1010					throw "two-level ordinal out of range";
1011				binder = fDependentDylibs[ordinal-1].binder;
1012		}
1013		pint_t addr;
1014		bool isResolver;
1015		bool isAbsolute;
1016        Binder<A>* foundIn;
1017		if ( ! binder->findExportedSymbolAddress(symbolName, &addr, &foundIn, &isResolver, &isAbsolute) )
1018			throwf("could not resolve undefined symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
1019		return addr;
1020	}
1021}
1022
1023template <typename A>
1024bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol, bool* isAbsolute)
1025{
1026    *foundIn = NULL;
1027	// since re-export chains can be any length, re-exports cannot be resolved in setDependencies()
1028	// instead we lazily, recursively update
1029	if ( !fReExportedSymbolsResolved ) {
1030
1031		// update fHashTable with any individual symbol re-exports
1032		for (typename std::vector<SymbolReExport>::iterator it=fReExportedSymbols.begin(); it != fReExportedSymbols.end(); ++it) {
1033			pint_t targetSymbolAddress;
1034			bool isResolver;
1035			bool isAb;
1036
1037			if ( it->dylibOrdinal <= 0 )
1038				throw "bad mach-o binary, special library ordinal not allowed in re-exported symbols in dyld shared cache";
1039
1040			Binder<A>* binder = fDependentDylibs[it->dylibOrdinal-1].binder;
1041
1042			if ( ! binder->findExportedSymbolAddress(it->importName, &targetSymbolAddress, foundIn, &isResolver, &isAb) )
1043				throwf("could not bind symbol %s in %s expected in %s", it->importName, this->getDylibID(), binder->getDylibID());
1044
1045			if ( isResolver )
1046				fSymbolResolvers.insert(name);
1047
1048			fHashTable[it->exportName] = targetSymbolAddress;
1049		}
1050		// mark as done
1051		fReExportedSymbolsResolved = true;
1052	}
1053
1054	*isResolverSymbol = false;
1055	if ( !fSymbolResolvers.empty() && fSymbolResolvers.count(name) ) {
1056		// lazy pointers should be left unbound, rather than bind to resolver stub
1057		*isResolverSymbol = true;
1058	}
1059
1060	// search this dylib
1061	typename NameToAddrMap::iterator pos = fHashTable.find(name);
1062	if ( pos != fHashTable.end() ) {
1063		*result = pos->second;
1064		//fprintf(stderr, "findExportedSymbolAddress(%s) => 0x%08llX in %s\n", name, (uint64_t)*result, this->getDylibID());
1065        *foundIn = this;
1066		*isAbsolute = (fAbsoluteSymbols.count(name) != 0);
1067		return true;
1068	}
1069
1070	// search re-exported dylibs
1071	for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
1072		if ( it->reExport ) {
1073			if ( it->binder->findExportedSymbolAddress(name, result, foundIn, isResolverSymbol, isAbsolute) )
1074				return true;
1075		}
1076	}
1077	//fprintf(stderr, "findExportedSymbolAddress(%s) => not found in %s\n", name, this->getDylibID());
1078	return false;
1079}
1080
1081// record which dylibs will be using this dylibs lazy pointer
1082template <typename A>
1083void Binder<A>::addResolverClient(Binder<A>* clientDylib, const char* symbolName)
1084{
1085    ClientAndSymbol x;
1086    x.client = clientDylib;
1087    x.symbolName = symbolName;
1088    fClientAndSymbols.push_back(x);
1089}
1090
1091
1092template <typename A>
1093typename A::P::uint_t Binder<A>::findLazyPointerFor(const char* symbolName)
1094{
1095	static const bool log = false;
1096
1097	// first check cache
1098	typename NameToAddrMap::iterator pos = fResolverLazyPointers.find(symbolName);
1099	if ( pos != fResolverLazyPointers.end() ) {
1100		if ( log ) fprintf(stderr, "found cached shared lazy pointer at 0x%llX for %s in %s\n", (uint64_t)(pos->second), symbolName, this->getDylibID());
1101		return pos->second;
1102	}
1103
1104	// do slow lookup in lazy pointer section
1105	const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
1106	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
1107	const uint32_t cmd_count = this->fHeader->ncmds();
1108	const macho_load_command<P>* cmd = cmds;
1109	for (uint32_t i = 0; i < cmd_count; ++i) {
1110		if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1111			const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
1112			const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
1113			const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
1114			for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1115				uint8_t sectionType = sect->flags() & SECTION_TYPE;
1116				if ( sectionType == S_LAZY_SYMBOL_POINTERS) {
1117					uint32_t elementCount = sect->size() / sizeof(pint_t);
1118					const uint32_t indirectTableOffset = sect->reserved1();
1119					pint_t vmlocation = sect->addr();
1120					for (uint32_t j=0; j < elementCount; ++j, vmlocation += sizeof(pint_t)) {
1121						uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
1122						switch ( symbolIndex ) {
1123							case INDIRECT_SYMBOL_ABS:
1124							case INDIRECT_SYMBOL_LOCAL:
1125								break;
1126							default:
1127								const macho_nlist<P>* aSymbol = &fSymbolTable[symbolIndex];
1128								const char* aName = &fStrings[aSymbol->n_strx()];
1129								//fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
1130								if ( strcmp(aName, symbolName) == 0 ) {
1131									fResolverLazyPointers[symbolName] = vmlocation;
1132									if ( log ) fprintf(stderr, "found slow-path shared lazy pointer at 0x%llX for %s in %s\n", (uint64_t)vmlocation, symbolName, this->getDylibID());
1133									return vmlocation;
1134								}
1135								break;
1136						}
1137					}
1138				}
1139			}
1140		}
1141		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1142	}
1143
1144	if ( log ) fprintf(stderr, "NOT found shared lazy pointer for %s in %s\n", symbolName, this->getDylibID());
1145    return 0;
1146}
1147
1148// called after all binding is done to optimize lazy pointers
1149template <typename A>
1150void Binder<A>::optimize()
1151{
1152    for (typename std::vector<ClientAndSymbol>::iterator it = fClientAndSymbols.begin(); it != fClientAndSymbols.end(); ++it) {
1153        pint_t lpVMAddr = findLazyPointerFor(it->symbolName);
1154        if ( lpVMAddr != 0 ) {
1155            it->client->optimizeStub(it->symbolName, lpVMAddr);
1156        }
1157        else {
1158            fprintf(stderr, "not able to optimize lazy pointer for %s in %s\n", it->symbolName, it->client->getDylibID());
1159        }
1160
1161    }
1162}
1163
1164template <>
1165void Binder<arm>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr)
1166{
1167    if ( stubSize != 16 ) {
1168        fprintf(stderr, "could not optimize ARM stub to resolver function in %s because it is wrong size\n", this->getDylibID());
1169        return;
1170    }
1171    uint32_t* instructions = (uint32_t*)stubMappedAddress;
1172    if (   (E::get32(instructions[0]) != 0xe59fc004)
1173        || (E::get32(instructions[1]) != 0xe08fc00c)
1174        || (E::get32(instructions[2]) != 0xe59cf000)
1175        ) {
1176        fprintf(stderr, "could not optimize ARM stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
1177        return;
1178    }
1179    // last .long in stub is:  lazyPtr - (stub+8)
1180    // alter to point to more optimal lazy pointer
1181    uint32_t betterOffset = lpVMAddr  - (stubVMAddress + 12);
1182    E::set32(instructions[3], betterOffset);
1183}
1184
1185
1186template <>
1187void Binder<x86_64>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr)
1188{
1189    if ( stubSize != 6 ) {
1190        fprintf(stderr, "could not optimize x86_64 stub to resolver function in %s because it is wrong size\n", this->getDylibID());
1191        return;
1192    }
1193    if ( (stubMappedAddress[0] != 0xFF) || (stubMappedAddress[1] != 0x25) ) {
1194        fprintf(stderr, "could not optimize stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
1195        return;
1196    }
1197    // last four bytes in stub is RIP relative offset to lazy pointer
1198    // alter to point to more optimal lazy pointer
1199    uint32_t betterOffset = lpVMAddr  - (stubVMAddress + 6);
1200    E::set32(*((uint32_t*)(&stubMappedAddress[2])), betterOffset);
1201}
1202
1203template <typename A>
1204void Binder<A>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddress)
1205{
1206    // Remaining architectures are not optimized
1207    //fprintf(stderr, "optimize stub at %p in %s to use lazyPointer at 0x%llX\n", stubMappedAddress, this->getDylibID(), (uint64_t)lpVMAddress);
1208}
1209
1210// search for stub in this image that call target symbol name and then optimize its lazy pointer
1211template <typename A>
1212void Binder<A>::optimizeStub(const char* stubName, pint_t lpVMAddr)
1213{
1214	// find named stub
1215	const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
1216	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
1217	const uint32_t cmd_count = this->fHeader->ncmds();
1218	const macho_load_command<P>* cmd = cmds;
1219	for (uint32_t i = 0; i < cmd_count; ++i) {
1220		if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
1221			macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
1222			macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
1223			macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
1224			for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
1225				if ( ((sect->flags() & SECTION_TYPE) == S_SYMBOL_STUBS) && (sect->size() != 0) ) {
1226					pint_t stubsVMStart = sect->addr();
1227					uint8_t* stubsMappingStart = (uint8_t*)this->mappedAddressForNewAddress(stubsVMStart);
1228					const uint32_t indirectTableOffset = sect->reserved1();
1229					const uint32_t stubSize = sect->reserved2();
1230					uint32_t elementCount = sect->size() / stubSize;
1231                    pint_t stubVMAddr = stubsVMStart;
1232                    uint8_t* stubMappedAddr = stubsMappingStart;
1233					for (uint32_t j=0; j < elementCount; ++j, stubMappedAddr += stubSize, stubVMAddr += stubSize) {
1234						uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
1235						switch ( symbolIndex ) {
1236							case INDIRECT_SYMBOL_ABS:
1237							case INDIRECT_SYMBOL_LOCAL:
1238								break;
1239							default:
1240                                {
1241                                   const macho_nlist<P>* sym = &this->fSymbolTable[symbolIndex];
1242                                   const char* symName = &fStrings[sym->n_strx()];
1243                                    if ( strcmp(symName, stubName) == 0 )
1244                                        this->optimizeStub(stubMappedAddr, stubVMAddr, stubSize, lpVMAddr);
1245                                }
1246 								break;
1247						}
1248					}
1249				}
1250			}
1251		}
1252		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
1253	}
1254}
1255
1256
1257#endif // __MACHO_BINDER__
1258
1259
1260
1261
1262