]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMachOClassic.cpp
dyld-239.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 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
184 ImageLoaderMachOClassic* 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
218 ImageLoaderMachOClassic* 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
251 ImageLoaderMachOClassic::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
258 ImageLoaderMachOClassic* 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
273 void ImageLoaderMachOClassic::instantiateFinish(const LinkContext& context)
274 {
275 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
276 this->parseLoadCmds();
277 }
278
279 ImageLoaderMachOClassic::~ImageLoaderMachOClassic()
280 {
281 // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
282 destroy();
283 }
284
285 uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const
286 {
287 return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic)));
288 }
289
290
291 ImageLoader* 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
298 bool 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
305 bool 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
313 void 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
325 void 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
332 void 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
370 unsigned int
371 ImageLoaderMachOClassic::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
383 void
384 ImageLoaderMachOClassic::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
413 int
414 ImageLoaderMachOClassic::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
504 void 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
529 static 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
534 int
535 ImageLoaderMachOClassic::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)
578 bool 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
613 bool 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
694 uintptr_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
704 uintptr_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
720 void 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
753 void 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
856 const 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
894 const 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
929 const 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
947 bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
948 {
949 return ( (fSymbolTable <= addr) && (addr < fStrings) );
950 }
951
952
953 uintptr_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
965 bool 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
971 const 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
977 unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const
978 {
979 return fDynamicInfo->nextdefsym;
980 }
981
982 const 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
991 unsigned int ImageLoaderMachOClassic::importedSymbolCount() const
992 {
993 return fDynamicInfo->nundefsym;
994 }
995
996 const 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
1005 const 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
1013 bool 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
1023 bool 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
1033 uintptr_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
1038 uintptr_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
1161 bool 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
1187 void 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
1326 uintptr_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
1381 uintptr_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
1386 uintptr_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
1447 void 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
1467 bool 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
1514 uintptr_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
1538 void 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
1695 void 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__
1812 void 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
1886 void 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
1928 void 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
1934 void 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
2028 const 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