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