1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008 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
26#include <string.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/fcntl.h>
31#include <sys/stat.h>
32#include <sys/mman.h>
33#include <sys/param.h>
34#include <mach/mach.h>
35#include <mach/thread_status.h>
36#include <mach-o/loader.h>
37
38#include "ImageLoaderMachOCompressed.h"
39#include "mach-o/dyld_images.h"
40
41#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
42	#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE			0x02
43#endif
44
45// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
46#if __LP64__
47	#define RELOC_SIZE 3
48	#define LC_SEGMENT_COMMAND		LC_SEGMENT_64
49	#define LC_ROUTINES_COMMAND		LC_ROUTINES_64
50	struct macho_segment_command	: public segment_command_64  {};
51	struct macho_section			: public section_64  {};
52	struct macho_routines_command	: public routines_command_64  {};
53#else
54	#define RELOC_SIZE 2
55	#define LC_SEGMENT_COMMAND		LC_SEGMENT
56	#define LC_ROUTINES_COMMAND		LC_ROUTINES
57	struct macho_segment_command	: public segment_command {};
58	struct macho_section			: public section  {};
59	struct macho_routines_command	: public routines_command  {};
60#endif
61
62
63static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end)
64{
65	uint64_t result = 0;
66	int		 bit = 0;
67	do {
68		if (p == end)
69			dyld::throwf("malformed uleb128");
70
71		uint64_t slice = *p & 0x7f;
72
73		if (bit > 63)
74			dyld::throwf("uleb128 too big for uint64, bit=%d, result=0x%0llX", bit, result);
75		else {
76			result |= (slice << bit);
77			bit += 7;
78		}
79	} while (*p++ & 0x80);
80	return result;
81}
82
83
84static intptr_t read_sleb128(const uint8_t*& p, const uint8_t* end)
85{
86	int64_t result = 0;
87	int bit = 0;
88	uint8_t byte;
89	do {
90		if (p == end)
91			throw "malformed sleb128";
92		byte = *p++;
93		result |= (((int64_t)(byte & 0x7f)) << bit);
94		bit += 7;
95	} while (byte & 0x80);
96	// sign extend negative numbers
97	if ( (byte & 0x40) != 0 )
98		result |= (-1LL) << bit;
99	return result;
100}
101
102
103// create image for main executable
104ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path,
105																		unsigned int segCount, unsigned int libCount, const LinkContext& context)
106{
107	ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
108
109	// set slide for PIE programs
110	image->setSlide(slide);
111
112	// for PIE record end of program, to know where to start loading dylibs
113	if ( slide != 0 )
114		fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
115
116	image->instantiateFinish(context);
117	image->setMapped(context);
118
119	if ( context.verboseMapping ) {
120		dyld::log("dyld: Main executable mapped %s\n", path);
121		for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
122			const char* name = image->segName(i);
123			if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0)  )
124				dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
125			else
126				dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
127		}
128	}
129
130	return image;
131}
132
133// create image by mapping in a mach-o file
134ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(const char* path, int fd, const uint8_t* fileData,
135															uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info,
136															unsigned int segCount, unsigned int libCount,
137															const struct linkedit_data_command* codeSigCmd, const LinkContext& context)
138{
139	ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart((macho_header*)fileData, path, segCount, libCount);
140
141	try {
142		// record info about file
143		image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
144
145		// if this image is code signed, let kernel validate signature before mapping any pages from image
146		image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context);
147
148		// mmap segments
149		image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
150
151		// probe to see if code signed correctly
152		image->crashIfInvalidCodeSignature();
153
154		// finish construction
155		image->instantiateFinish(context);
156
157		// if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
158		const char* installName = image->getInstallPath();
159		if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
160			image->setPathUnowned(installName);
161#if __MAC_OS_X_VERSION_MIN_REQUIRED
162		// <rdar://problem/6563887> app crashes when libSystem cannot be found
163		else if ( (installName != NULL) && (strcmp(path, "/usr/lib/libgcc_s.1.dylib") == 0) && (strcmp(installName, "/usr/lib/libSystem.B.dylib") == 0) )
164			image->setPathUnowned("/usr/lib/libSystem.B.dylib");
165#endif
166		else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) {
167			// rdar://problem/10733082 Fix up @rpath based paths during introspection
168			// rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
169			char realPath[MAXPATHLEN];
170			if ( fcntl(fd, F_GETPATH, realPath) == 0 )
171				image->setPaths(path, realPath);
172			else
173				image->setPath(path);
174		}
175		else
176			image->setPath(path);
177
178		// make sure path is stable before recording in dyld_all_image_infos
179		image->setMapped(context);
180
181		// pre-fetch content of __DATA and __LINKEDIT segment for faster launches
182		// don't do this on prebound images or if prefetching is disabled
183        if ( !context.preFetchDisabled && !image->isPrebindable()) {
184			image->preFetchDATA(fd, offsetInFat, context);
185			image->markSequentialLINKEDIT(context);
186		}
187	}
188	catch (...) {
189		// ImageLoader::setMapped() can throw an exception to block loading of image
190		// <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
191		delete image;
192		throw;
193	}
194
195	return image;
196}
197
198// create image by using cached mach-o file
199ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(const macho_header* mh, const char* path, long slide,
200																		const struct stat& info, unsigned int segCount,
201																		unsigned int libCount, const LinkContext& context)
202{
203	ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
204	try {
205		// record info about file
206		image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
207
208		// remember this is from shared cache and cannot be unloaded
209		image->fInSharedCache = true;
210		image->setNeverUnload();
211		image->setSlide(slide);
212
213		// segments already mapped in cache
214		if ( context.verboseMapping ) {
215			dyld::log("dyld: Using shared cached for %s\n", path);
216			for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
217				dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
218			}
219		}
220
221		image->instantiateFinish(context);
222		image->setMapped(context);
223	}
224	catch (...) {
225		// ImageLoader::setMapped() can throw an exception to block loading of image
226		// <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
227		delete image;
228		throw;
229	}
230
231	return image;
232}
233
234// create image by copying an in-memory mach-o file
235ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len,
236															unsigned int segCount, unsigned int libCount, const LinkContext& context)
237{
238	ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, moduleName, segCount, libCount);
239	try {
240		// map segments
241		if ( mh->filetype == MH_EXECUTE )
242			throw "can't load another MH_EXECUTE";
243
244		// vmcopy segments
245		image->mapSegments((const void*)mh, len, context);
246
247		// for compatibility, never unload dylibs loaded from memory
248		image->setNeverUnload();
249
250		// bundle loads need path copied
251		if ( moduleName != NULL )
252			image->setPath(moduleName);
253
254		image->instantiateFinish(context);
255		image->setMapped(context);
256	}
257	catch (...) {
258		// ImageLoader::setMapped() can throw an exception to block loading of image
259		// <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
260		delete image;
261		throw;
262	}
263
264	return image;
265}
266
267
268ImageLoaderMachOCompressed::ImageLoaderMachOCompressed(const macho_header* mh, const char* path, unsigned int segCount,
269																		uint32_t segOffsets[], unsigned int libCount)
270 : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fDyldInfo(NULL)
271{
272}
273
274ImageLoaderMachOCompressed::~ImageLoaderMachOCompressed()
275{
276	// don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
277	destroy();
278}
279
280
281
282// construct ImageLoaderMachOCompressed using "placement new" with SegmentMachO objects array at end
283ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateStart(const macho_header* mh, const char* path,
284																			unsigned int segCount, unsigned int libCount)
285{
286	size_t size = sizeof(ImageLoaderMachOCompressed) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
287	ImageLoaderMachOCompressed* allocatedSpace = static_cast<ImageLoaderMachOCompressed*>(malloc(size));
288	if ( allocatedSpace == NULL )
289		throw "malloc failed";
290	uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOCompressed)));
291	bzero(&segOffsets[segCount], libCount*sizeof(void*));	// zero out lib array
292	return new (allocatedSpace) ImageLoaderMachOCompressed(mh, path, segCount, segOffsets, libCount);
293}
294
295
296// common code to finish initializing object
297void ImageLoaderMachOCompressed::instantiateFinish(const LinkContext& context)
298{
299	// now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
300	this->parseLoadCmds();
301}
302
303uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
304{
305	return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed)));
306}
307
308
309ImageLoader* ImageLoaderMachOCompressed::libImage(unsigned int libIndex) const
310{
311	const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
312	// mask off low bits
313	return (ImageLoader*)(images[libIndex] & (-4));
314}
315
316bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
317{
318	const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
319	// re-export flag is low bit
320	return ((images[libIndex] & 1) != 0);
321}
322
323bool ImageLoaderMachOCompressed::libIsUpward(unsigned int libIndex) const
324{
325	const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
326	// re-export flag is second bit
327	return ((images[libIndex] & 2) != 0);
328}
329
330
331void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward)
332{
333	uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
334	uintptr_t value = (uintptr_t)image;
335	if ( reExported )
336		value |= 1;
337	if ( upward )
338		value |= 2;
339	images[libIndex] = value;
340}
341
342
343void ImageLoaderMachOCompressed::markFreeLINKEDIT(const LinkContext& context)
344{
345	// mark that we are done with rebase and bind info
346	markLINKEDIT(context, MADV_FREE);
347}
348
349void ImageLoaderMachOCompressed::markSequentialLINKEDIT(const LinkContext& context)
350{
351	// mark the rebase and bind info and using sequential access
352	markLINKEDIT(context, MADV_SEQUENTIAL);
353}
354
355void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int advise)
356{
357	// if not loaded at preferred address, mark rebase info
358	uintptr_t start = 0;
359	if ( (fSlide != 0) && (fDyldInfo->rebase_size != 0) )
360		start = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off;
361	else if ( fDyldInfo->bind_off != 0 )
362		start = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off;
363	else
364		return; // no binding info to prefetch
365
366	// end is at end of bind info
367	uintptr_t end = 0;
368	if ( fDyldInfo->bind_off != 0 )
369		end = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off + fDyldInfo->bind_size;
370	else if ( fDyldInfo->rebase_off != 0 )
371		end = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off + fDyldInfo->rebase_size;
372	else
373		return;
374
375
376	// round to whole pages
377	start = dyld_page_trunc(start);
378	end = dyld_page_round(end);
379
380	// do nothing if only one page of rebase/bind info
381	if ( (end-start) <= dyld_page_size )
382		return;
383
384	// tell kernel about our access to these pages
385	madvise((void*)start, end-start, advise);
386	if ( context.verboseMapping ) {
387		const char* adstr = "sequential";
388		if ( advise == MADV_FREE )
389			adstr = "free";
390		dyld::log("%18s %s 0x%0lX -> 0x%0lX for %s\n", "__LINKEDIT", adstr, start, end-1, this->getPath());
391	}
392}
393
394
395
396void ImageLoaderMachOCompressed::rebaseAt(const LinkContext& context, uintptr_t addr, uintptr_t slide, uint8_t type)
397{
398	if ( context.verboseRebase ) {
399		dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)addr, slide);
400	}
401	//dyld::log("0x%08lX type=%d\n", addr, type);
402	uintptr_t* locationToFix = (uintptr_t*)addr;
403	switch (type) {
404		case REBASE_TYPE_POINTER:
405			*locationToFix += slide;
406			break;
407		case REBASE_TYPE_TEXT_ABSOLUTE32:
408			*locationToFix += slide;
409			break;
410		default:
411			dyld::throwf("bad rebase type %d", type);
412	}
413}
414
415void ImageLoaderMachOCompressed::throwBadRebaseAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex,
416										const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
417{
418	dyld::throwf("malformed rebase opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
419		(intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex),
420		segActualLoadAddress(segmentIndex), segmentEndAddress);
421}
422
423void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
424{
425	CRSetCrashLogMessage2(this->getPath());
426	const uintptr_t slide = this->fSlide;
427	const uint8_t* const start = fLinkEditBase + fDyldInfo->rebase_off;
428	const uint8_t* const end = &start[fDyldInfo->rebase_size];
429	const uint8_t* p = start;
430
431	try {
432		uint8_t type = 0;
433		int segmentIndex = 0;
434		uintptr_t address = segActualLoadAddress(0);
435		uintptr_t segmentEndAddress = segActualEndAddress(0);
436		uintptr_t count;
437		uintptr_t skip;
438		bool done = false;
439		while ( !done && (p < end) ) {
440			uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
441			uint8_t opcode = *p & REBASE_OPCODE_MASK;
442			++p;
443			switch (opcode) {
444				case REBASE_OPCODE_DONE:
445					done = true;
446					break;
447				case REBASE_OPCODE_SET_TYPE_IMM:
448					type = immediate;
449					break;
450				case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
451					segmentIndex = immediate;
452					if ( segmentIndex >= fSegmentsCount )
453						dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
454								segmentIndex, fSegmentsCount-1);
455					address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
456					segmentEndAddress = segActualEndAddress(segmentIndex);
457					break;
458				case REBASE_OPCODE_ADD_ADDR_ULEB:
459					address += read_uleb128(p, end);
460					break;
461				case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
462					address += immediate*sizeof(uintptr_t);
463					break;
464				case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
465					for (int i=0; i < immediate; ++i) {
466						if ( address >= segmentEndAddress )
467							throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
468						rebaseAt(context, address, slide, type);
469						address += sizeof(uintptr_t);
470					}
471					fgTotalRebaseFixups += immediate;
472					break;
473				case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
474					count = read_uleb128(p, end);
475					for (uint32_t i=0; i < count; ++i) {
476						if ( address >= segmentEndAddress )
477							throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
478						rebaseAt(context, address, slide, type);
479						address += sizeof(uintptr_t);
480					}
481					fgTotalRebaseFixups += count;
482					break;
483				case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
484					if ( address >= segmentEndAddress )
485						throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
486					rebaseAt(context, address, slide, type);
487					address += read_uleb128(p, end) + sizeof(uintptr_t);
488					++fgTotalRebaseFixups;
489					break;
490				case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
491					count = read_uleb128(p, end);
492					skip = read_uleb128(p, end);
493					for (uint32_t i=0; i < count; ++i) {
494						if ( address >= segmentEndAddress )
495							throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
496						rebaseAt(context, address, slide, type);
497						address += skip + sizeof(uintptr_t);
498					}
499					fgTotalRebaseFixups += count;
500					break;
501				default:
502					dyld::throwf("bad rebase opcode %d", *p);
503			}
504		}
505	}
506	catch (const char* msg) {
507		const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
508		free((void*)msg);
509		throw newMsg;
510	}
511	CRSetCrashLogMessage2(NULL);
512}
513
514//
515// This function is the hotspot of symbol lookup.  It was pulled out of findExportedSymbol()
516// to enable it to be re-written in assembler if needed.
517//
518const uint8_t* ImageLoaderMachOCompressed::trieWalk(const uint8_t* start, const uint8_t* end, const char* s)
519{
520	const uint8_t* p = start;
521	while ( p != NULL ) {
522		uintptr_t terminalSize = *p++;
523		if ( terminalSize > 127 ) {
524			// except for re-export-with-rename, all terminal sizes fit in one byte
525			--p;
526			terminalSize = read_uleb128(p, end);
527		}
528		if ( (*s == '\0') && (terminalSize != 0) ) {
529			//dyld::log("trieWalk(%p) returning %p\n", start, p);
530			return p;
531		}
532		const uint8_t* children = p + terminalSize;
533		//dyld::log("trieWalk(%p) sym=%s, terminalSize=%d, children=%p\n", start, s, terminalSize, children);
534		uint8_t childrenRemaining = *children++;
535		p = children;
536		uintptr_t nodeOffset = 0;
537		for (; childrenRemaining > 0; --childrenRemaining) {
538			const char* ss = s;
539			//dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p);
540			bool wrongEdge = false;
541			// scan whole edge to get to next edge
542			// if edge is longer than target symbol name, don't read past end of symbol name
543			char c = *p;
544			while ( c != '\0' ) {
545				if ( !wrongEdge ) {
546					if ( c != *ss )
547						wrongEdge = true;
548					++ss;
549				}
550				++p;
551				c = *p;
552			}
553			if ( wrongEdge ) {
554				// advance to next child
555				++p; // skip over zero terminator
556				// skip over uleb128 until last byte is found
557				while ( (*p & 0x80) != 0 )
558					++p;
559				++p; // skil over last byte of uleb128
560			}
561			else {
562 				// the symbol so far matches this edge (child)
563				// so advance to the child's node
564				++p;
565				nodeOffset = read_uleb128(p, end);
566				s = ss;
567				//dyld::log("trieWalk() found matching edge advancing to node 0x%x\n", nodeOffset);
568				break;
569			}
570		}
571		if ( nodeOffset != 0 )
572			p = &start[nodeOffset];
573		else
574			p = NULL;
575	}
576	//dyld::log("trieWalk(%p) return NULL\n", start);
577	return NULL;
578}
579
580
581const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol, const ImageLoader** foundIn) const
582{
583	//dyld::log("Compressed::findExportedSymbol(%s) in %s\n", symbol, this->getShortName());
584	if ( fDyldInfo->export_size == 0 )
585		return NULL;
586#if LOG_BINDINGS
587	dyld::logBindings("%s: %s\n", this->getShortName(), symbol);
588#endif
589	++ImageLoaderMachO::fgSymbolTrieSearchs;
590	const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
591	const uint8_t* end = &start[fDyldInfo->export_size];
592	const uint8_t* foundNodeStart = this->trieWalk(start, end, symbol);
593	if ( foundNodeStart != NULL ) {
594		const uint8_t* p = foundNodeStart;
595		const uintptr_t flags = read_uleb128(p, end);
596		// found match, return pointer to terminal part of node
597		if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
598			// re-export from another dylib, lookup there
599			const uintptr_t ordinal = read_uleb128(p, end);
600			const char* importedName = (char*)p;
601			if ( importedName[0] == '\0' )
602				importedName = symbol;
603			if ( (ordinal > 0) && (ordinal <= libraryCount()) ) {
604				const ImageLoader* reexportedFrom = libImage((unsigned int)ordinal-1);
605				//dyld::log("Compressed::findExportedSymbol(), %s -> %s/%s\n", symbol, reexportedFrom->getShortName(), importedName);
606				return reexportedFrom->findExportedSymbol(importedName, true, foundIn);
607			}
608			else {
609				//dyld::throwf("bad mach-o binary, library ordinal (%u) invalid (max %u) for re-exported symbol %s in %s",
610				//	ordinal, libraryCount(), symbol, this->getPath());
611			}
612		}
613		else {
614			//dyld::log("findExportedSymbol(%s) in %s found match, returning %p\n", symbol, this->getShortName(), p);
615			if ( foundIn != NULL )
616				*foundIn = (ImageLoader*)this;
617			// return pointer to terminal part of node
618			return (Symbol*)foundNodeStart;
619		}
620	}
621	return NULL;
622}
623
624
625bool ImageLoaderMachOCompressed::containsSymbol(const void* addr) const
626{
627	const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
628	const uint8_t* end = &start[fDyldInfo->export_size];
629	return ( (start <= addr) && (addr < end) );
630}
631
632
633uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
634{
635	const uint8_t* exportNode = (uint8_t*)symbol;
636	const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
637	const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
638	if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
639		throw "symbol is not in trie";
640	//dyld::log("exportedSymbolAddress(): node=%p, nodeOffset=0x%04X in %s\n", symbol, (int)((uint8_t*)symbol - exportTrieStart), this->getShortName());
641	uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
642	switch ( flags & EXPORT_SYMBOL_FLAGS_KIND_MASK ) {
643		case EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
644			if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
645				// this node has a stub and resolver, run the resolver to get target address
646				uintptr_t stub = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData; // skip over stub
647				// <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
648				uintptr_t interposedStub = interposedAddress(context, stub, requestor);
649				if ( interposedStub != stub )
650					return interposedStub;
651				// stub was not interposed, so run resolver
652				typedef uintptr_t (*ResolverProc)(void);
653				ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
654				uintptr_t result = (*resolver)();
655				if ( context.verboseBind )
656					dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver, result);
657				return result;
658			}
659			return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
660		case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
661			if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
662				dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
663			return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
664		case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE:
665			if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
666				dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
667			return read_uleb128(exportNode, exportTrieEnd);
668		default:
669			dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
670	}
671}
672
673bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
674{
675	const uint8_t* exportNode = (uint8_t*)symbol;
676	const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
677	const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
678	if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
679		throw "symbol is not in trie";
680	uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
681	return ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION );
682}
683
684
685const char* ImageLoaderMachOCompressed::exportedSymbolName(const Symbol* symbol) const
686{
687	throw "NSNameOfSymbol() not supported with compressed LINKEDIT";
688}
689
690unsigned int ImageLoaderMachOCompressed::exportedSymbolCount() const
691{
692	throw "NSSymbolDefinitionCountInObjectFileImage() not supported with compressed LINKEDIT";
693}
694
695const ImageLoader::Symbol* ImageLoaderMachOCompressed::exportedSymbolIndexed(unsigned int index) const
696{
697	throw "NSSymbolDefinitionNameInObjectFileImage() not supported with compressed LINKEDIT";
698}
699
700unsigned int ImageLoaderMachOCompressed::importedSymbolCount() const
701{
702	throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
703}
704
705const ImageLoader::Symbol* ImageLoaderMachOCompressed::importedSymbolIndexed(unsigned int index) const
706{
707	throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
708}
709
710const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol* symbol) const
711{
712	throw "NSSymbolReferenceNameInObjectFileImage() not supported with compressed LINKEDIT";
713}
714
715
716
717uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import,
718													bool runResolver, const ImageLoader** foundIn)
719{
720	const Symbol* sym;
721	if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
722		if ( *foundIn != this )
723			context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
724		return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
725	}
726	// if a bundle is loaded privately the above will not find its exports
727	if ( this->isBundle() && this->hasHiddenExports() ) {
728		// look in self for needed symbol
729		sym = this->ImageLoaderMachO::findExportedSymbol(symbolName, false, foundIn);
730		if ( sym != NULL )
731			return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
732	}
733	if ( weak_import ) {
734		// definition can't be found anywhere, ok because it is weak, just return 0
735		return 0;
736	}
737	throwSymbolNotFound(context, symbolName, this->getPath(), "", "flat namespace");
738}
739
740
741uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import,
742												const char* symbolName, bool runResolver, const ImageLoader** foundIn)
743{
744	// two level lookup
745	const Symbol* sym = targetImage->findExportedSymbol(symbolName, true, foundIn);
746	if ( sym != NULL ) {
747		return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
748	}
749
750	if ( weak_import ) {
751		// definition can't be found anywhere, ok because it is weak, just return 0
752		return 0;
753	}
754
755	// nowhere to be found, check if maybe this image is too new for this OS
756	char versMismatch[256];
757	versMismatch[0] = '\0';
758	uint32_t imageMinOS = this->minOSVersion();
759	// dyld is always built for the current OS, so we can get the current OS version
760	// from the load command in dyld itself.
761	extern const mach_header __dso_handle;
762	uint32_t dyldMinOS = ImageLoaderMachO::minOSVersion(&__dso_handle);
763	if ( imageMinOS > dyldMinOS ) {
764#if __MAC_OS_X_VERSION_MIN_REQUIRED
765		const char* msg = dyld::mkstringf(" (which was built for Mac OS X %d.%d)", imageMinOS >> 16, (imageMinOS >> 8) & 0xFF);
766#else
767		const char* msg = dyld::mkstringf(" (which was built for iOS %d.%d)", imageMinOS >> 16, (imageMinOS >> 8) & 0xFF);
768#endif
769		strcpy(versMismatch, msg);
770		::free((void*)msg);
771	}
772	throwSymbolNotFound(context, symbolName, this->getPath(), versMismatch, targetImage->getPath());
773}
774
775
776uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const char* symbolName,
777													uint8_t symboFlags, long libraryOrdinal, const ImageLoader** targetImage,
778													LastLookup* last, bool runResolver)
779{
780	*targetImage = NULL;
781
782	// only clients that benefit from caching last lookup pass in a LastLookup struct
783	if ( last != NULL ) {
784		if ( (last->ordinal == libraryOrdinal)
785			&& (last->flags == symboFlags)
786			&& (last->name == symbolName) ) {
787				*targetImage = last->foundIn;
788				return last->result;
789			}
790	}
791
792	bool weak_import = (symboFlags & BIND_SYMBOL_FLAGS_WEAK_IMPORT);
793	uintptr_t symbolAddress;
794	if ( context.bindFlat || (libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ) {
795		symbolAddress = this->resolveFlat(context, symbolName, weak_import, runResolver, targetImage);
796	}
797	else {
798		if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
799			*targetImage = context.mainExecutable;
800		}
801		else if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF ) {
802			*targetImage = this;
803		}
804		else if ( libraryOrdinal <= 0 ) {
805			dyld::throwf("bad mach-o binary, unknown special library ordinal (%ld) too big for symbol %s in %s",
806				libraryOrdinal, symbolName, this->getPath());
807		}
808		else if ( (unsigned)libraryOrdinal <= libraryCount() ) {
809			*targetImage = libImage((unsigned int)libraryOrdinal-1);
810		}
811		else {
812			dyld::throwf("bad mach-o binary, library ordinal (%ld) too big (max %u) for symbol %s in %s",
813				libraryOrdinal, libraryCount(), symbolName, this->getPath());
814		}
815		if ( *targetImage == NULL ) {
816			if ( weak_import ) {
817				// if target library not loaded and reference is weak or library is weak return 0
818				symbolAddress = 0;
819			}
820			else {
821				dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%ld could not be loaded",
822					symbolName, this->getPath(), libraryOrdinal);
823			}
824		}
825		else {
826			symbolAddress = resolveTwolevel(context, *targetImage, weak_import, symbolName, runResolver, targetImage);
827		}
828	}
829
830	// save off lookup results if client wants
831	if ( last != NULL ) {
832		last->ordinal	= libraryOrdinal;
833		last->flags		= symboFlags;
834		last->name		= symbolName;
835		last->foundIn	= *targetImage;
836		last->result	= symbolAddress;
837	}
838
839	return symbolAddress;
840}
841
842uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName,
843								uint8_t symboFlags, intptr_t addend, long libraryOrdinal, const char* msg,
844								LastLookup* last, bool runResolver)
845{
846	const ImageLoader*	targetImage;
847	uintptr_t			symbolAddress;
848
849	// resolve symbol
850	symbolAddress = this->resolve(context, symbolName, symboFlags, libraryOrdinal, &targetImage, last, runResolver);
851
852	// do actual update
853	return this->bindLocation(context, addr, symbolAddress, targetImage, type, symbolName, addend, msg);
854}
855
856void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex,
857										const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
858{
859	dyld::throwf("malformed binding opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
860		(intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex),
861		segActualLoadAddress(segmentIndex), segmentEndAddress);
862}
863
864
865void ImageLoaderMachOCompressed::doBind(const LinkContext& context, bool forceLazysBound)
866{
867	CRSetCrashLogMessage2(this->getPath());
868
869	// if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
870	// note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
871	if ( this->usablePrebinding(context) ) {
872		// don't need to bind
873	}
874	else {
875
876	#if TEXT_RELOC_SUPPORT
877		// if there are __TEXT fixups, temporarily make __TEXT writable
878		if ( fTextSegmentBinds )
879			this->makeTextSegmentWritable(context, true);
880	#endif
881
882		// run through all binding opcodes
883		eachBind(context, &ImageLoaderMachOCompressed::bindAt);
884
885	#if TEXT_RELOC_SUPPORT
886		// if there were __TEXT fixups, restore write protection
887		if ( fTextSegmentBinds )
888			this->makeTextSegmentWritable(context, false);
889	#endif
890
891		// if this image is in the shared cache, but depends on something no longer in the shared cache,
892		// there is no way to reset the lazy pointers, so force bind them now
893		if ( forceLazysBound || fInSharedCache )
894			this->doBindJustLazies(context);
895
896		// this image is in cache, but something below it is not.  If
897        // this image has lazy pointer to a resolver function, then
898        // the stub may have been altered to point to a shared lazy pointer.
899		if ( fInSharedCache )
900			this->updateOptimizedLazyPointers(context);
901
902		// tell kernel we are done with chunks of LINKEDIT
903		if ( !context.preFetchDisabled )
904			this->markFreeLINKEDIT(context);
905	}
906
907	// set up dyld entry points in image
908	// do last so flat main executables will have __dyld or __program_vars set up
909	this->setupLazyPointerHandler(context);
910	CRSetCrashLogMessage2(NULL);
911}
912
913
914void ImageLoaderMachOCompressed::doBindJustLazies(const LinkContext& context)
915{
916	eachLazyBind(context, &ImageLoaderMachOCompressed::bindAt);
917}
918
919void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handler handler)
920{
921	try {
922		uint8_t type = 0;
923		int segmentIndex = 0;
924		uintptr_t address = segActualLoadAddress(0);
925		uintptr_t segmentEndAddress = segActualEndAddress(0);
926		const char* symbolName = NULL;
927		uint8_t symboFlags = 0;
928		long libraryOrdinal = 0;
929		intptr_t addend = 0;
930		uintptr_t count;
931		uintptr_t skip;
932		LastLookup last = { 0, 0, NULL, 0, NULL };
933		const uint8_t* const start = fLinkEditBase + fDyldInfo->bind_off;
934		const uint8_t* const end = &start[fDyldInfo->bind_size];
935		const uint8_t* p = start;
936		bool done = false;
937		while ( !done && (p < end) ) {
938			uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
939			uint8_t opcode = *p & BIND_OPCODE_MASK;
940			++p;
941			switch (opcode) {
942				case BIND_OPCODE_DONE:
943					done = true;
944					break;
945				case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
946					libraryOrdinal = immediate;
947					break;
948				case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
949					libraryOrdinal = read_uleb128(p, end);
950					break;
951				case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
952					// the special ordinals are negative numbers
953					if ( immediate == 0 )
954						libraryOrdinal = 0;
955					else {
956						int8_t signExtended = BIND_OPCODE_MASK | immediate;
957						libraryOrdinal = signExtended;
958					}
959					break;
960				case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
961					symbolName = (char*)p;
962					symboFlags = immediate;
963					while (*p != '\0')
964						++p;
965					++p;
966					break;
967				case BIND_OPCODE_SET_TYPE_IMM:
968					type = immediate;
969					break;
970				case BIND_OPCODE_SET_ADDEND_SLEB:
971					addend = read_sleb128(p, end);
972					break;
973				case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
974					segmentIndex = immediate;
975					if ( segmentIndex >= fSegmentsCount )
976						dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
977								segmentIndex, fSegmentsCount-1);
978					address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
979					segmentEndAddress = segActualEndAddress(segmentIndex);
980					break;
981				case BIND_OPCODE_ADD_ADDR_ULEB:
982					address += read_uleb128(p, end);
983					break;
984				case BIND_OPCODE_DO_BIND:
985					if ( address >= segmentEndAddress )
986						throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
987					(this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
988					address += sizeof(intptr_t);
989					break;
990				case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
991					if ( address >= segmentEndAddress )
992						throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
993					(this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
994					address += read_uleb128(p, end) + sizeof(intptr_t);
995					break;
996				case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
997					if ( address >= segmentEndAddress )
998						throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
999					(this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
1000					address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1001					break;
1002				case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1003					count = read_uleb128(p, end);
1004					skip = read_uleb128(p, end);
1005					for (uint32_t i=0; i < count; ++i) {
1006						if ( address >= segmentEndAddress )
1007							throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1008						(this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
1009						address += skip + sizeof(intptr_t);
1010					}
1011					break;
1012				default:
1013					dyld::throwf("bad bind opcode %d in bind info", *p);
1014			}
1015		}
1016	}
1017	catch (const char* msg) {
1018		const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
1019		free((void*)msg);
1020		throw newMsg;
1021	}
1022}
1023
1024void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_handler handler)
1025{
1026	try {
1027		uint8_t type = BIND_TYPE_POINTER;
1028		int segmentIndex = 0;
1029		uintptr_t address = segActualLoadAddress(0);
1030		uintptr_t segmentEndAddress = segActualEndAddress(0);
1031		const char* symbolName = NULL;
1032		uint8_t symboFlags = 0;
1033		long libraryOrdinal = 0;
1034		intptr_t addend = 0;
1035		const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
1036		const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
1037		const uint8_t* p = start;
1038		bool done = false;
1039		while ( !done && (p < end) ) {
1040			uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1041			uint8_t opcode = *p & BIND_OPCODE_MASK;
1042			++p;
1043			switch (opcode) {
1044				case BIND_OPCODE_DONE:
1045					// there is BIND_OPCODE_DONE at end of each lazy bind, don't stop until end of whole sequence
1046					break;
1047				case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1048					libraryOrdinal = immediate;
1049					break;
1050				case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1051					libraryOrdinal = read_uleb128(p, end);
1052					break;
1053				case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1054					// the special ordinals are negative numbers
1055					if ( immediate == 0 )
1056						libraryOrdinal = 0;
1057					else {
1058						int8_t signExtended = BIND_OPCODE_MASK | immediate;
1059						libraryOrdinal = signExtended;
1060					}
1061					break;
1062				case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1063					symbolName = (char*)p;
1064					symboFlags = immediate;
1065					while (*p != '\0')
1066						++p;
1067					++p;
1068					break;
1069				case BIND_OPCODE_SET_TYPE_IMM:
1070					type = immediate;
1071					break;
1072				case BIND_OPCODE_SET_ADDEND_SLEB:
1073					addend = read_sleb128(p, end);
1074					break;
1075				case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1076					segmentIndex = immediate;
1077					if ( segmentIndex >= fSegmentsCount )
1078						dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1079								segmentIndex, fSegmentsCount-1);
1080					address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
1081					segmentEndAddress = segActualEndAddress(segmentIndex);
1082					break;
1083				case BIND_OPCODE_ADD_ADDR_ULEB:
1084					address += read_uleb128(p, end);
1085					break;
1086				case BIND_OPCODE_DO_BIND:
1087					if ( address >= segmentEndAddress )
1088						throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1089					(this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "forced lazy ", NULL, false);
1090					address += sizeof(intptr_t);
1091					break;
1092				case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1093				case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1094				case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1095				default:
1096					dyld::throwf("bad lazy bind opcode %d", *p);
1097			}
1098		}
1099	}
1100
1101	catch (const char* msg) {
1102		const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
1103		free((void*)msg);
1104		throw newMsg;
1105	}
1106}
1107
1108// A program built targeting 10.5 will have hybrid stubs.  When used with weak symbols
1109// the classic lazy loader is used even when running on 10.6
1110uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
1111{
1112	// only works with compressed LINKEDIT if classic symbol table is also present
1113	const macho_nlist* symbolTable = NULL;
1114	const char* symbolTableStrings = NULL;
1115	const dysymtab_command* dynSymbolTable = NULL;
1116	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1117	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1118	const struct load_command* cmd = cmds;
1119	for (uint32_t i = 0; i < cmd_count; ++i) {
1120		switch (cmd->cmd) {
1121			case LC_SYMTAB:
1122				{
1123					const struct symtab_command* symtab = (struct symtab_command*)cmd;
1124					symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
1125					symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
1126				}
1127				break;
1128			case LC_DYSYMTAB:
1129				dynSymbolTable = (struct dysymtab_command*)cmd;
1130				break;
1131		}
1132		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1133	}
1134	// no symbol table => no lookup by address
1135	if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
1136		dyld::throwf("classic lazy binding used with compressed LINKEDIT at %p in image %s", lazyPointer, this->getPath());
1137
1138	// scan for all lazy-pointer sections
1139	const bool twoLevel = this->usesTwoLevelNameSpace();
1140	const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
1141	cmd = cmds;
1142	for (uint32_t i = 0; i < cmd_count; ++i) {
1143		switch (cmd->cmd) {
1144			case LC_SEGMENT_COMMAND:
1145				{
1146					const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1147					const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1148					const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1149					for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1150						const uint8_t type = sect->flags & SECTION_TYPE;
1151						uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
1152						if ( type == S_LAZY_SYMBOL_POINTERS ) {
1153							const size_t pointerCount = sect->size / sizeof(uintptr_t);
1154							uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1155							if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
1156								const uint32_t indirectTableOffset = sect->reserved1;
1157								const size_t lazyIndex = lazyPointer - symbolPointers;
1158								symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
1159							}
1160						}
1161						if ( (symbolIndex != INDIRECT_SYMBOL_ABS) && (symbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
1162							const macho_nlist* symbol = &symbolTable[symbolIndex];
1163							const char* symbolName = &symbolTableStrings[symbol->n_un.n_strx];
1164							int libraryOrdinal = GET_LIBRARY_ORDINAL(symbol->n_desc);
1165							if ( !twoLevel || context.bindFlat )
1166								libraryOrdinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
1167							uintptr_t ptrToBind = (uintptr_t)lazyPointer;
1168							uintptr_t symbolAddr = bindAt(context, ptrToBind, BIND_TYPE_POINTER, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL);
1169							++fgTotalLazyBindFixups;
1170							return symbolAddr;
1171						}
1172					}
1173				}
1174				break;
1175		}
1176		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1177	}
1178	dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
1179}
1180
1181
1182uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context,
1183															void (*lock)(), void (*unlock)())
1184{
1185	// <rdar://problem/8663923> race condition with flat-namespace lazy binding
1186	if ( this->usesTwoLevelNameSpace() ) {
1187		// two-level namespace lookup does not require lock because dependents can't be unloaded before this image
1188	}
1189	else {
1190		// acquire dyld global lock
1191		if ( lock != NULL )
1192			lock();
1193	}
1194
1195	const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
1196	const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
1197	if ( lazyBindingInfoOffset > fDyldInfo->lazy_bind_size ) {
1198		dyld::throwf("fast lazy bind offset out of range (%u, max=%u) in image %s",
1199			lazyBindingInfoOffset, fDyldInfo->lazy_bind_size, this->getPath());
1200	}
1201
1202	uint8_t type = BIND_TYPE_POINTER;
1203	uintptr_t address = 0;
1204	const char* symbolName = NULL;
1205	uint8_t symboFlags = 0;
1206	long libraryOrdinal = 0;
1207	bool done = false;
1208	uintptr_t result = 0;
1209	const uint8_t* p = &start[lazyBindingInfoOffset];
1210	while ( !done && (p < end) ) {
1211		uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1212		uint8_t opcode = *p & BIND_OPCODE_MASK;
1213		++p;
1214		switch (opcode) {
1215			case BIND_OPCODE_DONE:
1216				done = true;
1217				break;
1218			case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1219				libraryOrdinal = immediate;
1220				break;
1221			case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1222				libraryOrdinal = read_uleb128(p, end);
1223				break;
1224			case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1225				// the special ordinals are negative numbers
1226				if ( immediate == 0 )
1227					libraryOrdinal = 0;
1228				else {
1229					int8_t signExtended = BIND_OPCODE_MASK | immediate;
1230					libraryOrdinal = signExtended;
1231				}
1232				break;
1233			case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1234				symbolName = (char*)p;
1235				symboFlags = immediate;
1236				while (*p != '\0')
1237					++p;
1238				++p;
1239				break;
1240			case BIND_OPCODE_SET_TYPE_IMM:
1241				type = immediate;
1242				break;
1243			case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1244				if ( immediate >= fSegmentsCount )
1245					dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1246							immediate, fSegmentsCount-1);
1247				address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1248				break;
1249			case BIND_OPCODE_DO_BIND:
1250
1251
1252				result = this->bindAt(context, address, type, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL, true);
1253				break;
1254			case BIND_OPCODE_SET_ADDEND_SLEB:
1255			case BIND_OPCODE_ADD_ADDR_ULEB:
1256			case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1257			case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1258			case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1259			default:
1260				dyld::throwf("bad lazy bind opcode %d", *p);
1261		}
1262	}
1263
1264	if ( !this->usesTwoLevelNameSpace() ) {
1265		// release dyld global lock
1266		if ( unlock != NULL )
1267			unlock();
1268	}
1269	return result;
1270}
1271
1272void ImageLoaderMachOCompressed::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder)
1273{
1274	it.image = this;
1275	it.symbolName = " ";
1276	it.loadOrder = loadOrder;
1277	it.weakSymbol = false;
1278	it.symbolMatches = false;
1279	it.done = false;
1280	it.curIndex = 0;
1281	it.endIndex = this->fDyldInfo->weak_bind_size;
1282	it.address = 0;
1283	it.type = 0;
1284	it.addend = 0;
1285}
1286
1287
1288bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
1289{
1290	if ( it.done )
1291		return false;
1292
1293	if ( this->fDyldInfo->weak_bind_size == 0 ) {
1294		/// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
1295		it.done = true;
1296		it.symbolName = "~~~";
1297		return true;
1298	}
1299	const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
1300	const uint8_t* p = start + it.curIndex;
1301	const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
1302	uintptr_t count;
1303	uintptr_t skip;
1304	while ( p < end ) {
1305		uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1306		uint8_t opcode = *p & BIND_OPCODE_MASK;
1307		++p;
1308		switch (opcode) {
1309			case BIND_OPCODE_DONE:
1310				it.done = true;
1311				it.curIndex = p - start;
1312				it.symbolName = "~~~"; // sorts to end
1313				return true;
1314			case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1315				it.symbolName = (char*)p;
1316				it.weakSymbol = ((immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) == 0);
1317				it.symbolMatches = false;
1318				while (*p != '\0')
1319					++p;
1320				++p;
1321				it.curIndex = p - start;
1322				return false;
1323			case BIND_OPCODE_SET_TYPE_IMM:
1324				it.type = immediate;
1325				break;
1326			case BIND_OPCODE_SET_ADDEND_SLEB:
1327				it.addend = read_sleb128(p, end);
1328				break;
1329			case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1330				if ( immediate >= fSegmentsCount )
1331					dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1332							immediate, fSegmentsCount-1);
1333				it.address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1334				break;
1335			case BIND_OPCODE_ADD_ADDR_ULEB:
1336				it.address += read_uleb128(p, end);
1337				break;
1338			case BIND_OPCODE_DO_BIND:
1339				it.address += sizeof(intptr_t);
1340				break;
1341			case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1342				it.address += read_uleb128(p, end) + sizeof(intptr_t);
1343				break;
1344			case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1345				it.address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1346				break;
1347			case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1348				count = read_uleb128(p, end);
1349				skip = read_uleb128(p, end);
1350				for (uint32_t i=0; i < count; ++i) {
1351					it.address += skip + sizeof(intptr_t);
1352				}
1353				break;
1354			default:
1355				dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p, (int)(p-start), this->getPath());
1356		}
1357	}
1358	/// hmmm, BIND_OPCODE_DONE is missing...
1359	it.done = true;
1360	it.symbolName = "~~~";
1361	//dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
1362	return true;
1363}
1364
1365uintptr_t ImageLoaderMachOCompressed::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
1366{
1367	//dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
1368	const ImageLoader* foundIn = NULL;
1369	const ImageLoader::Symbol* sym = this->findExportedSymbol(it.symbolName, &foundIn);
1370	if ( sym != NULL ) {
1371		//dyld::log("sym=%p, foundIn=%p\n", sym, foundIn);
1372		return foundIn->getExportedSymbolAddress(sym, context, this);
1373	}
1374	return 0;
1375}
1376
1377
1378void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context)
1379{
1380	// <rdar://problem/6570879> weak binding done too early with inserted libraries
1381	if ( this->getState() < dyld_image_state_bound  )
1382		return;
1383
1384	const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
1385	const uint8_t* p = start + it.curIndex;
1386	const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
1387
1388	uint8_t type = it.type;
1389	uintptr_t address = it.address;
1390	const char* symbolName = it.symbolName;
1391	intptr_t addend = it.addend;
1392	uintptr_t count;
1393	uintptr_t skip;
1394	bool done = false;
1395	bool boundSomething = false;
1396	while ( !done && (p < end) ) {
1397		uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1398		uint8_t opcode = *p & BIND_OPCODE_MASK;
1399		++p;
1400		switch (opcode) {
1401			case BIND_OPCODE_DONE:
1402				done = true;
1403				break;
1404			case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1405				done = true;
1406				break;
1407			case BIND_OPCODE_SET_TYPE_IMM:
1408				type = immediate;
1409				break;
1410			case BIND_OPCODE_SET_ADDEND_SLEB:
1411				addend = read_sleb128(p, end);
1412				break;
1413			case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1414				if ( immediate >= fSegmentsCount )
1415					dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1416							immediate, fSegmentsCount-1);
1417				address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1418				break;
1419			case BIND_OPCODE_ADD_ADDR_ULEB:
1420				address += read_uleb128(p, end);
1421				break;
1422			case BIND_OPCODE_DO_BIND:
1423				bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1424				boundSomething = true;
1425				address += sizeof(intptr_t);
1426				break;
1427			case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1428				bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1429				boundSomething = true;
1430				address += read_uleb128(p, end) + sizeof(intptr_t);
1431				break;
1432			case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1433				bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1434				boundSomething = true;
1435				address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1436				break;
1437			case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1438				count = read_uleb128(p, end);
1439				skip = read_uleb128(p, end);
1440				for (uint32_t i=0; i < count; ++i) {
1441					bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1442					boundSomething = true;
1443					address += skip + sizeof(intptr_t);
1444				}
1445				break;
1446			default:
1447				dyld::throwf("bad bind opcode %d in weak binding info", *p);
1448		}
1449	}
1450	// C++ weak coalescing cannot be tracked by reference counting.  Error on side of never unloading.
1451	if ( boundSomething && (targetImage != this) )
1452		context.addDynamicReference(this, targetImage);
1453}
1454
1455uintptr_t ImageLoaderMachOCompressed::interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*,
1456												uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver)
1457{
1458	if ( type == BIND_TYPE_POINTER ) {
1459		uintptr_t* fixupLocation = (uintptr_t*)addr;
1460		uintptr_t curValue = *fixupLocation;
1461		uintptr_t newValue = interposedAddress(context, curValue, this);
1462		if ( newValue != curValue)
1463			*fixupLocation = newValue;
1464	}
1465	return 0;
1466}
1467
1468void ImageLoaderMachOCompressed::doInterpose(const LinkContext& context)
1469{
1470	if ( context.verboseInterposing )
1471		dyld::log("dyld: interposing %lu tuples onto image: %s\n", fgInterposingTuples.size(), this->getPath());
1472
1473	// update prebound symbols
1474	eachBind(context, &ImageLoaderMachOCompressed::interposeAt);
1475	eachLazyBind(context, &ImageLoaderMachOCompressed::interposeAt);
1476}
1477
1478
1479uintptr_t ImageLoaderMachOCompressed::dynamicInterposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName,
1480												uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver)
1481{
1482	if ( type == BIND_TYPE_POINTER ) {
1483		uintptr_t* fixupLocation = (uintptr_t*)addr;
1484		uintptr_t value = *fixupLocation;
1485		// don't apply interposing to table entries.
1486		if ( (context.dynamicInterposeArray <= (void*)addr) && ((void*)addr < &context.dynamicInterposeArray[context.dynamicInterposeCount]) )
1487			return 0;
1488		for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
1489			if ( value == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
1490				if ( context.verboseInterposing ) {
1491					dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",
1492						fixupLocation, context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
1493				}
1494				*fixupLocation = (uintptr_t)context.dynamicInterposeArray[i].replacement;
1495			}
1496		}
1497	}
1498	return 0;
1499}
1500
1501void ImageLoaderMachOCompressed::dynamicInterpose(const LinkContext& context)
1502{
1503	if ( context.verboseInterposing )
1504		dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context.dynamicInterposeCount, this->getPath());
1505
1506	// update already bound references to symbols
1507	eachBind(context, &ImageLoaderMachOCompressed::dynamicInterposeAt);
1508	eachLazyBind(context, &ImageLoaderMachOCompressed::dynamicInterposeAt);
1509}
1510
1511
1512const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr, const void** closestAddr) const
1513{
1514	// called by dladdr()
1515	// only works with compressed LINKEDIT if classic symbol table is also present
1516	const macho_nlist* symbolTable = NULL;
1517	const char* symbolTableStrings = NULL;
1518	const dysymtab_command* dynSymbolTable = NULL;
1519	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1520	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1521	const struct load_command* cmd = cmds;
1522	for (uint32_t i = 0; i < cmd_count; ++i) {
1523		switch (cmd->cmd) {
1524			case LC_SYMTAB:
1525				{
1526					const struct symtab_command* symtab = (struct symtab_command*)cmd;
1527					symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
1528					symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
1529				}
1530				break;
1531			case LC_DYSYMTAB:
1532				dynSymbolTable = (struct dysymtab_command*)cmd;
1533				break;
1534		}
1535		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1536	}
1537	// no symbol table => no lookup by address
1538	if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
1539		return NULL;
1540
1541	uintptr_t targetAddress = (uintptr_t)addr - fSlide;
1542	const struct macho_nlist* bestSymbol = NULL;
1543	// first walk all global symbols
1544	const struct macho_nlist* const globalsStart = &symbolTable[dynSymbolTable->iextdefsym];
1545	const struct macho_nlist* const globalsEnd= &globalsStart[dynSymbolTable->nextdefsym];
1546	for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
1547 		if ( (s->n_type & N_TYPE) == N_SECT ) {
1548			if ( bestSymbol == NULL ) {
1549				if ( s->n_value <= targetAddress )
1550					bestSymbol = s;
1551			}
1552			else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
1553				bestSymbol = s;
1554			}
1555		}
1556	}
1557	// next walk all local symbols
1558	const struct macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
1559	const struct macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
1560	for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
1561 		if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
1562			if ( bestSymbol == NULL ) {
1563				if ( s->n_value <= targetAddress )
1564					bestSymbol = s;
1565			}
1566			else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
1567				bestSymbol = s;
1568			}
1569		}
1570	}
1571	if ( bestSymbol != NULL ) {
1572#if __arm__
1573		if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
1574			*closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
1575		else
1576			*closestAddr = (void*)(bestSymbol->n_value + fSlide);
1577#else
1578		*closestAddr = (void*)(bestSymbol->n_value + fSlide);
1579#endif
1580		return &symbolTableStrings[bestSymbol->n_un.n_strx];
1581	}
1582	return NULL;
1583}
1584
1585
1586#if PREBOUND_IMAGE_SUPPORT
1587void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& context)
1588{
1589	// no way to back off a prebound compress image
1590}
1591#endif
1592
1593
1594#if __arm__ || __x86_64__
1595void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr, const LinkContext& context)
1596{
1597#if __arm__
1598	uint32_t* instructions = (uint32_t*)stub;
1599    // sanity check this is a stub we understand
1600	if ( (instructions[0] != 0xe59fc004) || (instructions[1] != 0xe08fc00c) || (instructions[2] != 0xe59cf000) )
1601		return;
1602
1603	void** lazyPointerAddr = (void**)(instructions[3] + (stub + 12));
1604#endif
1605#if __x86_64__
1606    // sanity check this is a stub we understand
1607	if ( (stub[0] != 0xFF) || (stub[1] != 0x25) )
1608		return;
1609    int32_t ripOffset = *((int32_t*)(&stub[2]));
1610	void** lazyPointerAddr = (void**)(ripOffset + stub + 6);
1611#endif
1612
1613   // if stub does not use original lazy pointer (meaning it was optimized by update_dyld_shared_cache)
1614    if ( lazyPointerAddr != originalLazyPointerAddr ) {
1615		// <rdar://problem/12928448> only de-optimization lazy pointers if they are part of shared cache not loaded (because overridden)
1616		const ImageLoader* lazyPointerImage = context.findImageContainingAddress(lazyPointerAddr);
1617		if ( lazyPointerImage != NULL )
1618			return;
1619
1620        // copy newly re-bound lazy pointer value to shared lazy pointer
1621        *lazyPointerAddr = *originalLazyPointerAddr;
1622
1623		if ( context.verboseBind )
1624			dyld::log("dyld: alter bind: %s: *0x%08lX = 0x%08lX \n",
1625					  this->getShortName(), (long)lazyPointerAddr, (long)*originalLazyPointerAddr);
1626    }
1627}
1628#endif
1629
1630
1631// <rdar://problem/8890875> overriding shared cache dylibs with resolvers fails
1632void ImageLoaderMachOCompressed::updateOptimizedLazyPointers(const LinkContext& context)
1633{
1634#if __arm__ || __x86_64__
1635	// find stubs and lazy pointer sections
1636	const struct macho_section* stubsSection = NULL;
1637	const struct macho_section* lazyPointerSection = NULL;
1638	const dysymtab_command* dynSymbolTable = NULL;
1639	const macho_header* mh = (macho_header*)fMachOData;
1640	const uint32_t cmd_count = mh->ncmds;
1641	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1642	const struct load_command* cmd = cmds;
1643	for (uint32_t i = 0; i < cmd_count; ++i) {
1644		if (cmd->cmd == LC_SEGMENT_COMMAND) {
1645			const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1646			const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1647			const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1648			for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1649				const uint8_t type = sect->flags & SECTION_TYPE;
1650				if ( type == S_SYMBOL_STUBS )
1651					stubsSection = sect;
1652				else if ( type == S_LAZY_SYMBOL_POINTERS )
1653					lazyPointerSection = sect;
1654			}
1655		}
1656		else if ( cmd->cmd == LC_DYSYMTAB ) {
1657			dynSymbolTable = (struct dysymtab_command*)cmd;
1658		}
1659		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1660	}
1661
1662	// sanity check
1663	if ( dynSymbolTable == NULL )
1664		return;
1665	if ( (stubsSection == NULL) || (lazyPointerSection == NULL) )
1666		return;
1667	const uint32_t stubsCount = stubsSection->size / stubsSection->reserved2;
1668	const uint32_t lazyPointersCount = lazyPointerSection->size / sizeof(void*);
1669	if ( stubsCount != lazyPointersCount )
1670		return;
1671	const uint32_t stubsIndirectTableOffset = stubsSection->reserved1;
1672	const uint32_t lazyPointersIndirectTableOffset = lazyPointerSection->reserved1;
1673	if ( (stubsIndirectTableOffset+stubsCount) > dynSymbolTable->nindirectsyms )
1674		return;
1675	if ( (lazyPointersIndirectTableOffset+lazyPointersCount) > dynSymbolTable->nindirectsyms )
1676		return;
1677
1678	// walk stubs and lazy pointers
1679	const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
1680	void** const lazyPointersStartAddr = (void**)(lazyPointerSection->addr + this->fSlide);
1681	uint8_t* const stubsStartAddr = (uint8_t*)(stubsSection->addr + this->fSlide);
1682	uint8_t* stub = stubsStartAddr;
1683	void** lpa = lazyPointersStartAddr;
1684	for(uint32_t i=0; i < stubsCount; ++i, stub += stubsSection->reserved2, ++lpa) {
1685        // sanity check symbol index of stub and lazy pointer match
1686		if ( indirectTable[stubsIndirectTableOffset+i] != indirectTable[lazyPointersIndirectTableOffset+i] )
1687			continue;
1688		this->updateAlternateLazyPointer(stub, lpa, context);
1689	}
1690
1691#endif
1692}
1693
1694
1695