1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2010 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// work around until conformance work is complete rdar://problem/4508801
26#define __srr0	srr0
27#define __eip	eip
28#define __rip	rip
29
30
31#include <string.h>
32#include <fcntl.h>
33#include <errno.h>
34#include <sys/types.h>
35#include <sys/fcntl.h>
36#include <sys/stat.h>
37#include <sys/mman.h>
38#include <mach/mach.h>
39#include <mach/thread_status.h>
40#include <mach-o/loader.h>
41#include <mach-o/reloc.h>
42#include <mach-o/nlist.h>
43#include <sys/sysctl.h>
44#include <libkern/OSAtomic.h>
45#include <libkern/OSCacheControl.h>
46
47#if __x86_64__
48	#include <mach-o/x86_64/reloc.h>
49#endif
50#if __arm__
51	#include <mach-o/arm/reloc.h>
52#endif
53
54#include "ImageLoaderMachOClassic.h"
55#include "mach-o/dyld_images.h"
56
57// in dyldStartup.s
58extern "C" void fast_stub_binding_helper_interface();
59
60
61#if __x86_64__
62	#define POINTER_RELOC X86_64_RELOC_UNSIGNED
63#else
64	#define POINTER_RELOC GENERIC_RELOC_VANILLA
65#endif
66
67
68// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
69#if __LP64__
70	#define RELOC_SIZE 3
71	#define LC_SEGMENT_COMMAND		LC_SEGMENT_64
72	#define LC_ROUTINES_COMMAND		LC_ROUTINES_64
73	struct macho_segment_command	: public segment_command_64  {};
74	struct macho_section			: public section_64  {};
75	struct macho_routines_command	: public routines_command_64  {};
76#else
77	#define RELOC_SIZE 2
78	#define LC_SEGMENT_COMMAND		LC_SEGMENT
79	#define LC_ROUTINES_COMMAND		LC_ROUTINES
80	struct macho_segment_command	: public segment_command {};
81	struct macho_section			: public section  {};
82	struct macho_routines_command	: public routines_command  {};
83#endif
84
85
86
87
88// create image for main executable
89ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path,
90																		unsigned int segCount, unsigned int libCount, const LinkContext& context)
91{
92	ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
93
94	// set slide for PIE programs
95	image->setSlide(slide);
96
97	// for PIE record end of program, to know where to start loading dylibs
98	if ( slide != 0 )
99		fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
100
101	image->instantiateFinish(context);
102	image->setMapped(context);
103
104#if __i386__
105	// kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
106	if ( image->fReadOnlyImportSegment ) {
107		for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
108			if ( image->segIsReadOnlyImport(i) )
109				image->segMakeWritable(i, context);
110		}
111	}
112#endif
113
114	if ( context.verboseMapping ) {
115		dyld::log("dyld: Main executable mapped %s\n", path);
116		for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
117			const char* name = image->segName(i);
118			if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0)  )
119				dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
120			else
121				dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
122		}
123	}
124
125	return image;
126}
127
128// create image by mapping in a mach-o file
129ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char* path, int fd, const uint8_t* fileData,
130															uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info,
131															unsigned int segCount, unsigned int libCount,
132															const struct linkedit_data_command* codeSigCmd, const LinkContext& context)
133{
134	ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart((macho_header*)fileData, path, segCount, libCount);
135	try {
136		// record info about file
137		image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
138
139		// if this image is code signed, let kernel validate signature before mapping any pages from image
140		image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context);
141
142		// mmap segments
143		image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context);
144
145		// finish up
146		image->instantiateFinish(context);
147
148		// if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
149		const char* installName = image->getInstallPath();
150		if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
151			image->setPathUnowned(installName);
152		else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) {
153			// rdar://problem/10733082 Fix up @path based paths during introspection
154			// rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
155			char realPath[MAXPATHLEN];
156			if ( fcntl(fd, F_GETPATH, realPath) == 0 )
157				image->setPaths(path, realPath);
158			else
159				image->setPath(path);
160		}
161		else
162			image->setPath(path);
163
164		// make sure path is stable before recording in dyld_all_image_infos
165		image->setMapped(context);
166
167		// pre-fetch content of __DATA segment for faster launches
168		// don't do this on prebound images or if prefetching is disabled
169        if ( !context.preFetchDisabled && !image->isPrebindable())
170			image->preFetchDATA(fd, offsetInFat, context);
171
172	}
173	catch (...) {
174		// ImageLoader::setMapped() can throw an exception to block loading of image
175		// <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
176		delete image;
177		throw;
178	}
179
180	return image;
181}
182
183// create image by using cached mach-o file
184ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info,
185																unsigned int segCount, unsigned int libCount, const LinkContext& context)
186{
187	ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
188	try {
189		// record info about file
190		image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
191
192		// remember this is from shared cache and cannot be unloaded
193		image->fInSharedCache = true;
194		image->setNeverUnload();
195
196		// segments already mapped in cache
197		if ( context.verboseMapping ) {
198			dyld::log("dyld: Using shared cached for %s\n", path);
199			for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
200				dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
201			}
202		}
203
204		image->instantiateFinish(context);
205		image->setMapped(context);
206	}
207	catch (...) {
208		// ImageLoader::setMapped() can throw an exception to block loading of image
209		// <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
210		delete image;
211		throw;
212	}
213
214	return image;
215}
216
217// create image by copying an in-memory mach-o file
218ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len,
219															unsigned int segCount, unsigned int libCount, const LinkContext& context)
220{
221	ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, moduleName, segCount, libCount);
222	try {
223		// map segments
224		if ( mh->filetype == MH_EXECUTE )
225			throw "can't load another MH_EXECUTE";
226
227		// vmcopy segments
228		image->ImageLoaderMachO::mapSegments((const void*)mh, len, context);
229
230		// for compatibility, never unload dylibs loaded from memory
231		image->setNeverUnload();
232
233		// bundle loads need path copied
234		if ( moduleName != NULL )
235			image->setPath(moduleName);
236
237		image->instantiateFinish(context);
238		image->setMapped(context);
239	}
240	catch (...) {
241		// ImageLoader::setMapped() can throw an exception to block loading of image
242		// <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
243		delete image;
244		throw;
245	}
246
247	return image;
248}
249
250
251ImageLoaderMachOClassic::ImageLoaderMachOClassic(const macho_header* mh, const char* path,
252													unsigned int segCount, uint32_t segOffsets[], unsigned int libCount)
253 : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fStrings(NULL), fSymbolTable(NULL), fDynamicInfo(NULL)
254{
255}
256
257// construct ImageLoaderMachOClassic using "placement new" with SegmentMachO objects array at end
258ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateStart(const macho_header* mh, const char* path,
259																		unsigned int segCount, unsigned int libCount)
260{
261	size_t size = sizeof(ImageLoaderMachOClassic) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
262	ImageLoaderMachOClassic* allocatedSpace = static_cast<ImageLoaderMachOClassic*>(malloc(size));
263	if ( allocatedSpace == NULL )
264		throw "malloc failed";
265	uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOClassic)));
266	bzero(&segOffsets[segCount], libCount*sizeof(void*));	// zero out lib array
267	return new (allocatedSpace) ImageLoaderMachOClassic(mh, path, segCount, segOffsets, libCount);
268}
269
270
271
272// common code to finish initializing object
273void ImageLoaderMachOClassic::instantiateFinish(const LinkContext& context)
274{
275	// now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
276	this->parseLoadCmds();
277}
278
279ImageLoaderMachOClassic::~ImageLoaderMachOClassic()
280{
281	// don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
282	destroy();
283}
284
285uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const
286{
287	return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic)));
288}
289
290
291ImageLoader* ImageLoaderMachOClassic::libImage(unsigned int libIndex) const
292{
293	const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
294	// mask off low bits
295	return (ImageLoader*)(images[libIndex] & (-4));
296}
297
298bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
299{
300	const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
301	// re-export flag is low bit
302	return ((images[libIndex] & 1) != 0);
303}
304
305bool ImageLoaderMachOClassic::libIsUpward(unsigned int libIndex) const
306{
307	const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
308	// upward flag is second bit
309	return ((images[libIndex] & 2) != 0);
310}
311
312
313void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward)
314{
315	uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
316	uintptr_t value = (uintptr_t)image;
317	if ( reExported )
318		value |= 1;
319	if ( upward )
320		value |= 2;
321	images[libIndex] = value;
322}
323
324
325void ImageLoaderMachOClassic::setSymbolTableInfo(const macho_nlist* symbols, const char* strings, const dysymtab_command* dynSym)
326{
327	fSymbolTable = symbols;
328	fStrings = strings;
329	fDynamicInfo = dynSym;
330}
331
332void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext& context)
333{
334	// always prefetch a subrange of __LINKEDIT pages
335	uintptr_t symbolTableStart = (uintptr_t)fSymbolTable;
336	uintptr_t stringTableStart = (uintptr_t)fStrings;
337	uintptr_t start;
338	// if image did not load at preferred address
339	if ( segPreferredLoadAddress(0) != (uintptr_t)fMachOData ) {
340		// local relocations will be processed, so start pre-fetch at local symbols
341		start = (uintptr_t)fMachOData + fDynamicInfo->locreloff;
342	}
343	else {
344		// otherwise start pre-fetch at global symbols section of symbol table
345		start = symbolTableStart + fDynamicInfo->iextdefsym * sizeof(macho_nlist);
346	}
347	// prefetch ends at end of last undefined string in string pool
348	uintptr_t end = stringTableStart;
349	if ( fDynamicInfo->nundefsym != 0 )
350		end += fSymbolTable[fDynamicInfo->iundefsym+fDynamicInfo->nundefsym-1].n_un.n_strx;
351	else if ( fDynamicInfo->nextdefsym != 0 )
352		end += fSymbolTable[fDynamicInfo->iextdefsym+fDynamicInfo->nextdefsym-1].n_un.n_strx;
353
354	// round to whole pages
355	start = start & (-4096);
356	end = (end + 4095) & (-4096);
357
358	// skip if there is only one page
359	if ( (end-start) > 4096 ) {
360		madvise((void*)start, end-start, MADV_WILLNEED);
361		fgTotalBytesPreFetched += (end-start);
362		if ( context.verboseMapping ) {
363			dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", "__LINKEDIT", start, end-1);
364		}
365	}
366}
367
368
369#if SPLIT_SEG_DYLIB_SUPPORT
370unsigned int
371ImageLoaderMachOClassic::getExtraZeroFillEntriesCount()
372{
373	// calculate mapping entries
374	unsigned int extraZeroFillEntries = 0;
375	for(unsigned int i=0; i < fSegmentsCount; ++i) {
376		if ( segHasTrailingZeroFill(i) )
377			++extraZeroFillEntries;
378	}
379
380	return extraZeroFillEntries;
381}
382
383void
384ImageLoaderMachOClassic::initMappingTable(uint64_t offsetInFat,
385								   shared_file_mapping_np *mappingTable)
386{
387	for(unsigned int i=0,entryIndex=0; i < fSegmentsCount; ++i, ++entryIndex) {
388		shared_file_mapping_np* entry = &mappingTable[entryIndex];
389		entry->sfm_address			= segActualLoadAddress(i);
390		entry->sfm_size				= segFileSize(i);
391		entry->sfm_file_offset		= segFileOffset(i) + offsetInFat;
392		entry->sfm_init_prot		= VM_PROT_NONE;
393		if ( !segUnaccessible(i) ) {
394			if ( segExecutable(i) )
395				entry->sfm_init_prot   |= VM_PROT_EXECUTE;
396			if ( segReadable(i) )
397				entry->sfm_init_prot   |= VM_PROT_READ;
398			if ( segWriteable(i) )
399				entry->sfm_init_prot   |= VM_PROT_WRITE | VM_PROT_COW;
400		}
401		entry->sfm_max_prot			= entry->sfm_init_prot;
402		if ( segHasTrailingZeroFill(i) ) {
403			shared_file_mapping_np* zfentry = &mappingTable[++entryIndex];
404			zfentry->sfm_address		= entry->sfm_address + segFileSize(i);
405			zfentry->sfm_size			= segSize(i) - segFileSize(i);
406			zfentry->sfm_file_offset	= 0;
407			zfentry->sfm_init_prot		= entry->sfm_init_prot | VM_PROT_COW | VM_PROT_ZF;
408			zfentry->sfm_max_prot		= zfentry->sfm_init_prot;
409		}
410	}
411}
412
413int
414ImageLoaderMachOClassic::mapSplitSegDylibOutsideSharedRegion(int fd,
415													uint64_t offsetInFat,
416													uint64_t lenInFat,
417													uint64_t fileLen,
418													const LinkContext& context)
419{
420	uintptr_t nextAltLoadAddress = 0;
421	const unsigned int segmentCount = fSegmentsCount;
422	const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
423	const unsigned int regionCount = segmentCount+extraZeroFillEntries;
424	shared_file_mapping_np regions[regionCount];
425	initMappingTable(offsetInFat, regions);
426	int r = -1;
427	// find space somewhere to allocate split seg
428	bool foundRoom = false;
429	while ( ! foundRoom ) {
430		foundRoom = true;
431		for(unsigned int i=0; i < regionCount; ++i) {
432			vm_address_t addr = nextAltLoadAddress + regions[i].sfm_address - regions[0].sfm_address;
433			vm_size_t size = regions[i].sfm_size ;
434			r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
435			if ( 0 != r ) {
436				// no room here, deallocate what has succeeded so far
437				for(unsigned int j=0; j < i; ++j) {
438					vm_address_t addr = nextAltLoadAddress + regions[j].sfm_address - regions[0].sfm_address;
439					vm_size_t size = regions[j].sfm_size ;
440					(void)vm_deallocate(mach_task_self(), addr, size);
441				}
442				nextAltLoadAddress += 0x00100000;  // skip ahead 1MB and try again
443				// skip over shared region
444				if ( (SHARED_REGION_BASE <= nextAltLoadAddress) && (nextAltLoadAddress < (SHARED_REGION_BASE + SHARED_REGION_SIZE)) )
445					nextAltLoadAddress = (SHARED_REGION_BASE + SHARED_REGION_SIZE);
446				if ( nextAltLoadAddress > 0xFF000000 )
447					throw "can't map split seg anywhere";
448				foundRoom = false;
449				break;
450			}
451		}
452	}
453
454	// map in each region
455	uintptr_t slide = nextAltLoadAddress - regions[0].sfm_address;
456	this->setSlide(slide);
457	for(unsigned int i=0; i < regionCount; ++i) {
458		if ( ((regions[i].sfm_init_prot & VM_PROT_ZF) != 0) || (regions[i].sfm_size == 0) ) {
459			// nothing to mmap for zero-fills areas, they are just vm_allocated
460		}
461		else {
462			void* mmapAddress = (void*)(uintptr_t)(regions[i].sfm_address + slide);
463			size_t size = regions[i].sfm_size;
464			int protection = 0;
465			if ( regions[i].sfm_init_prot & VM_PROT_EXECUTE )
466				protection   |= PROT_EXEC;
467			if ( regions[i].sfm_init_prot & VM_PROT_READ )
468				protection   |= PROT_READ;
469			if ( regions[i].sfm_init_prot & VM_PROT_WRITE )
470				protection   |= PROT_WRITE;
471			off_t offset = regions[i].sfm_file_offset;
472			//dyld::log("mmap(%p, 0x%08lX, %s\n", mmapAddress, size, fPath);
473			mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
474			if ( mmapAddress == ((void*)(-1)) )
475				throw "mmap error";
476		}
477	}
478
479	// logging
480	if ( context.verboseMapping ) {
481		dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath());
482		for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
483			const shared_file_mapping_np* entry = &regions[entryIndex];
484			if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 )
485				dyld::log("%18s at 0x%08lX->0x%08lX\n",
486						segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1);
487			if ( entryIndex < (regionCount-1) ) {
488				const shared_file_mapping_np* nextEntry = &regions[entryIndex+1];
489				if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) {
490					uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address;
491					dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
492							segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1));
493					++entryIndex;
494				}
495			}
496		}
497	}
498
499	return r;
500}
501#endif // SPLIT_SEG_DYLIB_SUPPORT
502
503
504void ImageLoaderMachOClassic::mapSegmentsClassic(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
505{
506	// non-split segment libraries handled by super class
507	if ( !fIsSplitSeg )
508		return ImageLoaderMachO::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
509
510#if SPLIT_SEG_SHARED_REGION_SUPPORT
511	// don't map split-seg dylibs into shared region if shared cache is in use
512	if ( ! context.dyldLoadedAtSameAddressNeededBySharedCache ) {
513		// try to map into shared region at preferred address
514		if ( mapSplitSegDylibInfoSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) == 0)
515			return;
516	}
517	// if there is a problem, fall into case where we map file somewhere outside the shared region
518#endif
519
520#if SPLIT_SEG_DYLIB_SUPPORT
521	// support old split-seg dylibs by mapping them where ever we find space
522	if ( mapSplitSegDylibOutsideSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) != 0 )
523#endif
524		throw "mapping error";
525}
526
527
528#if SPLIT_SEG_SHARED_REGION_SUPPORT
529static int _shared_region_map_np(int fd, uint32_t count, const shared_file_mapping_np mappings[])
530{
531	return syscall(295, fd, count, mappings);
532}
533
534int
535ImageLoaderMachOClassic::mapSplitSegDylibInfoSharedRegion(int fd,
536                                         uint64_t offsetInFat,
537                                         uint64_t lenInFat,
538                                         uint64_t fileLen,
539                                         const LinkContext& context)
540{
541	// build table of segments to map
542	const unsigned int segmentCount = fSegmentsCount;
543	const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
544	const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
545	shared_file_mapping_np mappingTable[mappingTableCount];
546	initMappingTable(offsetInFat, mappingTable);
547
548	// try to map it in shared
549	int r = _shared_region_map_np(fd, mappingTableCount, mappingTable);
550	if ( 0 == r ) {
551		this->setNeverUnload();
552		if ( context.verboseMapping ) {
553			dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath());
554			for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
555				const shared_file_mapping_np* entry = &mappingTable[entryIndex];
556				if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 )
557					dyld::log("%18s at 0x%08lX->0x%08lX\n",
558							  segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1);
559				if ( entryIndex < (mappingTableCount-1) ) {
560					const shared_file_mapping_np* nextEntry = &mappingTable[entryIndex+1];
561					if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) {
562						uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address;
563						dyld::log("%18s at 0x%08lX->0x%08lX\n",
564								  segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset),
565								  (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1));
566						++entryIndex;
567					}
568				}
569			}
570		}
571	}
572	return r;
573}
574
575#endif // SPLIT_SEG_SHARED_REGION_SUPPORT
576
577// test if this image is re-exported through parent (the image that loaded this one)
578bool ImageLoaderMachOClassic::isSubframeworkOf(const LinkContext& context, const ImageLoader* parent) const
579{
580	if ( fInUmbrella ) {
581		const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
582		const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
583		const struct load_command* cmd = cmds;
584		for (uint32_t i = 0; i < cmd_count; ++i) {
585			if (cmd->cmd == LC_SUB_FRAMEWORK) {
586				const struct sub_framework_command* subf = (struct sub_framework_command*)cmd;
587				const char* exportThruName = (char*)cmd + subf->umbrella.offset;
588				// need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
589				const char* parentInstallPath = parent->getInstallPath();
590				if ( parentInstallPath != NULL ) {
591					const char* lastSlash = strrchr(parentInstallPath, '/');
592					if ( lastSlash != NULL ) {
593						if ( strcmp(&lastSlash[1], exportThruName) == 0 )
594							return true;
595						if ( context.imageSuffix != NULL ) {
596							// when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
597							char reexportAndSuffix[strlen(context.imageSuffix)+strlen(exportThruName)+1];
598							strcpy(reexportAndSuffix, exportThruName);
599							strcat(reexportAndSuffix, context.imageSuffix);
600							if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 )
601								return true;
602						}
603					}
604				}
605			}
606			cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
607		}
608	}
609	return false;
610}
611
612// test if child is re-exported
613bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const
614{
615	if ( fHasSubLibraries ) {
616		// need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
617		const char* childInstallPath = child->getInstallPath();
618		if ( childInstallPath != NULL ) {
619			const char* lastSlash = strrchr(childInstallPath, '/');
620			if ( lastSlash != NULL ) {
621				const char* firstDot = strchr(lastSlash, '.');
622				int len;
623				if ( firstDot == NULL )
624					len = strlen(lastSlash);
625				else
626					len = firstDot-lastSlash-1;
627				char childLeafName[len+1];
628				strncpy(childLeafName, &lastSlash[1], len);
629				childLeafName[len] = '\0';
630				const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
631				const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
632				const struct load_command* cmd = cmds;
633				for (uint32_t i = 0; i < cmd_count; ++i) {
634					switch (cmd->cmd) {
635						case LC_SUB_LIBRARY:
636							{
637								const struct sub_library_command* lib = (struct sub_library_command*)cmd;
638								const char* aSubLibName = (char*)cmd + lib->sub_library.offset;
639								if ( strcmp(aSubLibName, childLeafName) == 0 )
640									return true;
641								if ( context.imageSuffix != NULL ) {
642									// when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
643									char aSubLibNameAndSuffix[strlen(context.imageSuffix)+strlen(aSubLibName)+1];
644									strcpy(aSubLibNameAndSuffix, aSubLibName);
645									strcat(aSubLibNameAndSuffix, context.imageSuffix);
646									if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 )
647										return true;
648								}
649							}
650							break;
651					}
652					cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
653				}
654			}
655		}
656	}
657	if ( fHasSubUmbrella ) {
658		// need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
659		const char* childInstallPath = child->getInstallPath();
660		if ( childInstallPath != NULL ) {
661			const char* lastSlash = strrchr(childInstallPath, '/');
662			if ( lastSlash != NULL ) {
663				const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
664				const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
665				const struct load_command* cmd = cmds;
666				for (uint32_t i = 0; i < cmd_count; ++i) {
667					switch (cmd->cmd) {
668						case LC_SUB_UMBRELLA:
669							{
670								const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd;
671								const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset;
672								if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 )
673									return true;
674								if ( context.imageSuffix != NULL ) {
675									// when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
676									char umbrellaAndSuffix[strlen(context.imageSuffix)+strlen(aSubUmbrellaName)+1];
677									strcpy(umbrellaAndSuffix, aSubUmbrellaName);
678									strcat(umbrellaAndSuffix, context.imageSuffix);
679									if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 )
680										return true;
681								}
682							}
683							break;
684					}
685					cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
686				}
687			}
688		}
689	}
690	return false;
691}
692
693
694uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress()
695{
696	// in split segment libraries r_address is offset from first writable segment
697	for(unsigned int i=0; i < fSegmentsCount; ++i) {
698		if ( segWriteable(i) )
699			return segActualLoadAddress(i);
700	}
701	throw "no writable segment";
702}
703
704uintptr_t ImageLoaderMachOClassic::getRelocBase()
705{
706	// r_address is either an offset from the first segment address
707	// or from the first writable segment address
708#if __x86_64__
709	return getFirstWritableSegmentAddress();
710#else
711	if ( fIsSplitSeg )
712		return getFirstWritableSegmentAddress();
713	else
714		return segActualLoadAddress(0);
715#endif
716}
717
718
719#if PREBOUND_IMAGE_SUPPORT
720void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& context)
721{
722	// loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
723	const uintptr_t relocBase = this->getRelocBase();
724	register const uintptr_t slide = this->fSlide;
725	const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
726	const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
727	for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
728		if ( (reloc->r_address & R_SCATTERED) != 0 ) {
729			const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
730			if (sreloc->r_length == RELOC_SIZE) {
731				uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
732				switch(sreloc->r_type) {
733		#if __i386__
734					case GENERIC_RELOC_PB_LA_PTR:
735						*locationToFix = sreloc->r_value + slide;
736						break;
737		#endif
738		#if __arm__
739					case ARM_RELOC_PB_LA_PTR:
740						*locationToFix = sreloc->r_value + slide;
741						break;
742		#endif
743				}
744			}
745		}
746	}
747}
748#endif
749
750
751
752
753void ImageLoaderMachOClassic::rebase(const LinkContext& context)
754{
755	CRSetCrashLogMessage2(this->getPath());
756	register const uintptr_t slide = this->fSlide;
757	const uintptr_t relocBase = this->getRelocBase();
758
759	// prefetch any LINKEDIT pages needed
760	if ( !context.preFetchDisabled && !this->isPrebindable())
761		this->prefetchLINKEDIT(context);
762
763	// loop through all local (internal) relocation records
764	const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
765	const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
766	for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
767		uintptr_t rebaseAddr;
768		try {
769	#if LINKEDIT_USAGE_DEBUG
770			noteAccessedLinkEditAddress(reloc);
771	#endif
772		#if __x86_64__
773			// only one kind of local relocation supported for x86_64
774			if ( reloc->r_length != 3 )
775				throw "bad local relocation length";
776			if ( reloc->r_type != X86_64_RELOC_UNSIGNED )
777				throw "unknown local relocation type";
778			if ( reloc->r_pcrel != 0 )
779				throw "bad local relocation pc_rel";
780			if ( reloc->r_extern != 0 )
781				throw "extern relocation found with local relocations";
782			rebaseAddr = reloc->r_address + relocBase;
783			if ( ! this->containsAddress((void*)rebaseAddr) )
784				dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
785			*((uintptr_t*)rebaseAddr) += slide;
786			if ( context.verboseRebase )
787				dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
788		#else
789			if ( (reloc->r_address & R_SCATTERED) == 0 ) {
790				if ( reloc->r_symbolnum == R_ABS ) {
791					// ignore absolute relocations
792				}
793				else if (reloc->r_length == RELOC_SIZE) {
794					switch(reloc->r_type) {
795						case GENERIC_RELOC_VANILLA:
796							rebaseAddr = reloc->r_address + relocBase;
797							if ( ! this->containsAddress((void*)rebaseAddr) )
798								dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr);
799							*((uintptr_t*)rebaseAddr) += slide;
800							if ( context.verboseRebase )
801								dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide);
802							break;
803						default:
804							throw "unknown local relocation type";
805					}
806				}
807				else {
808					throw "bad local relocation length";
809				}
810			}
811			else {
812				const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
813				if (sreloc->r_length == RELOC_SIZE) {
814					uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
815					switch(sreloc->r_type) {
816						case GENERIC_RELOC_VANILLA:
817							if ( ! this->containsAddress((void*)locationToFix) )
818								dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix);
819							*locationToFix += slide;
820							if ( context.verboseRebase )
821								dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix, slide);
822							break;
823			#if __i386__
824						case GENERIC_RELOC_PB_LA_PTR:
825							// do nothing
826							break;
827			#elif __arm__
828						case ARM_RELOC_PB_LA_PTR:
829							// do nothing
830							break;
831			#endif
832						default:
833							throw "unknown local scattered relocation type";
834					}
835				}
836				else {
837					throw "bad local scattered relocation length";
838				}
839			}
840		#endif // x86_64
841		}
842		catch (const char* msg) {
843			const uint8_t* r = (uint8_t*)reloc;
844			dyld::throwf("%s in %s. reloc record at %p: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
845				msg, this->getPath(), reloc, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
846		}
847	}
848
849	// update stats
850	fgTotalRebaseFixups += fDynamicInfo->nlocrel;
851	CRSetCrashLogMessage2(NULL);
852}
853
854
855
856const struct macho_nlist* ImageLoaderMachOClassic::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[],
857												const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const
858{
859	int32_t high = symbolCount-1;
860	int32_t mid = hintIndex;
861
862	// handle out of range hint
863	if ( mid >= (int32_t)symbolCount )
864		mid = symbolCount/2;
865	++ImageLoaderMachO::fgSymbolTableBinarySearchs;
866	++fgTotalBindImageSearches;
867
868	//dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName());
869
870	for (int32_t low = 0; low <= high; mid = (low+high)/2) {
871		const uint32_t index = toc[mid].symbol_index;
872		const struct macho_nlist* pivot = &symbols[index];
873		const char* pivotStr = &stringPool[pivot->n_un.n_strx];
874#if LINKEDIT_USAGE_DEBUG
875		noteAccessedLinkEditAddress(&toc[mid]);
876		noteAccessedLinkEditAddress(pivot);
877		noteAccessedLinkEditAddress(pivotStr);
878#endif
879		int cmp = strcmp(key, pivotStr);
880		if ( cmp == 0 )
881			return pivot;
882		if ( cmp > 0 ) {
883			// key > pivot
884			low = mid + 1;
885		}
886		else {
887			// key < pivot
888			high = mid - 1;
889		}
890	}
891	return NULL;
892}
893
894const struct macho_nlist* ImageLoaderMachOClassic::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const
895{
896	// update stats
897	++fgTotalBindImageSearches;
898	++ImageLoaderMachO::fgSymbolTableBinarySearchs;
899
900	//dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n",
901	//				key, this->getShortName(), stringPool, symbols, symbolCount);
902
903	const struct macho_nlist* base = symbols;
904	for (uint32_t n = symbolCount; n > 0; n /= 2) {
905		const struct macho_nlist* pivot = &base[n/2];
906		const char* pivotStr = &stringPool[pivot->n_un.n_strx];
907#if LINKEDIT_USAGE_DEBUG
908		noteAccessedLinkEditAddress(pivot);
909		noteAccessedLinkEditAddress(pivotStr);
910#endif
911		int cmp = strcmp(key, pivotStr);
912		if ( cmp == 0 )
913			return pivot;
914		if ( cmp > 0 ) {
915			// key > pivot
916			// move base to symbol after pivot
917			base = &pivot[1];
918			--n;
919		}
920		else {
921			// key < pivot
922			// keep same base
923		}
924	}
925	return NULL;
926}
927
928
929const ImageLoader::Symbol* ImageLoaderMachOClassic::findExportedSymbol(const char* name, const ImageLoader** foundIn) const
930{
931	const struct macho_nlist* sym = NULL;
932	if ( fDynamicInfo->tocoff == 0 )
933		sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym);
934	else
935		sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff],
936										fDynamicInfo->ntoc, fDynamicInfo->nextdefsym);
937	if ( sym != NULL ) {
938		if ( foundIn != NULL )
939			*foundIn = (ImageLoader*)this;
940		return (const Symbol*)sym;
941	}
942	return NULL;
943}
944
945
946
947bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
948{
949	return ( (fSymbolTable <= addr) && (addr < fStrings) );
950}
951
952
953uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
954{
955	const struct macho_nlist* sym = (macho_nlist*)symbol;
956	uintptr_t result = sym->n_value + fSlide;
957	#if __arm__
958		// processor assumes code address with low bit set is thumb
959		if (sym->n_desc & N_ARM_THUMB_DEF)
960			result |= 1;
961	#endif
962	return result;
963}
964
965bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
966{
967	const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
968	return ( (nlistSym->n_desc & N_WEAK_DEF) != 0 );
969}
970
971const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol* symbol) const
972{
973	const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
974	return &fStrings[nlistSym->n_un.n_strx];
975}
976
977unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const
978{
979	return fDynamicInfo->nextdefsym;
980}
981
982const ImageLoader::Symbol* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index) const
983{
984	if ( index < fDynamicInfo->nextdefsym ) {
985		const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index];
986		return (const ImageLoader::Symbol*)sym;
987	}
988	return NULL;
989}
990
991unsigned int ImageLoaderMachOClassic::importedSymbolCount() const
992{
993	return fDynamicInfo->nundefsym;
994}
995
996const ImageLoader::Symbol* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index) const
997{
998	if ( index < fDynamicInfo->nundefsym ) {
999		const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index];
1000		return (const ImageLoader::Symbol*)sym;
1001	}
1002	return NULL;
1003}
1004
1005const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol* symbol) const
1006{
1007	const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
1008	return &fStrings[nlistSym->n_un.n_strx];
1009}
1010
1011
1012
1013bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist* symbol)
1014{
1015	// if a define and weak ==> coalesced
1016	if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) )
1017		return true;
1018
1019	// regular symbol
1020	return false;
1021}
1022
1023bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* symbol)
1024{
1025	// if an undefine and not referencing a weak symbol ==> coalesced
1026	if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) )
1027		return true;
1028
1029	// regular symbol
1030	return false;
1031}
1032
1033uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context, bool runResolver) const
1034{
1035	return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context, runResolver);
1036}
1037
1038uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol,
1039										bool twoLevel, bool dontCoalesce, const ImageLoader** foundIn)
1040{
1041	++fgTotalBindSymbolsResolved;
1042	const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
1043
1044#if LINKEDIT_USAGE_DEBUG
1045	noteAccessedLinkEditAddress(undefinedSymbol);
1046	noteAccessedLinkEditAddress(symbolName);
1047#endif
1048	if ( context.bindFlat || !twoLevel ) {
1049		// flat lookup
1050		if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
1051			// is a multi-module private_extern internal reference that the linker did not optimize away
1052			uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
1053			*foundIn = this;
1054			return addr;
1055		}
1056		const Symbol* sym;
1057		if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
1058			if ( *foundIn != this )
1059				context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
1060			return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1061		}
1062		// if a bundle is loaded privately the above will not find its exports
1063		if ( this->isBundle() && this->hasHiddenExports() ) {
1064			// look in self for needed symbol
1065			sym = this->findExportedSymbol(symbolName, foundIn);
1066			if ( sym != NULL )
1067				return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1068		}
1069		if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
1070			// definition can't be found anywhere
1071			// if reference is weak_import, then it is ok, just return 0
1072			return 0;
1073		}
1074		throwSymbolNotFound(context, symbolName, this->getPath(), "flat namespace");
1075	}
1076	else {
1077		// symbol requires searching images with coalesced symbols (not done during prebinding)
1078		if ( !context.prebinding && !dontCoalesce && (symbolIsWeakReference(undefinedSymbol) || symbolIsWeakDefinition(undefinedSymbol)) ) {
1079			const Symbol* sym;
1080			if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) {
1081				if ( *foundIn != this )
1082					context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
1083				return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1084			}
1085			//throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace");
1086			//dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1087		}
1088
1089		// if this is a real definition (not an undefined symbol) there is no ordinal
1090		if ( (undefinedSymbol->n_type & N_TYPE) == N_SECT ) {
1091			// static linker should never generate this case, but if it does, do something sane
1092			uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
1093			*foundIn = this;
1094			return addr;
1095		}
1096
1097		// two level lookup
1098		ImageLoader* target = NULL;
1099		uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc);
1100		if ( ord == EXECUTABLE_ORDINAL ) {
1101			target = context.mainExecutable;
1102		}
1103		else if ( ord == SELF_LIBRARY_ORDINAL ) {
1104			target = this;
1105		}
1106		else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) {
1107			// rnielsen: HACKHACK
1108			// flat lookup
1109			const Symbol* sym;
1110			if ( context.flatExportFinder(symbolName, &sym, foundIn) )
1111				return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1112			// no image has exports this symbol
1113			// report error
1114			context.undefinedHandler(symbolName);
1115			// try looking again
1116			if ( context.flatExportFinder(symbolName, &sym, foundIn) )
1117				return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1118
1119			throwSymbolNotFound(context, symbolName, this->getPath(), "dynamic lookup");
1120		}
1121		else if ( ord <= libraryCount() ) {
1122			target = libImage(ord-1);
1123			if ( target == NULL ) {
1124				// if target library not loaded and reference is weak or library is weak return 0
1125				return 0;
1126			}
1127		}
1128		else {
1129			dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
1130				ord, libraryCount(), symbolName, this->getPath());
1131		}
1132
1133		if ( target == NULL ) {
1134			//dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
1135			throw "symbol not found";
1136		}
1137
1138		const Symbol* sym = target->findExportedSymbol(symbolName, true, foundIn);
1139		if ( sym!= NULL ) {
1140			return (*foundIn)->getExportedSymbolAddress(sym, context, this);
1141		}
1142		else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
1143			// don't know why the static linker did not eliminate the internal reference to a private extern definition
1144			*foundIn = this;
1145			return this->getSymbolAddress(undefinedSymbol, context, false);
1146		}
1147		else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
1148			// if definition not found and reference is weak return 0
1149			return 0;
1150		}
1151
1152		// nowhere to be found
1153		throwSymbolNotFound(context, symbolName, this->getPath(), target->getPath());
1154	}
1155}
1156
1157
1158
1159// returns if 'addr' is within the address range of section 'sectionIndex'
1160// fSlide is not used.  'addr' is assumed to be a prebound address in this image
1161bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr, uint8_t sectionIndex)
1162{
1163	uint8_t currentSectionIndex = 1;
1164	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1165	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1166	const struct load_command* cmd = cmds;
1167	for (uint32_t i = 0; i < cmd_count; ++i) {
1168		if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1169			const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1170			if ( (currentSectionIndex <= sectionIndex) && (sectionIndex < currentSectionIndex+seg->nsects) ) {
1171				// 'sectionIndex' is in this segment, get section info
1172				const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1173				const struct macho_section* const section = &sectionsStart[sectionIndex-currentSectionIndex];
1174				return ( (section->addr <= addr) && (addr < section->addr+section->size) );
1175			}
1176			else {
1177				// 'sectionIndex' not in this segment, skip to next segment
1178				currentSectionIndex += seg->nsects;
1179			}
1180		}
1181		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1182	}
1183
1184	return false;
1185}
1186
1187void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext& context)
1188{
1189	const uintptr_t relocBase = this->getRelocBase();
1190	const bool twoLevel = this->usesTwoLevelNameSpace();
1191	const bool prebound = this->isPrebindable();
1192
1193#if TEXT_RELOC_SUPPORT
1194	// if there are __TEXT fixups, temporarily make __TEXT writable
1195	if ( fTextSegmentBinds )
1196		this->makeTextSegmentWritable(context, true);
1197#endif
1198	// cache last lookup
1199	const struct macho_nlist*	lastUndefinedSymbol = NULL;
1200	uintptr_t					symbolAddr = 0;
1201	const ImageLoader*			image = NULL;
1202
1203	// loop through all external relocation records and bind each
1204	const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1205	const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1206	for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1207		if (reloc->r_length == RELOC_SIZE) {
1208			switch(reloc->r_type) {
1209				case POINTER_RELOC:
1210					{
1211						const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
1212						uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
1213						if ( ! this->containsAddress((void*)location) )
1214							dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location, this->getPath());
1215						uintptr_t value = *location;
1216						bool symbolAddrCached = true;
1217					#if __i386__
1218						if ( reloc->r_pcrel ) {
1219							value += (uintptr_t)location + 4 - fSlide;
1220						}
1221					#endif
1222						if ( prebound ) {
1223							// we are doing relocations, so prebinding was not usable
1224							// in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1225							// so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1226							// if mach-o relocation structs had an "addend" field this complication would not be necessary.
1227							if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1228								// weak symbols need special casing, since *location may have been prebound to a definition in another image.
1229								// If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1230								// that we can subtract off the weak symbol address to get the addend.
1231								// If prebound elsewhere, we've lost the addend and have to assume it is zero.
1232								// The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1233								if ( (value == undefinedSymbol->n_value) || this->isAddrInSection(value, undefinedSymbol->n_sect) ) {
1234									value -= undefinedSymbol->n_value;
1235                        #if __arm__
1236                                    // if weak and thumb subtract off extra thumb bit
1237                                    if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1238                                        value -= 1;
1239                        #endif
1240								}
1241								else
1242									value = 0;
1243							}
1244					#if __arm__
1245							else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
1246								// it was prebound to a defined symbol for thumb code in the same linkage unit
1247								// we need to subtract off one to get real addend
1248								value -= (undefinedSymbol->n_value+1);
1249							}
1250					#endif
1251							else {
1252								// is undefined or non-weak symbol, so do subtraction to get addend
1253								value -= undefinedSymbol->n_value;
1254							}
1255						}
1256						// if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1257						if ( undefinedSymbol != lastUndefinedSymbol ) {
1258							bool dontCoalesce = true;
1259							if ( symbolIsWeakReference(undefinedSymbol) ) {
1260								// when weakbind() is run on a classic mach-o encoding, it won't try
1261								// to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
1262								// range of global symbols.  To handle that case we do the coalesing now.
1263								dontCoalesce = false;
1264							}
1265							symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, dontCoalesce, &image);
1266							lastUndefinedSymbol = undefinedSymbol;
1267							symbolAddrCached = false;
1268						}
1269						if ( context.verboseBind ) {
1270							const char *path = NULL;
1271							if ( image != NULL ) {
1272								path = image->getShortName();
1273							}
1274							const char* cachedString = "(cached)";
1275							if ( !symbolAddrCached )
1276								cachedString = "";
1277							if ( value == 0 ) {
1278								dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n",
1279										this->getShortName(), (uintptr_t)location,
1280										path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString);
1281							}
1282							else {
1283								dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n",
1284										this->getShortName(), (uintptr_t)location,
1285										path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value);
1286							}
1287						}
1288						value += symbolAddr;
1289					#if __i386__
1290						if ( reloc->r_pcrel ) {
1291							*location = value - ((uintptr_t)location + 4);
1292						}
1293						else {
1294							// don't dirty page if prebound value was correct
1295							if ( !prebound || (*location != value) )
1296								*location = value;
1297						}
1298					#else
1299						// don't dirty page if prebound value was correct
1300						if ( !prebound || (*location != value) )
1301							*location = value;
1302					#endif
1303						// update stats
1304						++fgTotalBindFixups;
1305					}
1306					break;
1307				default:
1308					throw "unknown external relocation type";
1309			}
1310		}
1311		else {
1312			throw "bad external relocation length";
1313		}
1314	}
1315
1316#if TEXT_RELOC_SUPPORT
1317	// if there were __TEXT fixups, restore write protection
1318	if ( fTextSegmentBinds ) {
1319		this->makeTextSegmentWritable(context, true);
1320	}
1321#endif
1322}
1323
1324
1325
1326uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context)
1327{
1328	if ( context.verboseBind ) {
1329		const char* path = NULL;
1330		if ( targetImage != NULL )
1331			path = targetImage->getShortName();
1332		dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
1333				this->getShortName(), symbolName, (((sect->flags & SECTION_TYPE)==S_NON_LAZY_SYMBOL_POINTERS) ? "non_lazy_ptr" : "lazy_ptr"),
1334				((path != NULL) ? path : "<weak_import-not-found>"), symbolName, (uintptr_t)ptrToBind, targetAddr);
1335	}
1336	if ( context.bindingHandler != NULL ) {
1337		const char* path = NULL;
1338		if ( targetImage != NULL )
1339			path = targetImage->getShortName();
1340		targetAddr = (uintptr_t)context.bindingHandler(path, symbolName, (void *)targetAddr);
1341	}
1342#if __i386__
1343	// i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
1344	if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
1345		uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5);
1346		// re-write instruction in a thread-safe manner
1347		// use 8-byte compare-and-swap to alter 5-byte jump table entries
1348		// loop is required in case the extra three bytes that cover the next entry are altered by another thread
1349		bool done = false;
1350		while ( !done ) {
1351			volatile int64_t* jumpPtr = (int64_t*)ptrToBind;
1352			int pad = 0;
1353			// By default the three extra bytes swapped follow the 5-byte JMP.
1354			// But, if the 5-byte jump is up against the end of the __IMPORT segment
1355			// We don't want to access bytes off the end of the segment, so we shift
1356			// the extra bytes to precede the 5-byte JMP.
1357			if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) {
1358				jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3);
1359				pad = 3;
1360			}
1361			int64_t oldEntry = *jumpPtr;
1362			union {
1363				int64_t int64;
1364				uint8_t bytes[8];
1365			} newEntry;
1366			newEntry.int64 = oldEntry;
1367			newEntry.bytes[pad+0] = 0xE9; // JMP rel32
1368			newEntry.bytes[pad+1] = rel32 & 0xFF;
1369			newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF;
1370			newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF;
1371			newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF;
1372			done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr);
1373		}
1374	}
1375	else
1376#endif
1377	*ptrToBind = targetAddr;
1378	return targetAddr;
1379}
1380
1381uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)())
1382{
1383	throw "compressed LINKEDIT lazy binder called with classic LINKEDIT";
1384}
1385
1386uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
1387{
1388	// scan for all lazy-pointer sections
1389	const bool twoLevel = this->usesTwoLevelNameSpace();
1390	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1391	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1392	const struct load_command* cmd = cmds;
1393	const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1394	for (uint32_t i = 0; i < cmd_count; ++i) {
1395		switch (cmd->cmd) {
1396			case LC_SEGMENT_COMMAND:
1397				{
1398					const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1399					const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1400					const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1401					for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1402						const uint8_t type = sect->flags & SECTION_TYPE;
1403						uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
1404						if ( type == S_LAZY_SYMBOL_POINTERS ) {
1405							const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
1406							uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1407							if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
1408								const uint32_t indirectTableOffset = sect->reserved1;
1409								const uint32_t lazyIndex = lazyPointer - symbolPointers;
1410								symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
1411							}
1412						}
1413					#if __i386__
1414						else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1415							// 5 bytes stubs on i386 are new "fast stubs"
1416							uint8_t* const jmpTableBase = (uint8_t*)(sect->addr + fSlide);
1417							uint8_t* const jmpTableEnd = jmpTableBase + sect->size;
1418							// initial CALL instruction in jump table leaves pointer to next entry, so back up
1419							uint8_t* const jmpTableEntryToPatch = ((uint8_t*)lazyPointer) - 5;
1420							lazyPointer = (uintptr_t*)jmpTableEntryToPatch;
1421							if ( (jmpTableEntryToPatch >= jmpTableBase) && (jmpTableEntryToPatch < jmpTableEnd) ) {
1422								const uint32_t indirectTableOffset = sect->reserved1;
1423								const uint32_t entryIndex = (jmpTableEntryToPatch - jmpTableBase)/5;
1424								symbolIndex = indirectTable[indirectTableOffset + entryIndex];
1425							}
1426						}
1427					#endif
1428						if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
1429							const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
1430							const ImageLoader* image = NULL;
1431							uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], twoLevel, false, &image);
1432							symbolAddr = this->bindIndirectSymbol(lazyPointer, sect, symbolName, symbolAddr, image,  context);
1433							++fgTotalLazyBindFixups;
1434							return symbolAddr;
1435						}
1436					}
1437				}
1438				break;
1439		}
1440		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1441	}
1442	dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
1443}
1444
1445
1446
1447void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder)
1448{
1449	it.image = this;
1450	it.symbolName = " ";
1451	it.loadOrder = loadOrder;
1452	it.weakSymbol = false;
1453	it.symbolMatches = false;
1454	it.done = false;
1455	it.type = 0;
1456	if ( fDynamicInfo->tocoff != 0 ) {
1457		it.curIndex = 0;
1458		it.endIndex = fDynamicInfo->ntoc;
1459	}
1460	else {
1461		it.curIndex = 0;
1462		it.endIndex = fDynamicInfo->nextdefsym;
1463	}
1464}
1465
1466
1467bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator& it)
1468{
1469	if ( it.done )
1470		return false;
1471
1472	if ( fDynamicInfo->tocoff != 0 ) {
1473		if ( it.curIndex >= fDynamicInfo->ntoc ) {
1474			it.done = true;
1475			it.symbolName = "~~~";
1476			return true;
1477		}
1478		else {
1479			const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1480			const uint32_t index = toc[it.curIndex].symbol_index;
1481			const struct macho_nlist* sym = &fSymbolTable[index];
1482			const char* symStr = &fStrings[sym->n_un.n_strx];
1483			it.symbolName = symStr;
1484			it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
1485			it.symbolMatches = false;
1486			it.type = 0; // clear flag that says we applied updates for this symbol
1487			//dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
1488			it.curIndex++;
1489			return false;
1490		}
1491	}
1492	else {
1493		if ( it.curIndex >= fDynamicInfo->nextdefsym ) {
1494			it.done = true;
1495			it.symbolName = "~~~";
1496			return true;
1497		}
1498		else {
1499			const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym+it.curIndex];
1500			const char* symStr = &fStrings[sym->n_un.n_strx];
1501			it.symbolName = symStr;
1502			it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
1503			it.symbolMatches = false;
1504			it.type = 0; // clear flag that says we applied updates for this symbol
1505			//dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
1506			it.curIndex++;
1507			return false;
1508		}
1509	}
1510
1511	return false;
1512}
1513
1514uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
1515{
1516	uint32_t symbol_index = 0;
1517	if ( fDynamicInfo->tocoff != 0 ) {
1518		const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1519		symbol_index = toc[it.curIndex-1].symbol_index;
1520	}
1521	else {
1522		symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1;
1523	}
1524	const struct macho_nlist* sym = &fSymbolTable[symbol_index];
1525	//dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath());
1526#if __arm__
1527		// processor assumes code address with low bit set is thumb
1528		if (sym->n_desc & N_ARM_THUMB_DEF)
1529			return (sym->n_value | 1) + fSlide ;
1530		else
1531			return sym->n_value + fSlide;
1532#else
1533	return sym->n_value + fSlide;
1534#endif
1535}
1536
1537
1538void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context)
1539{
1540	// flat_namespace images with classic LINKEDIT do not need late coalescing.
1541	// They still need to be iterated becuase they may implement
1542	// something needed by other coalescing images.
1543	// But they need no updating because during the bind phase every symbol lookup is a full scan.
1544	if ( !this->usesTwoLevelNameSpace() )
1545		return;
1546
1547	// <rdar://problem/6570879> weak binding done too early with inserted libraries
1548	if ( this->getState() < dyld_image_state_bound  )
1549		return;
1550
1551	uint32_t symbol_index = 0;
1552	if ( fDynamicInfo->tocoff != 0 ) {
1553		const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
1554		symbol_index = toc[it.curIndex-1].symbol_index;
1555	}
1556	else {
1557		symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1;
1558	}
1559
1560	// if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here
1561	if ( !symbolIsWeakReference(&fSymbolTable[symbol_index]) && !symbolIsWeakDefinition(&fSymbolTable[symbol_index]) ) {
1562		return;
1563	}
1564
1565	// <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding
1566	if ( it.type )
1567		return;
1568
1569	bool boundSomething = false;
1570	// scan external relocations for uses of symbol_index
1571	const uintptr_t relocBase = this->getRelocBase();
1572	const bool prebound = this->isPrebindable();
1573	const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
1574	const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
1575	for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
1576		if ( reloc->r_symbolnum == symbol_index ) {
1577			//dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath());
1578			const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
1579			const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
1580			uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
1581			const uintptr_t initialValue = *location;
1582			uintptr_t addend = 0;
1583			if ( prebound ) {
1584				// we are doing relocations, so prebinding was not usable
1585				// in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1586				// so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1587				// if mach-o relocation structs had an "addend" field this complication would not be necessary.
1588				if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1589					// weak symbols need special casing, since *location may have been prebound to a definition in another image.
1590					// If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1591					// that we can subtract off the weak symbol address to get the addend.
1592					// If prebound elsewhere, we've lost the addend and have to assume it is zero.
1593					// The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1594					if ( (initialValue == undefinedSymbol->n_value) || this->isAddrInSection(initialValue, undefinedSymbol->n_sect) ) {
1595						addend = initialValue - undefinedSymbol->n_value;
1596			#if __arm__
1597						// if weak and thumb subtract off extra thumb bit
1598						if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1599							addend &= -2;
1600			#endif
1601					}
1602				}
1603		#if __arm__
1604				else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
1605					// it was prebound to a defined symbol for thumb code in the same linkage unit
1606					// we need to subtract off one to get real addend
1607					addend = initialValue - (undefinedSymbol->n_value+1);
1608				}
1609		#endif
1610				else {
1611					// is undefined or non-weak symbol, so do subtraction to get addend
1612					addend = initialValue - undefinedSymbol->n_value;
1613				}
1614			}
1615			else {
1616				// non-prebound case
1617				if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
1618					// if target is weak-def in same linkage unit, then bind phase has already set initialValue
1619					// to be definition address plus addend
1620					//dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide);
1621					addend = initialValue - (undefinedSymbol->n_value + fSlide);
1622		#if __arm__
1623					// if weak and thumb subtract off extra thumb bit
1624					if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
1625						addend &= -2;
1626		#endif
1627				}
1628				else {
1629					// nothing fixed up yet, addend is just initial value
1630					//dyld::log("addend=0x%lX\n", initialValue);
1631					addend = initialValue;
1632				}
1633			}
1634
1635			uint8_t type = BIND_TYPE_POINTER;
1636		#if __i386__
1637			if ( reloc->r_pcrel )
1638				type = BIND_TYPE_TEXT_PCREL32;
1639		#endif
1640			this->bindLocation(context, (uintptr_t)location, value, targetImage, type, symbolName, addend, "weak ");
1641			boundSomething = true;
1642		}
1643	}
1644
1645	// scan lazy and non-lazy pointers for uses of symbol_index
1646	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1647	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1648	const struct load_command* cmd = cmds;
1649	const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1650	for (uint32_t i = 0; i < cmd_count; ++i) {
1651		if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
1652			const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1653			const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1654			const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1655			for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1656				uint32_t elementSize = sizeof(uintptr_t);
1657				switch ( sect->flags & SECTION_TYPE ) {
1658				#if __i386__
1659					case S_SYMBOL_STUBS:
1660						if ( ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) ==0) || (sect->reserved2 != 5) )
1661							continue;
1662						elementSize = 5;
1663				#endif
1664					case S_NON_LAZY_SYMBOL_POINTERS:
1665					case S_LAZY_SYMBOL_POINTERS:
1666					{
1667						uint32_t elementCount = sect->size / elementSize;
1668						const uint32_t indirectTableOffset = sect->reserved1;
1669						uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
1670						//dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind);
1671						for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
1672							if ( indirectTable[indirectTableOffset + j] == symbol_index ) {
1673								//dyld::log("  found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind);
1674								// update pointer
1675								this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, it.symbolName, value, targetImage, context);
1676								boundSomething = true;
1677							}
1678						}
1679					}
1680					break;
1681				}
1682			}
1683		}
1684		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1685	}
1686	if ( boundSomething && (targetImage != this) ) {
1687		context.addDynamicReference(this, targetImage);
1688	}
1689
1690	// mark that this symbol has already been bound, so we don't try to bind again
1691	it.type = 1;
1692}
1693
1694
1695void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys)
1696{
1697	// scan for all non-lazy-pointer sections
1698	const bool twoLevel = this->usesTwoLevelNameSpace();
1699	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1700	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1701	const struct load_command* cmd = cmds;
1702	const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1703	for (uint32_t i = 0; i < cmd_count; ++i) {
1704		switch (cmd->cmd) {
1705			case LC_SEGMENT_COMMAND:
1706				{
1707					const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1708					const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1709					const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1710					for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1711						bool isLazySymbol = false;
1712						const uint8_t type = sect->flags & SECTION_TYPE;
1713						uint32_t elementSize = sizeof(uintptr_t);
1714						uint32_t elementCount = sect->size / elementSize;
1715						if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
1716							if ( ! bindNonLazys )
1717								continue;
1718						}
1719						else if ( type == S_LAZY_SYMBOL_POINTERS ) {
1720							// process each symbol pointer in this section
1721							fgTotalPossibleLazyBindFixups += elementCount;
1722							isLazySymbol = true;
1723							if ( ! bindLazys )
1724								continue;
1725						}
1726				#if __i386__
1727						else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1728							// process each jmp entry in this section
1729							elementCount = sect->size / 5;
1730							elementSize = 5;
1731							fgTotalPossibleLazyBindFixups += elementCount;
1732							isLazySymbol = true;
1733							if ( ! bindLazys )
1734								continue;
1735						}
1736				#endif
1737						else {
1738							continue;
1739						}
1740						const uint32_t indirectTableOffset = sect->reserved1;
1741						uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
1742						for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
1743				#if LINKEDIT_USAGE_DEBUG
1744							noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]);
1745				#endif
1746							uint32_t symbolIndex = indirectTable[indirectTableOffset + j];
1747							if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) {
1748								*((uintptr_t*)ptrToBind) += this->fSlide;
1749							}
1750							else if ( symbolIndex == INDIRECT_SYMBOL_ABS) {
1751								// do nothing since already has absolute address
1752							}
1753							else {
1754								const struct macho_nlist* sym = &fSymbolTable[symbolIndex];
1755								if ( symbolIndex == 0 ) {
1756									// This could be rdar://problem/3534709
1757									if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) {
1758										static bool alreadyWarned = false;
1759										if ( (sym->n_type & N_TYPE) != N_UNDF ) {
1760											// The indirect table parallels the (non)lazy pointer sections.  For
1761											// instance, to find info about the fifth lazy pointer you look at the
1762											// fifth entry in the indirect table.  (try otool -Iv on a file).
1763											// The entry in the indirect table contains an index into the symbol table.
1764
1765											// The bug in ld caused the entry in the indirect table to be zero
1766											// (instead of a magic value that means a local symbol).  So, if the
1767											// symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
1768											// symbol table index. The check I put in place is to see if the zero'th
1769											// symbol table entry is an import entry (usually it is a local symbol
1770											// definition).
1771											if ( context.verboseWarnings && !alreadyWarned ) {
1772												dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
1773														this->getPath(), &fStrings[sym->n_un.n_strx]);
1774												alreadyWarned = true;
1775											}
1776											continue;
1777										}
1778									}
1779								}
1780								const ImageLoader* image = NULL;
1781								// let weak definitions resolve to themselves, later coalescing may overwrite them
1782								bool dontCoalesce = true;
1783								if ( bindLazys && isLazySymbol ) {
1784									// if this is something normally lazy bound, but we are forcing
1785									// it to be bound now, do coalescing
1786									dontCoalesce = false;
1787								}
1788								if ( symbolIsWeakReference(sym) ) {
1789									// when weakbind() is run on a classic mach-o encoding, it won't try
1790									// to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
1791									// range of global symbols.  To handle that case we do the coalesing now.
1792									dontCoalesce = false;
1793								}
1794								uintptr_t symbolAddr = resolveUndefined(context, sym, twoLevel, dontCoalesce, &image);
1795								// update pointer
1796								symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image,  context);
1797								// update stats
1798								++fgTotalBindFixups;
1799							}
1800						}
1801					}
1802				}
1803				break;
1804		}
1805		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1806	}
1807}
1808
1809
1810
1811#if __i386__
1812void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
1813{
1814	if ( ! this->usablePrebinding(context) ) {
1815		// reset all "fast" stubs
1816		const macho_header* mh = (macho_header*)fMachOData;
1817		const uint32_t cmd_count = mh->ncmds;
1818		const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1819		const struct load_command* cmd = cmds;
1820		for (uint32_t i = 0; i < cmd_count; ++i) {
1821			switch (cmd->cmd) {
1822				case LC_SEGMENT_COMMAND:
1823				{
1824					const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1825					const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1826					const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1827					for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1828						const uint8_t type = sect->flags & SECTION_TYPE;
1829						if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
1830							// reset each jmp entry in this section
1831							const uint32_t indirectTableOffset = sect->reserved1;
1832							const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
1833							uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
1834							uint8_t* end = start + sect->size;
1835							uintptr_t dyldHandler = (uintptr_t)&fast_stub_binding_helper_interface;
1836							uint32_t entryIndex = 0;
1837							for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
1838								bool installLazyHandler = true;
1839								// jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
1840								// if the instruction is updated by one thread while being executed by another
1841								if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) {
1842									// need to bind this now to avoid a potential problem if bound lazily
1843									uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex];
1844									// the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
1845									if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
1846										const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
1847										const ImageLoader* image = NULL;
1848										try {
1849											uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), false, &image);
1850											symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context);
1851											++fgTotalBindFixups;
1852											uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5);
1853											entry[0] = 0xE9; // JMP rel32
1854											entry[1] = rel32 & 0xFF;
1855											entry[2] = (rel32 >> 8) & 0xFF;
1856											entry[3] = (rel32 >> 16) & 0xFF;
1857											entry[4] = (rel32 >> 24) & 0xFF;
1858											installLazyHandler = false;
1859										}
1860										catch (const char* msg) {
1861											// ignore errors when binding symbols early
1862											// maybe the function is never called, and therefore erroring out now would be a regression
1863										}
1864									}
1865								}
1866								if ( installLazyHandler ) {
1867									uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
1868									entry[0] = 0xE8; // CALL rel32
1869									entry[1] = rel32 & 0xFF;
1870									entry[2] = (rel32 >> 8) & 0xFF;
1871									entry[3] = (rel32 >> 16) & 0xFF;
1872									entry[4] = (rel32 >> 24) & 0xFF;
1873								}
1874							}
1875						}
1876					}
1877				}
1878			}
1879			cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1880		}
1881	}
1882}
1883#endif // __i386__
1884
1885
1886void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
1887{
1888	CRSetCrashLogMessage2(this->getPath());
1889#if __i386__
1890	this->initializeLazyStubs(context);
1891#endif
1892
1893	// if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1894	// note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
1895	if ( this->usablePrebinding(context) ) {
1896		// binding already up to date
1897	}
1898	else {
1899		// no valid prebinding, so bind symbols.
1900		// values bound by name are stored two different ways in classic mach-o:
1901
1902	#if TEXT_RELOC_SUPPORT
1903		// if there are __TEXT fixups, temporarily make __TEXT writable
1904		if ( fTextSegmentBinds )
1905			this->makeTextSegmentWritable(context, true);
1906	#endif
1907
1908		// 1) external relocations are used for data initialized to external symbols
1909		this->doBindExternalRelocations(context);
1910
1911		// 2) "indirect symbols" are used for code references to external symbols
1912		// if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now
1913		this->bindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache);
1914
1915	#if TEXT_RELOC_SUPPORT
1916		// if there were __TEXT fixups, restore write protection
1917		if ( fTextSegmentBinds )
1918			this->makeTextSegmentWritable(context, false);
1919	#endif
1920	}
1921
1922	// set up dyld entry points in image
1923	this->setupLazyPointerHandler(context);
1924
1925	CRSetCrashLogMessage2(NULL);
1926}
1927
1928void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
1929{
1930	// some API called requested that all lazy pointers in this image be force bound
1931	this->bindIndirectSymbolPointers(context, false, true);
1932}
1933
1934void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
1935{
1936	if ( context.verboseInterposing )
1937		dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples.size(), this->getPath());
1938
1939	// scan indirect symbols
1940	const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1941	const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1942	const struct load_command* cmd = cmds;
1943	for (uint32_t i = 0; i < cmd_count; ++i) {
1944		switch (cmd->cmd) {
1945			case LC_SEGMENT_COMMAND:
1946				{
1947					const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1948					const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1949					const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1950					for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1951						const uint8_t type = sect->flags & SECTION_TYPE;
1952						if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
1953							const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
1954							uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1955							for (uint32_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
1956								for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
1957									// replace all references to 'replacee' with 'replacement'
1958									if ( (symbolPointers[pointerIndex] == it->replacee) && (this != it->replacementImage) ) {
1959										if ( context.verboseInterposing ) {
1960											dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n",
1961												&symbolPointers[pointerIndex], it->replacee, it->replacement, this->getPath());
1962										}
1963										symbolPointers[pointerIndex] = it->replacement;
1964									}
1965								}
1966							}
1967						}
1968				#if __i386__
1969						// i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking
1970						else if ( (type == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
1971							// check each jmp entry in this section
1972							uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
1973							uint8_t* end = start + sect->size;
1974							for (uint8_t* entry = start; entry < end; entry += 5) {
1975								if ( entry[0] == 0xE9 ) { // 0xE9 == JMP
1976									uint32_t rel32 = *((uint32_t*)&entry[1]); // assume unaligned load of uint32_t is ok
1977									uint32_t target = (uint32_t)&entry[5] + rel32;
1978									for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
1979										// replace all references to 'replacee' with 'replacement'
1980										if ( (it->replacee == target) && (this != it->replacementImage) ) {
1981											if ( context.verboseInterposing ) {
1982												dyld::log("dyld: interposing: at %p replace JMP 0x%lX with JMP 0x%lX in %s\n",
1983													&entry[1], it->replacee, it->replacement, this->getPath());
1984											}
1985											uint32_t newRel32 = it->replacement - (uint32_t)&entry[5];
1986											*((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok
1987										}
1988									}
1989								}
1990							}
1991						}
1992				#endif
1993					}
1994				}
1995				break;
1996		}
1997		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1998	}
1999
2000	// scan external relocations
2001	const uintptr_t relocBase = this->getRelocBase();
2002	const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
2003	const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
2004	for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
2005		if (reloc->r_length == RELOC_SIZE) {
2006			switch(reloc->r_type) {
2007				case POINTER_RELOC:
2008					{
2009						uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
2010						for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
2011							// replace all references to 'replacee' with 'replacement'
2012							if ( (*location == it->replacee) && (this != it->replacementImage) ) {
2013								if ( context.verboseInterposing ) {
2014									dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n",
2015										location, it->replacee, it->replacement, this->getPath());
2016								}
2017								*location = it->replacement;
2018							}
2019						}
2020					}
2021					break;
2022			}
2023		}
2024	}
2025}
2026
2027
2028const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const
2029{
2030	uintptr_t targetAddress = (uintptr_t)addr - fSlide;
2031	const struct macho_nlist* bestSymbol = NULL;
2032	// first walk all global symbols
2033	const struct macho_nlist* const globalsStart = &fSymbolTable[fDynamicInfo->iextdefsym];
2034	const struct macho_nlist* const globalsEnd= &globalsStart[fDynamicInfo->nextdefsym];
2035	for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
2036 		if ( (s->n_type & N_TYPE) == N_SECT ) {
2037			if ( bestSymbol == NULL ) {
2038				if ( s->n_value <= targetAddress )
2039					bestSymbol = s;
2040			}
2041			else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2042				bestSymbol = s;
2043			}
2044		}
2045	}
2046	// next walk all local symbols
2047	const struct macho_nlist* const localsStart = &fSymbolTable[fDynamicInfo->ilocalsym];
2048	const struct macho_nlist* const localsEnd= &localsStart[fDynamicInfo->nlocalsym];
2049	for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
2050 		if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
2051			if ( bestSymbol == NULL ) {
2052				if ( s->n_value <= targetAddress )
2053					bestSymbol = s;
2054			}
2055			else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
2056				bestSymbol = s;
2057			}
2058		}
2059	}
2060	if ( bestSymbol != NULL ) {
2061#if __arm__
2062		if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
2063			*closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
2064		else
2065			*closestAddr = (void*)(bestSymbol->n_value + fSlide);
2066#else
2067		*closestAddr = (void*)(bestSymbol->n_value + fSlide);
2068#endif
2069		return &fStrings[bestSymbol->n_un.n_strx];
2070	}
2071	return NULL;
2072}
2073
2074
2075