1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2015 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
26 #if __arm__ || __arm64__
27 #include <System/sys/mman.h>
35 #include <sys/types.h>
36 #include <sys/fcntl.h>
38 #include <sys/param.h>
39 #include <mach/mach.h>
40 #include <mach/thread_status.h>
41 #include <mach-o/loader.h>
42 #include <libkern/OSAtomic.h>
44 #include "ImageLoaderMegaDylib.h"
45 #include "ImageLoaderMachO.h"
46 #include "mach-o/dyld_images.h"
47 #include "dyldLibSystemInterface.h"
51 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]);
54 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
55 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
58 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
61 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
62 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
63 struct macho_segment_command
: public segment_command_64
{};
64 struct macho_section
: public section_64
{};
65 struct macho_routines_command
: public routines_command_64
{};
68 #define LC_SEGMENT_COMMAND LC_SEGMENT
69 #define LC_ROUTINES_COMMAND LC_ROUTINES
70 struct macho_segment_command
: public segment_command
{};
71 struct macho_section
: public section
{};
72 struct macho_routines_command
: public routines_command
{};
77 #if SUPPORT_ACCELERATE_TABLES
80 ImageLoaderMegaDylib
* ImageLoaderMegaDylib::makeImageLoaderMegaDylib(const dyld_cache_header
* header
, long slide
, const LinkContext
& context
)
82 return new ImageLoaderMegaDylib(header
, slide
, context
);
86 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper
87 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
94 ImageLoaderMegaDylib::ImageLoaderMegaDylib(const dyld_cache_header
* header
, long slide
, const LinkContext
& context
)
95 : ImageLoader("dyld shared cache", 0), _header(header
), _linkEditBias(NULL
), _slide(slide
),
96 _lockArray(NULL
), _lockArrayInUseCount(0)
98 pthread_mutex_init(&_lockArrayGuard
, NULL
);
99 const dyld_cache_mapping_info
* mappings
= (const dyld_cache_mapping_info
*)((uint8_t*)_header
+ _header
->mappingOffset
);
100 const dyld_cache_mapping_info
* lastMapping
= &mappings
[_header
->mappingCount
-1];
101 const dyld_cache_accelerator_info
* accHeader
= (dyld_cache_accelerator_info
*)(_header
->accelerateInfoAddr
+ slide
);
102 for (const dyld_cache_mapping_info
* m
=mappings
; m
<= lastMapping
; ++m
) {
103 if ( m
->initProt
== VM_PROT_READ
) {
104 _linkEditBias
= (uint8_t*)(m
->address
- m
->fileOffset
) + _slide
;
108 _endOfCacheInMemory
= (void*)(lastMapping
->address
+ lastMapping
->size
+ slide
);
109 _images
= (const dyld_cache_image_info
*)((uint8_t*)_header
+ _header
->imagesOffset
);
110 _imageExtras
= (dyld_cache_image_info_extra
*)((char*)accHeader
+ accHeader
->imagesExtrasOffset
);
111 _initializers
= (dyld_cache_accelerator_initializer
*)((char*)accHeader
+ accHeader
->initializersOffset
);
112 _reExportsArray
= (uint16_t*)((char*)accHeader
+ accHeader
->reExportListOffset
);
113 _dependenciesArray
= (uint16_t*)((char*)accHeader
+ accHeader
->depListOffset
);
114 _bottomUpArray
= (uint16_t*)((char*)accHeader
+ accHeader
->bottomUpListOffset
);
115 _rangeTable
= (dyld_cache_range_entry
*)((char*)accHeader
+ accHeader
->rangeTableOffset
);
116 _rangeTableCount
= accHeader
->rangeTableCount
;
117 _imageCount
= accHeader
->imageExtrasCount
;
118 _stateFlags
= (uint8_t*)calloc(_imageCount
, 1);
119 _initializerCount
= accHeader
->initializersCount
;
120 _dylibsTrieStart
= (uint8_t*)accHeader
+ accHeader
->dylibTrieOffset
;
121 _dylibsTrieEnd
= _dylibsTrieStart
+ accHeader
->dylibTrieSize
;
122 _imageTextInfo
= (dyld_cache_image_text_info
*)((uint8_t*)_header
+ _header
->imagesTextOffset
);
123 DATAdyld
* dyldSection
= (DATAdyld
*)(accHeader
->dyldSectionAddr
+ slide
);
124 dyldSection
->dyldLazyBinder
= NULL
; // not used by libdyld.dylib
125 dyldSection
->dyldFuncLookup
= (void*)&_dyld_func_lookup
;
126 dyldSection
->vars
.mh
= context
.mainExecutable
->machHeader();
127 context
.setNewProgramVars(dyldSection
->vars
);
131 void ImageLoaderMegaDylib::unreachable() const
136 ImageLoaderMegaDylib::~ImageLoaderMegaDylib()
140 const char* ImageLoaderMegaDylib::getInstallPath() const {
144 const macho_header
* ImageLoaderMegaDylib::getIndexedMachHeader(unsigned index
) const
146 if ( index
> _header
->imagesCount
)
147 dyld::throwf("cache image index out of range (%u), max=%u", index
, _header
->imagesCount
- 1);
148 return (const macho_header
*)(_images
[index
].address
+ _slide
);
151 const char* ImageLoaderMegaDylib::getIndexedPath(unsigned index
) const
153 if ( index
> _header
->imagesCount
)
154 dyld::throwf("cache image index out of range (%u), max=%u", index
, _header
->imagesCount
- 1);
155 return (char*)_header
+ _images
[index
].pathFileOffset
;
158 const char* ImageLoaderMegaDylib::getIndexedShortName(unsigned index
) const
160 const char* path
= getIndexedPath(index
);
161 const char* lastSlash
= strrchr(path
, '/');
162 if ( lastSlash
== NULL
)
168 void ImageLoaderMegaDylib::getDylibUUID(unsigned int index
, uuid_t uuid
) const
170 if ( index
> _header
->imagesCount
)
171 dyld::throwf("cache image index out of range (%u), max=%u", index
, _header
->imagesCount
- 1);
172 memcpy(uuid
, _imageTextInfo
[index
].uuid
, 16);
175 void ImageLoaderMegaDylib::printSegments(const macho_header
* mh
) const
177 const uint32_t cmd_count
= mh
->ncmds
;
178 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+ sizeof(macho_header
));
179 const struct load_command
* cmd
= cmds
;
180 const macho_segment_command
* seg
;
181 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
183 case LC_SEGMENT_COMMAND
:
184 seg
= (macho_segment_command
*)cmd
;
185 dyld::log("%18s at 0x%08lX->0x%08lX\n", seg
->segname
, (long)(seg
->vmaddr
+ _slide
), (long)(seg
->vmaddr
+ seg
->vmsize
+ _slide
));
188 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
192 bool ImageLoaderMegaDylib::hasDylib(const char* path
, unsigned* index
) const
194 const uint8_t* imageNode
= ImageLoader::trieWalk(_dylibsTrieStart
, _dylibsTrieEnd
, path
);
195 if ( imageNode
== NULL
) {
196 #if __MAC_OS_X_VERSION_MIN_REQUIRED
197 // not all symlinks are recorded as aliases in accelerator tables
198 if ( (strncmp(path
, "/usr/lib/", 9) == 0) || (strncmp(path
, "/System/Library/", 16) == 0) ) {
199 char resolvedPath
[PATH_MAX
];
200 if ( realpath(path
, resolvedPath
) != NULL
) {
201 imageNode
= ImageLoader::trieWalk(_dylibsTrieStart
, _dylibsTrieEnd
, resolvedPath
);
204 if ( imageNode
== NULL
)
210 *index
= (unsigned)read_uleb128(imageNode
, _dylibsTrieEnd
);
214 bool ImageLoaderMegaDylib::addressInCache(const void* address
, const mach_header
** mh
, const char** path
, unsigned* index
)
216 // quick out of bounds check
218 if ( (uintptr_t)address
< 0x7FFF70000000LL
)
221 if ( address
< (void*)_header
)
224 if ( address
> _endOfCacheInMemory
)
227 uint64_t unslidAddress
= (uint64_t)address
- _slide
;
228 // linear search for now
229 const dyld_cache_range_entry
* rangeTableEnd
= &_rangeTable
[_rangeTableCount
];
230 for (const dyld_cache_range_entry
* r
= _rangeTable
; r
< rangeTableEnd
; ++r
) {
231 if ( (r
->startAddress
<= unslidAddress
) && (unslidAddress
< r
->startAddress
+r
->size
) ) {
232 *index
= r
->imageIndex
;
233 *mh
= (mach_header
*)getIndexedMachHeader(r
->imageIndex
);
234 *path
= getIndexedPath(r
->imageIndex
);
243 bool ImageLoaderMegaDylib::findUnwindSections(const void* address
, dyld_unwind_sections
* info
)
247 if ( addressInCache(address
, &info
->mh
, &path
, &index
) ) {
248 info
->dwarf_section
= NULL
;
249 info
->dwarf_section_length
= 0;
250 ImageLoaderMachO::findSection(info
->mh
, "__TEXT", "__eh_frame", (void**)&info
->dwarf_section
, &info
->dwarf_section_length
);
252 info
->compact_unwind_section
= NULL
;
253 info
->compact_unwind_section_length
= 0;
254 ImageLoaderMachO::findSection(info
->mh
, "__TEXT", "__unwind_info", (void**)&info
->compact_unwind_section
, &info
->compact_unwind_section_length
);
262 unsigned ImageLoaderMegaDylib::findImageIndex(const LinkContext
& context
, const char* path
) const
265 if ( hasDylib(path
, &index
) )
268 // <rdar://problem/26934069> Somehow we found the dylib in the cache, but it is not this literal string, try simple expansions of @rpath
269 if ( strncmp(path
, "@rpath/", 7) == 0 ) {
270 std::vector
<const char*> rpathsFromMainExecutable
;
271 context
.mainExecutable
->getRPaths(context
, rpathsFromMainExecutable
);
272 const char* trailingPath
= &path
[7];
273 for (const char* anRPath
: rpathsFromMainExecutable
) {
274 if ( anRPath
[0] != '/' )
276 char possiblePath
[strlen(anRPath
) + strlen(trailingPath
)+2];
277 strcpy(possiblePath
, anRPath
);
278 if ( possiblePath
[strlen(possiblePath
)-1] != '/' )
279 strcat(possiblePath
, "/");
280 strcat(possiblePath
, trailingPath
);
281 if ( hasDylib(possiblePath
, &index
) ) {
286 dyld::throwf("no cache image with name (%s)", path
);
289 void ImageLoaderMegaDylib::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
, unsigned imageIndex
)
293 it
.loadOrder
= loadOrder
;
294 it
.weakSymbol
= false;
295 it
.symbolMatches
= false;
298 it
.endIndex
= _imageExtras
[imageIndex
].weakBindingsSize
;
302 it
.imageIndex
= imageIndex
;
305 bool ImageLoaderMegaDylib::incrementCoalIterator(CoalIterator
& it
)
310 if ( _imageExtras
[it
.imageIndex
].weakBindingsSize
== 0 ) {
311 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
313 it
.symbolName
= "~~~";
316 const uint8_t* start
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
);
317 const uint8_t* end
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
+ _imageExtras
[it
.imageIndex
].weakBindingsSize
);
318 const uint8_t* p
= start
+ it
.curIndex
;
323 const mach_header
* mh
;
325 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
326 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
329 case BIND_OPCODE_DONE
:
331 it
.curIndex
= p
- start
;
332 it
.symbolName
= "~~~"; // sorts to end
334 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
335 it
.symbolName
= (char*)p
;
336 it
.weakSymbol
= ((immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) == 0);
337 it
.symbolMatches
= false;
341 it
.curIndex
= p
- start
;
343 case BIND_OPCODE_SET_TYPE_IMM
:
346 case BIND_OPCODE_SET_ADDEND_SLEB
:
347 it
.addend
= read_sleb128(p
, end
);
349 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
350 segIndex
= immediate
;
351 segOffset
= read_uleb128(p
, end
);
352 mh
= (mach_header
*)getIndexedMachHeader((unsigned)it
.imageIndex
);
353 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) )
354 it
.address
= segPrefAddress
+ segOffset
+ _slide
;
356 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex
);
358 case BIND_OPCODE_ADD_ADDR_ULEB
:
359 it
.address
+= read_uleb128(p
, end
);
361 case BIND_OPCODE_DO_BIND
:
362 it
.address
+= sizeof(intptr_t);
364 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
365 it
.address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
367 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
368 it
.address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
370 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
371 count
= read_uleb128(p
, end
);
372 skip
= read_uleb128(p
, end
);
373 for (uint32_t i
=0; i
< count
; ++i
) {
374 it
.address
+= skip
+ sizeof(intptr_t);
378 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p
, (int)(p
-start
), this->getPath());
381 /// hmmm, BIND_OPCODE_DONE is missing...
383 it
.symbolName
= "~~~";
384 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
388 uintptr_t ImageLoaderMegaDylib::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
)
390 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
392 if ( findInChainedTries(context
, it
.symbolName
, (unsigned)it
.imageIndex
, NULL
, false, &address
) ) {
398 void ImageLoaderMegaDylib::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, unsigned targetIndex
, const LinkContext
& context
)
401 const uint8_t* start
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
);
402 const uint8_t* end
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
+ _imageExtras
[it
.imageIndex
].weakBindingsSize
);
403 const uint8_t* p
= start
+ it
.curIndex
;
405 uint8_t type
= it
.type
;
406 uintptr_t address
= it
.address
;
407 const char* symbolName
= it
.symbolName
;
408 intptr_t addend
= it
.addend
;
411 const mach_header
* mh
;
415 bool boundSomething
= false;
416 const char* targetImagePath
= targetImage
? targetImage
->getIndexedPath(targetIndex
) : NULL
;
417 while ( !done
&& (p
< end
) ) {
418 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
419 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
422 case BIND_OPCODE_DONE
:
425 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
428 case BIND_OPCODE_SET_TYPE_IMM
:
431 case BIND_OPCODE_SET_ADDEND_SLEB
:
432 addend
= read_sleb128(p
, end
);
434 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
435 segIndex
= immediate
;
436 segOffset
= read_uleb128(p
, end
);
437 mh
= (mach_header
*)getIndexedMachHeader((unsigned)it
.imageIndex
);
438 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) )
439 address
= segPrefAddress
+ segOffset
+ _slide
;
441 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex
);
443 case BIND_OPCODE_ADD_ADDR_ULEB
:
444 address
+= read_uleb128(p
, end
);
446 case BIND_OPCODE_DO_BIND
:
447 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
448 boundSomething
= true;
449 address
+= sizeof(intptr_t);
451 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
452 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
453 boundSomething
= true;
454 address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
456 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
457 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
458 boundSomething
= true;
459 address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
461 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
462 count
= read_uleb128(p
, end
);
463 skip
= read_uleb128(p
, end
);
464 for (uint32_t i
=0; i
< count
; ++i
) {
465 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
466 boundSomething
= true;
467 address
+= skip
+ sizeof(intptr_t);
471 dyld::throwf("bad bind opcode %d in weak binding info", *p
);
474 // C++ weak coalescing cannot be tracked by reference counting. Error on side of never unloading.
475 if ( boundSomething
&& (targetImage
!= this) )
476 context
.addDynamicReference(this, targetImage
);
480 void ImageLoaderMegaDylib::appendImagesNeedingCoalescing(ImageLoader
* images
[], unsigned imageIndexes
[], unsigned& count
)
482 for (unsigned i
=0; i
< _imageCount
; ++i
) {
483 uint16_t index
= _bottomUpArray
[i
];
484 if ( _stateFlags
[index
] == kStateUnused
)
486 if ( _imageExtras
[index
].weakBindingsSize
== 0 )
488 images
[count
] = this;
489 imageIndexes
[count
] = index
;
495 bool ImageLoaderMegaDylib::weakSymbolsBound(unsigned index
)
497 return ( _stateFlags
[index
] >= kStateFlagWeakBound
);
500 void ImageLoaderMegaDylib::setWeakSymbolsBound(unsigned index
)
502 if ( _stateFlags
[index
] == kStateFlagBound
)
503 _stateFlags
[index
] = kStateFlagWeakBound
;
507 void ImageLoaderMegaDylib::recursiveMarkLoaded(const LinkContext
& context
, unsigned imageIndex
)
509 if ( _stateFlags
[imageIndex
] != kStateUnused
)
512 const macho_header
* mh
= getIndexedMachHeader(imageIndex
);
513 const char* path
= getIndexedPath(imageIndex
);
515 if ( context
.verboseLoading
)
516 dyld::log("dyld: loaded: %s\n", path
);
517 if ( context
.verboseMapping
) {
518 dyld::log("dyld: Using shared cached for %s\n", path
);
522 // change state to "loaded" before recursing to break cycles
523 _stateFlags
[imageIndex
] = kStateLoaded
;
524 ++fgImagesUsedFromSharedCache
;
526 dyld_image_info debuggerInfo
;
527 debuggerInfo
.imageLoadAddress
= (mach_header
*)mh
;
528 debuggerInfo
.imageFilePath
= path
;
529 debuggerInfo
.imageFileModDate
= 0;
530 addImagesToAllImages(1, &debuggerInfo
);
532 if ( _imageExtras
[imageIndex
].weakBindingsSize
!= 0 ) {
533 ++fgImagesRequiringCoalescing
;
534 ++fgImagesHasWeakDefinitions
;
537 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
538 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
539 unsigned subDep
= (_dependenciesArray
[i
] & 0x7FFF); // mask off upward bit
540 recursiveMarkLoaded(context
, subDep
);
544 void ImageLoaderMegaDylib::recursiveLoadLibraries(const LinkContext
& context
, bool preflightOnly
, const RPathChain
& loaderRPaths
, const char* loadPath
)
546 unsigned index
= findImageIndex(context
, loadPath
);
547 recursiveMarkLoaded(context
, index
);
550 unsigned int ImageLoaderMegaDylib::recursiveUpdateDepth(unsigned int maxDepth
)
557 const ImageLoader::Symbol
* ImageLoaderMegaDylib::findExportedSymbol(const char* name
, bool searchReExports
, const char* thisPath
, const ImageLoader
** foundIn
) const
560 if ( !hasDylib(thisPath
, &index
) )
562 const uint8_t* exportNode
;
563 const uint8_t* exportTrieEnd
;
564 unsigned foundinIndex
;
565 // <rdar://problem/22068598> always search re-exports
566 // the point of searchReExports was to break cycles in dylibs, we don't have cycles in cache, so ok to search deep
567 searchReExports
= true;
568 if ( searchReExports
) {
569 if ( !exportTrieHasNodeRecursive(name
, index
, &exportNode
, &exportTrieEnd
, &foundinIndex
) )
573 if ( !exportTrieHasNode(name
, index
, &exportNode
, &exportTrieEnd
) )
577 return (ImageLoader::Symbol
*)exportNode
;
580 bool ImageLoaderMegaDylib::exportTrieHasNode(const char* symbolName
, unsigned index
,
581 const uint8_t** exportNode
, const uint8_t** exportTrieEnd
) const
583 const uint8_t* start
= (uint8_t*)(_imageExtras
[index
].exportsTrieAddr
+ _slide
);
584 const uint32_t size
= _imageExtras
[index
].exportsTrieSize
;
587 const uint8_t* end
= start
+ size
;
588 const uint8_t* node
= ImageLoader::trieWalk(start
, end
, symbolName
);
592 *exportTrieEnd
= end
;
596 bool ImageLoaderMegaDylib::exportTrieHasNodeRecursive(const char* symbolName
, unsigned index
,
597 const uint8_t** exportNode
, const uint8_t** exportTrieEnd
,
598 unsigned* foundinIndex
) const
600 // look in trie for image index
601 if ( exportTrieHasNode(symbolName
, index
, exportNode
, exportTrieEnd
) ) {
602 *foundinIndex
= index
;
605 // recursively look in all re-exported tries
606 unsigned startArrayIndex
= _imageExtras
[index
].reExportsStartArrayIndex
;
607 for (int i
=startArrayIndex
; _reExportsArray
[i
] != 0xFFFF; ++i
) {
608 unsigned reExIndex
= _reExportsArray
[i
];
609 if ( exportTrieHasNodeRecursive(symbolName
, reExIndex
, exportNode
, exportTrieEnd
, foundinIndex
) )
615 bool ImageLoaderMegaDylib::findExportedSymbolAddress(const LinkContext
& context
, const char* symbolName
,
616 const ImageLoader
* requestorImage
, int requestorOrdinalOfDef
,
617 bool runResolver
, const ImageLoader
** foundIn
, uintptr_t* address
) const
619 const char* definedImagePath
= requestorImage
->libPath(requestorOrdinalOfDef
-1);
620 unsigned index
= findImageIndex(context
, definedImagePath
);
622 return findInChainedTries(context
, symbolName
, index
, requestorImage
, runResolver
, address
);
625 uintptr_t ImageLoaderMegaDylib::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
626 const ImageLoader
* requestor
, bool runResolver
, const char* symbolName
) const
628 // scan for with trie contains this node
629 const uint8_t* exportTrieEnd
= NULL
;
630 unsigned imageIndex
= 0xFFFF;
631 const macho_header
* mh
= NULL
;
632 uint64_t unslidTrieNode
= ((uintptr_t)sym
) - _slide
;
633 for (unsigned i
=0; i
< _imageCount
; ++i
) {
634 uint64_t start
= _imageExtras
[i
].exportsTrieAddr
;
635 uint64_t end
= _imageExtras
[i
].exportsTrieAddr
+ _imageExtras
[i
].exportsTrieSize
;
636 if ( (start
< unslidTrieNode
) && (unslidTrieNode
< end
) ) {
637 exportTrieEnd
= (uint8_t*)(end
+ _slide
);
639 mh
= (macho_header
*)(_images
[imageIndex
].address
+ _slide
);
645 dyld::throwf("getExportedSymbolAddress(Symbol=%p) not in a cache trie", sym
);
647 const uint8_t* exportNode
= (const uint8_t*)sym
;
649 processExportNode(context
, symbolName
? symbolName
: "unknown", imageIndex
, exportNode
, exportTrieEnd
, requestor
, runResolver
, &address
);
653 void ImageLoaderMegaDylib::processExportNode(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
654 const uint8_t* exportNode
, const uint8_t* exportTrieEnd
,
655 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
657 const macho_header
* mh
= getIndexedMachHeader(definedImageIndex
);
658 uintptr_t flags
= read_uleb128(exportNode
, exportTrieEnd
);
659 uintptr_t rawAddress
;
660 switch ( flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) {
661 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR
:
662 if ( runResolver
&& (flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) ) {
663 // this node has a stub and resolver, run the resolver to get target address
664 uintptr_t stub
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
; // skip over stub
665 // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
666 uintptr_t interposedStub
= interposedAddress(context
, stub
, requestorImage
);
667 if ( interposedStub
!= stub
) {
668 *address
= interposedStub
;
671 // stub was not interposed, so run resolver
672 typedef uintptr_t (*ResolverProc
)(void);
673 ResolverProc resolver
= (ResolverProc
)(read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
);
674 *address
= (*resolver
)();
675 if ( context
.verboseBind
)
676 dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver
, *address
);
679 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
680 // re-export from another dylib, lookup there
681 const uintptr_t ordinal
= read_uleb128(exportNode
, exportTrieEnd
);
682 const char* importedName
= (char*)exportNode
;
683 if ( importedName
[0] == '\0' )
684 importedName
= symbolName
;
685 unsigned startArrayIndex
= _imageExtras
[definedImageIndex
].dependentsStartArrayIndex
;
686 unsigned reExImageIndex
= _dependenciesArray
[startArrayIndex
+ ordinal
-1] & 0x7FFF;
687 if ( findInChainedTries(context
, importedName
, reExImageIndex
, requestorImage
, runResolver
, address
) )
689 dyld::throwf("re-exported symbol '%s' not found for image %s expected re-exported in %s, node=%p",
690 symbolName
, getIndexedShortName(definedImageIndex
), getIndexedShortName(reExImageIndex
), exportNode
);
692 rawAddress
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
;
693 *address
= interposedAddress(context
, rawAddress
, requestorImage
);
695 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
:
696 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
697 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
698 *address
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
;
700 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
:
701 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
702 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
703 *address
= read_uleb128(exportNode
, exportTrieEnd
);
706 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
708 dyld::throwf("unsupported exported symbol node=%p", exportNode
);
711 bool ImageLoaderMegaDylib::findInChainedTries(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
712 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
714 //dyld::log("findInChainedTries(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
715 const uint8_t* exportNode
;
716 const uint8_t* exportTrieEnd
;
717 unsigned foundinIndex
;
718 if ( !exportTrieHasNodeRecursive(symbolName
, definedImageIndex
, &exportNode
, &exportTrieEnd
, &foundinIndex
) )
721 processExportNode(context
, symbolName
, foundinIndex
, exportNode
, exportTrieEnd
, requestorImage
, runResolver
, address
);
726 bool ImageLoaderMegaDylib::findInChainedTriesAndDependentsExcept(const LinkContext
& context
, const char* symbolName
, unsigned imageIndex
,
727 const ImageLoader
* requestorImage
, bool runResolver
, bool alreadyVisited
[], uintptr_t* address
) const
729 //dyld::log("findInChainedTriesAndDependentsExcept(sym=%s, index=%u, path=%s)\n", symbolName, imageIndex, getIndexedPath(imageIndex));
730 if ( alreadyVisited
[imageIndex
] )
732 alreadyVisited
[imageIndex
] = true;
734 if ( findInChainedTries(context
, symbolName
, imageIndex
, requestorImage
, runResolver
, address
) )
737 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
738 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
739 // ignore upward links
740 if ( (_dependenciesArray
[i
] & 0x8000) == 0 ) {
741 unsigned depIndex
= _dependenciesArray
[i
] & 0x7FFF;
742 if ( _stateFlags
[depIndex
] != kStateFlagInitialized
)
744 if ( findInChainedTriesAndDependentsExcept(context
, symbolName
, depIndex
, requestorImage
, runResolver
, alreadyVisited
, address
) )
751 bool ImageLoaderMegaDylib::findInChainedTriesAndDependents(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
752 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
754 //dyld::log("findInChainedTriesAndDependents(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
755 if ( findInChainedTries(context
, symbolName
, definedImageIndex
, requestorImage
, runResolver
, address
) )
758 bool alreadyVisited
[_header
->imagesCount
];
759 bzero(alreadyVisited
, sizeof(alreadyVisited
));
760 return findInChainedTriesAndDependentsExcept(context
, symbolName
, definedImageIndex
, requestorImage
, runResolver
, alreadyVisited
, address
);
764 bool ImageLoaderMegaDylib::flatFindSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
766 // check export trie of all in-use images
767 for (unsigned i
=0; i
< _imageCount
; ++i
) {
768 uint16_t imageIndex
= _bottomUpArray
[i
];
769 if ( _stateFlags
[imageIndex
] == kStateUnused
)
771 if ( onlyInCoalesced
&& (_imageExtras
[imageIndex
].weakBindingsSize
== 0) )
773 const uint8_t* exportNode
;
774 const uint8_t* exportTrieEnd
;
775 if ( exportTrieHasNode(name
, imageIndex
, &exportNode
, &exportTrieEnd
) ) {
776 *sym
= (Symbol
*)exportNode
;
785 void ImageLoaderMegaDylib::markAllbound(const LinkContext
& context
)
787 for (unsigned i
=0; i
< _imageCount
; ++i
) {
788 uint16_t imageIndex
= _bottomUpArray
[i
];
789 if ( _stateFlags
[imageIndex
] == kStateLoaded
) {
790 _stateFlags
[imageIndex
] = kStateFlagBound
;
791 context
.notifySingleFromCache(dyld_image_state_bound
, (mach_header
*)getIndexedMachHeader(imageIndex
), getIndexedPath(imageIndex
));
797 void ImageLoaderMegaDylib::recursiveSpinLockAcquire(unsigned int imageIndex
, mach_port_t thisThread
)
799 pthread_mutex_lock(&_lockArrayGuard
);
800 if ( _lockArray
== NULL
)
801 _lockArray
= (recursive_lock
*)calloc(_imageCount
, sizeof(recursive_lock
));
802 _lockArrayInUseCount
++;
803 pthread_mutex_unlock(&_lockArrayGuard
);
805 recursive_lock
* imagesLock
= &_lockArray
[imageIndex
];
806 while ( !OSAtomicCompareAndSwap32Barrier(0, thisThread
, (int*)&imagesLock
->thread
) ) {
807 if ( imagesLock
->thread
== thisThread
)
813 void ImageLoaderMegaDylib::recursiveSpinLockRelease(unsigned int imageIndex
, mach_port_t thisThread
)
815 recursive_lock
* imagesLock
= &_lockArray
[imageIndex
];
816 if ( --imagesLock
->count
== 0 )
817 imagesLock
->thread
= 0;
819 pthread_mutex_lock(&_lockArrayGuard
);
820 _lockArrayInUseCount
--;
821 if ( _lockArrayInUseCount
== 0 ) {
822 free((void*)_lockArray
);
825 pthread_mutex_unlock(&_lockArrayGuard
);
829 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext
& context
, mach_port_t thisThread
, unsigned int imageIndex
,
830 InitializerTimingList
& timingInfo
)
832 // Don't do any locking until libSystem.dylib is initialized, so we can malloc() the lock array
833 bool useLock
= dyld::gProcessInfo
->libSystemInitialized
;
835 recursiveSpinLockAcquire(imageIndex
, thisThread
);
837 // only run initializers if currently in bound state
838 if ( (_stateFlags
[imageIndex
] == kStateFlagBound
) || (_stateFlags
[imageIndex
] == kStateFlagWeakBound
) ) {
840 // Each image in cache has its own lock. We only set the state to Initialized if we hold the lock for the image.
841 _stateFlags
[imageIndex
] = kStateFlagInitialized
;
843 // first recursively init all dependents
844 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
845 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
846 unsigned subDepIndex
= _dependenciesArray
[i
];
847 // ignore upward links
848 if ( (subDepIndex
& 0x8000) == 0 )
849 recursiveInitialization(context
, thisThread
, subDepIndex
, timingInfo
);
852 // notify objc about this image
853 context
.notifySingleFromCache(dyld_image_state_dependents_initialized
, (mach_header
*)getIndexedMachHeader(imageIndex
), getIndexedPath(imageIndex
));
855 // run all initializers for imageIndex
856 const dyld_cache_accelerator_initializer
* pInitStart
= _initializers
;
857 const dyld_cache_accelerator_initializer
* pInitEnd
= &pInitStart
[_initializerCount
];
858 bool ranSomeInitializers
= false;
859 uint64_t t1
= mach_absolute_time();
860 for (const dyld_cache_accelerator_initializer
* p
=pInitStart
; p
< pInitEnd
; ++p
) {
861 if ( p
->imageIndex
== imageIndex
) {
862 Initializer func
= (Initializer
)(p
->functionOffset
+ (uintptr_t)_header
);
863 if ( context
.verboseInit
)
864 dyld::log("dyld: calling initializer function %p in %s\n", func
, getIndexedPath(imageIndex
));
865 bool haveLibSystemHelpersBefore
= (dyld::gLibSystemHelpers
!= NULL
);
866 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
867 bool haveLibSystemHelpersAfter
= (dyld::gLibSystemHelpers
!= NULL
);
868 ranSomeInitializers
= true;
869 if ( !haveLibSystemHelpersBefore
&& haveLibSystemHelpersAfter
) {
870 // now safe to use malloc() and other calls in libSystem.dylib
871 dyld::gProcessInfo
->libSystemInitialized
= true;
875 if ( ranSomeInitializers
) {
876 uint64_t t2
= mach_absolute_time();
877 const char* shortName
= strrchr(getIndexedPath(imageIndex
), '/');
878 if ( shortName
== NULL
)
879 shortName
= getIndexedPath(imageIndex
);
882 timingInfo
.images
[timingInfo
.count
].shortName
= shortName
;
883 timingInfo
.images
[timingInfo
.count
].initTime
= (t2
-t1
);
888 // only unlock if this frame locked (note: libSystemInitialized changes after libSystem's initializer is run)
890 recursiveSpinLockRelease(imageIndex
, thisThread
);
894 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext
& context
, mach_port_t thisThread
, const char* pathToInitialize
,
895 InitializerTimingList
& timingInfo
, UninitedUpwards
& uninitUps
)
898 if ( hasDylib(pathToInitialize
, &imageIndex
) ) {
899 this->recursiveInitialization(context
, thisThread
, imageIndex
, timingInfo
);
903 void ImageLoaderMegaDylib::recursiveBind(const LinkContext
& context
, bool forceLazysBound
, bool neverUnload
)
905 markAllbound(context
);
908 uint8_t ImageLoaderMegaDylib::dyldStateToCacheState(dyld_image_states state
) {
910 case dyld_image_state_mapped
:
911 case dyld_image_state_dependents_mapped
:
913 case dyld_image_state_bound
:
914 return kStateFlagBound
;
915 case dyld_image_state_initialized
:
916 return kStateFlagInitialized
;
917 case dyld_image_state_rebased
:
918 case dyld_image_state_dependents_initialized
:
919 case dyld_image_state_terminated
:
925 void ImageLoaderMegaDylib::recursiveApplyInterposing(const LinkContext
& context
)
927 if ( context
.verboseInterposing
)
928 dyld::log("dyld: interposing %lu tuples onto shared cache\n", fgInterposingTuples
.size());
933 unsigned ImageLoaderMegaDylib::appendImagesToNotify(dyld_image_states state
, bool orLater
, dyld_image_info
* infos
)
935 uint8_t targetCacheState
= dyldStateToCacheState(state
);
936 if ( targetCacheState
== kStateUnused
)
939 unsigned usedCount
= 0;
940 for (int i
=_imageCount
-1; i
> 0; --i
) {
941 uint16_t index
= _bottomUpArray
[i
];
942 uint8_t imageState
= _stateFlags
[index
];
943 if ( imageState
== kStateFlagWeakBound
)
944 imageState
= kStateFlagBound
;
945 if ( (imageState
== targetCacheState
) || (orLater
&& (imageState
> targetCacheState
)) ) {
946 infos
[usedCount
].imageLoadAddress
= (mach_header
*)getIndexedMachHeader(index
);
947 infos
[usedCount
].imageFilePath
= getIndexedPath(index
);
948 infos
[usedCount
].imageFileModDate
= 0;
956 bool ImageLoaderMegaDylib::dlopenFromCache(const LinkContext
& context
, const char* path
, int mode
, void** handle
)
959 if ( !hasDylib(path
, &imageIndex
) ) {
963 // RTLD_NOLOAD means return handle if already loaded, but don't now load it
964 if ( mode
& RTLD_NOLOAD
) {
965 dyld::gLibSystemHelpers
->releaseGlobalDyldLock();
966 if ( _stateFlags
[imageIndex
] == kStateUnused
) {
972 this->recursiveMarkLoaded(context
, imageIndex
);
973 context
.notifyBatch(dyld_image_state_dependents_mapped
, false);
974 this->markAllbound(context
);
975 context
.notifyBatch(dyld_image_state_bound
, false);
977 this->weakBind(context
);
979 // <rdar://problem/25069046> Release dyld global lock before running initializers in dlopen() with customer cache
980 dyld::gLibSystemHelpers
->releaseGlobalDyldLock();
982 InitializerTimingList timingInfo
[_initializerCount
];
983 timingInfo
[0].count
= 0;
984 mach_port_t thisThread
= mach_thread_self();
985 this->recursiveInitialization(context
, thisThread
, imageIndex
, timingInfo
[0]);
986 mach_port_deallocate(mach_task_self(), thisThread
);
987 context
.notifyBatch(dyld_image_state_initialized
, false);
990 *handle
= makeCacheHandle(imageIndex
, mode
);
994 bool ImageLoaderMegaDylib::makeCacheHandle(const LinkContext
& context
, unsigned cacheIndex
, int mode
, void** result
)
996 if ( cacheIndex
>= _imageCount
)
999 *result
= makeCacheHandle(cacheIndex
, mode
);
1003 void* ImageLoaderMegaDylib::makeCacheHandle(unsigned index
, int mode
)
1005 uint8_t flags
= ((mode
& RTLD_FIRST
) ? 1 : 0);
1008 return (void*)(uintptr_t)( 0xFFEEDDCC00000000LL
| (index
<< 8) | flags
);
1010 return (void*)(uintptr_t)( 0xF8000000 | (index
<< 8) | flags
);
1014 bool ImageLoaderMegaDylib::isCacheHandle(void* handle
, unsigned* index
, uint8_t* flags
)
1017 if ( (((uintptr_t)handle
) >> 32) == 0xFFEEDDCC ) {
1019 *index
= (((uintptr_t)handle
) >> 8) & 0xFFFF;
1021 *flags
= ((uintptr_t)handle
) & 0xFF;
1025 if ( (((uintptr_t)handle
) >> 24) == 0xF8 ) {
1027 *index
= (((uintptr_t)handle
) >> 8) & 0xFFFF;
1029 *flags
= ((uintptr_t)handle
) & 0xFF;
1037 void* ImageLoaderMegaDylib::dlsymFromCache(const LinkContext
& context
, void* handle
, const char* symbolName
, unsigned imageIndex
)
1039 unsigned indexInHandle
;
1041 uintptr_t symAddress
;
1042 if ( handle
== RTLD_SELF
) {
1043 if ( findInChainedTriesAndDependents(context
, symbolName
, imageIndex
, NULL
, true, &symAddress
) )
1044 return (void*)symAddress
;
1046 else if ( handle
== RTLD_NEXT
) {
1047 // FIXME: really need to not look in imageIndex, but look in others.
1048 if ( findInChainedTriesAndDependents(context
, symbolName
, imageIndex
, NULL
, true, &symAddress
) )
1049 return (void*)symAddress
;
1051 else if ( isCacheHandle(handle
, &indexInHandle
, &flags
) ) {
1052 bool searchOnlyFirst
= (flags
& 1); // RTLD_FIRST
1053 // normal dlsym(handle,) semantics is that the handle is just the first place to search. RTLD_FIRST disables that
1054 if ( searchOnlyFirst
) {
1055 if ( findInChainedTries(context
, symbolName
, indexInHandle
, NULL
, true, &symAddress
) )
1056 return (void*)symAddress
;
1059 if ( findInChainedTriesAndDependents(context
, symbolName
, indexInHandle
, NULL
, true, &symAddress
) )
1060 return (void*)symAddress
;
1067 bool ImageLoaderMegaDylib::dladdrFromCache(const void* address
, Dl_info
* info
)
1069 const mach_header
* mh
;
1071 if ( !addressInCache(address
, &mh
, &info
->dli_fname
, &index
) )
1074 info
->dli_fbase
= (void*)mh
;
1075 if ( address
== mh
) {
1076 // special case lookup of header
1077 info
->dli_sname
= "__dso_handle";
1078 info
->dli_saddr
= info
->dli_fbase
;
1082 // find closest symbol in the image
1083 info
->dli_sname
= ImageLoaderMachO::findClosestSymbol(mh
, address
, (const void**)&info
->dli_saddr
);
1085 // never return the mach_header symbol
1086 if ( info
->dli_saddr
== info
->dli_fbase
) {
1087 info
->dli_sname
= NULL
;
1088 info
->dli_saddr
= NULL
;
1092 // strip off leading underscore
1093 if ( info
->dli_sname
!= NULL
) {
1094 if ( info
->dli_sname
[0] == '_' )
1095 info
->dli_sname
= info
->dli_sname
+1;
1101 uintptr_t ImageLoaderMegaDylib::bindLazy(uintptr_t lazyBindingInfoOffset
, const LinkContext
& context
, const mach_header
* mh
, unsigned imageIndex
)
1103 const dyld_info_command
* dyldInfoCmd
= ImageLoaderMachO::findDyldInfoLoadCommand(mh
);
1104 if ( dyldInfoCmd
== NULL
)
1107 const uint8_t* const lazyInfoStart
= &_linkEditBias
[dyldInfoCmd
->lazy_bind_off
];
1108 const uint8_t* const lazyInfoEnd
= &lazyInfoStart
[dyldInfoCmd
->lazy_bind_size
];
1109 uint32_t lbOffset
= (uint32_t)lazyBindingInfoOffset
;
1111 uintptr_t segOffset
;
1113 const char* symbolName
;
1115 if ( ImageLoaderMachO::getLazyBindingInfo(lbOffset
, lazyInfoStart
, lazyInfoEnd
, &segIndex
, &segOffset
, &libraryOrdinal
, &symbolName
, &doneAfterBind
) ) {
1116 //const char* thisPath = getIndexedPath(imageIndex);
1117 //dyld::log("%s needs symbol '%s' from ordinal=%d\n", thisPath, symbolName, libraryOrdinal);
1118 unsigned startDepArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
1119 unsigned targetIndex
;
1120 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_SELF
)
1121 targetIndex
= imageIndex
;
1123 targetIndex
= _dependenciesArray
[startDepArrayIndex
+libraryOrdinal
-1] & 0x7FFF;
1124 //const char* targetPath = getIndexedPath(targetIndex);
1125 //dyld::log("%s needs symbol '%s' from %s\n", thisPath, symbolName, targetPath);
1126 uintptr_t targetAddress
;
1127 if ( findInChainedTries(context
, symbolName
, targetIndex
, this, true, &targetAddress
) ) {
1128 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) ) {
1129 uintptr_t* lp
= (uintptr_t*)(segPrefAddress
+ segOffset
+ _slide
);
1130 //dyld::log(" storing 0x%0lX to lp %p\n", targetAddress, lp);
1131 *lp
= targetAddress
;
1132 return targetAddress
;
1141 #endif // SUPPORT_ACCELERATE_TABLES