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 <mach-o/dyld_images.h>
43 #include <libkern/OSAtomic.h>
45 #include "ImageLoaderMegaDylib.h"
46 #include "ImageLoaderMachO.h"
47 #include "dyldLibSystemInterface.h"
52 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]);
54 extern "C" int _dyld_func_lookup(const char* name
, void** address
);
57 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
58 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
61 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
64 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
65 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
66 struct macho_segment_command
: public segment_command_64
{};
67 struct macho_section
: public section_64
{};
68 struct macho_routines_command
: public routines_command_64
{};
71 #define LC_SEGMENT_COMMAND LC_SEGMENT
72 #define LC_ROUTINES_COMMAND LC_ROUTINES
73 struct macho_segment_command
: public segment_command
{};
74 struct macho_section
: public section
{};
75 struct macho_routines_command
: public routines_command
{};
80 #if SUPPORT_ACCELERATE_TABLES
83 ImageLoaderMegaDylib
* ImageLoaderMegaDylib::makeImageLoaderMegaDylib(const dyld_cache_header
* header
, long slide
, const macho_header
* mainMH
, const LinkContext
& context
)
85 return new ImageLoaderMegaDylib(header
, slide
, mainMH
, context
);
89 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper
90 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
97 ImageLoaderMegaDylib::ImageLoaderMegaDylib(const dyld_cache_header
* header
, long slide
, const macho_header
* mainMH
, const LinkContext
& context
)
98 : ImageLoader("dyld shared cache", 0), _header(header
), _linkEditBias(NULL
), _slide(slide
),
99 _lockArray(NULL
), _lockArrayInUseCount(0)
101 pthread_mutex_init(&_lockArrayGuard
, NULL
);
102 const dyld_cache_mapping_info
* mappings
= (const dyld_cache_mapping_info
*)((uint8_t*)_header
+ _header
->mappingOffset
);
103 const dyld_cache_mapping_info
* lastMapping
= &mappings
[_header
->mappingCount
-1];
104 const dyld_cache_accelerator_info
* accHeader
= (dyld_cache_accelerator_info
*)(_header
->accelerateInfoAddr
+ slide
);
105 for (const dyld_cache_mapping_info
* m
=mappings
; m
<= lastMapping
; ++m
) {
106 if ( m
->initProt
== VM_PROT_READ
) {
107 _linkEditBias
= (uint8_t*)(m
->address
- m
->fileOffset
) + _slide
;
111 _endOfCacheInMemory
= (void*)(lastMapping
->address
+ lastMapping
->size
+ slide
);
112 _images
= (const dyld_cache_image_info
*)((uint8_t*)_header
+ _header
->imagesOffset
);
113 _imageExtras
= (dyld_cache_image_info_extra
*)((char*)accHeader
+ accHeader
->imagesExtrasOffset
);
114 _initializers
= (dyld_cache_accelerator_initializer
*)((char*)accHeader
+ accHeader
->initializersOffset
);
115 _reExportsArray
= (uint16_t*)((char*)accHeader
+ accHeader
->reExportListOffset
);
116 _dependenciesArray
= (uint16_t*)((char*)accHeader
+ accHeader
->depListOffset
);
117 _bottomUpArray
= (uint16_t*)((char*)accHeader
+ accHeader
->bottomUpListOffset
);
118 _rangeTable
= (dyld_cache_range_entry
*)((char*)accHeader
+ accHeader
->rangeTableOffset
);
119 _rangeTableCount
= accHeader
->rangeTableCount
;
120 _imageCount
= accHeader
->imageExtrasCount
;
121 _stateFlags
= (uint8_t*)calloc(_imageCount
, 1);
122 _initializerCount
= accHeader
->initializersCount
;
123 _dylibsTrieStart
= (uint8_t*)accHeader
+ accHeader
->dylibTrieOffset
;
124 _dylibsTrieEnd
= _dylibsTrieStart
+ accHeader
->dylibTrieSize
;
125 _imageTextInfo
= (dyld_cache_image_text_info
*)((uint8_t*)_header
+ _header
->imagesTextOffset
);
126 DATAdyld
* dyldSection
= (DATAdyld
*)(accHeader
->dyldSectionAddr
+ slide
);
127 dyldSection
->dyldLazyBinder
= NULL
; // not used by libdyld.dylib
128 dyldSection
->dyldFuncLookup
= (void*)&_dyld_func_lookup
;
129 dyldSection
->vars
.mh
= mainMH
;
130 context
.setNewProgramVars(dyldSection
->vars
);
134 void ImageLoaderMegaDylib::unreachable() const
139 ImageLoaderMegaDylib::~ImageLoaderMegaDylib()
143 const char* ImageLoaderMegaDylib::getInstallPath() const {
147 const macho_header
* ImageLoaderMegaDylib::getIndexedMachHeader(unsigned index
) const
149 if ( index
> _header
->imagesCount
)
150 dyld::throwf("cache image index out of range (%u), max=%u", index
, _header
->imagesCount
- 1);
151 return (const macho_header
*)(_images
[index
].address
+ _slide
);
154 const char* ImageLoaderMegaDylib::getIndexedPath(unsigned index
) const
156 if ( index
> _header
->imagesCount
)
157 dyld::throwf("cache image index out of range (%u), max=%u", index
, _header
->imagesCount
- 1);
158 return (char*)_header
+ _images
[index
].pathFileOffset
;
161 const char* ImageLoaderMegaDylib::getIndexedShortName(unsigned index
) const
163 const char* path
= getIndexedPath(index
);
164 const char* lastSlash
= strrchr(path
, '/');
165 if ( lastSlash
== NULL
)
171 void ImageLoaderMegaDylib::getDylibUUID(unsigned int index
, uuid_t uuid
) const
173 if ( index
> _header
->imagesCount
)
174 dyld::throwf("cache image index out of range (%u), max=%u", index
, _header
->imagesCount
- 1);
175 memcpy(uuid
, _imageTextInfo
[index
].uuid
, 16);
178 void ImageLoaderMegaDylib::printSegments(const macho_header
* mh
) const
180 const uint32_t cmd_count
= mh
->ncmds
;
181 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+ sizeof(macho_header
));
182 const struct load_command
* cmd
= cmds
;
183 const macho_segment_command
* seg
;
184 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
186 case LC_SEGMENT_COMMAND
:
187 seg
= (macho_segment_command
*)cmd
;
188 dyld::log("%18s at 0x%08lX->0x%08lX\n", seg
->segname
, (long)(seg
->vmaddr
+ _slide
), (long)(seg
->vmaddr
+ seg
->vmsize
+ _slide
));
191 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
195 bool ImageLoaderMegaDylib::hasDylib(const char* path
, unsigned* index
) const
197 const uint8_t* imageNode
= ImageLoader::trieWalk(_dylibsTrieStart
, _dylibsTrieEnd
, path
);
198 if ( imageNode
== NULL
) {
199 #if __MAC_OS_X_VERSION_MIN_REQUIRED
200 // not all symlinks are recorded as aliases in accelerator tables
201 if ( (strncmp(path
, "/usr/lib/", 9) == 0) || (strncmp(path
, "/System/Library/", 16) == 0) ) {
202 char resolvedPath
[PATH_MAX
];
203 if ( realpath(path
, resolvedPath
) != NULL
) {
204 imageNode
= ImageLoader::trieWalk(_dylibsTrieStart
, _dylibsTrieEnd
, resolvedPath
);
207 if ( imageNode
== NULL
)
213 *index
= (unsigned)read_uleb128(imageNode
, _dylibsTrieEnd
);
217 bool ImageLoaderMegaDylib::addressInCache(const void* address
, const mach_header
** mh
, const char** path
, unsigned* index
)
219 // quick out of bounds check
221 if ( (uintptr_t)address
< 0x7FFF70000000LL
)
224 if ( address
< (void*)_header
)
227 if ( address
> _endOfCacheInMemory
)
230 uint64_t unslidAddress
= (uint64_t)address
- _slide
;
231 // linear search for now
232 const dyld_cache_range_entry
* rangeTableEnd
= &_rangeTable
[_rangeTableCount
];
233 for (const dyld_cache_range_entry
* r
= _rangeTable
; r
< rangeTableEnd
; ++r
) {
234 if ( (r
->startAddress
<= unslidAddress
) && (unslidAddress
< r
->startAddress
+r
->size
) ) {
235 *index
= r
->imageIndex
;
236 *mh
= (mach_header
*)getIndexedMachHeader(r
->imageIndex
);
237 *path
= getIndexedPath(r
->imageIndex
);
246 bool ImageLoaderMegaDylib::findUnwindSections(const void* address
, dyld_unwind_sections
* info
)
250 if ( addressInCache(address
, &info
->mh
, &path
, &index
) ) {
251 info
->dwarf_section
= NULL
;
252 info
->dwarf_section_length
= 0;
253 ImageLoaderMachO::findSection(info
->mh
, "__TEXT", "__eh_frame", (void**)&info
->dwarf_section
, &info
->dwarf_section_length
);
255 info
->compact_unwind_section
= NULL
;
256 info
->compact_unwind_section_length
= 0;
257 ImageLoaderMachO::findSection(info
->mh
, "__TEXT", "__unwind_info", (void**)&info
->compact_unwind_section
, &info
->compact_unwind_section_length
);
265 unsigned ImageLoaderMegaDylib::findImageIndex(const LinkContext
& context
, const char* path
) const
268 if ( hasDylib(path
, &index
) )
271 if ( strncmp(path
, "@rpath/libswift", 15) == 0 ) {
272 // <rdar://problem/51352017> a stable swift app built to run on pre-iOS-12.2 will use @rpath to reference swift dylibs in OS
273 const char* trailingPath
= &path
[7];
274 char possiblePath
[strlen(trailingPath
)+16];
275 strcpy(possiblePath
, "/usr/lib/swift/");
276 strcat(possiblePath
, trailingPath
);
277 if ( hasDylib(possiblePath
, &index
) )
280 else if ( strncmp(path
, "@rpath/", 7) == 0 ) {
281 // <rdar://problem/26934069> Somehow we found the dylib in the cache, but it is not this literal string, try simple expansions of @rpath
282 std::vector
<const char*> rpathsFromMainExecutable
;
283 context
.mainExecutable
->getRPaths(context
, rpathsFromMainExecutable
);
284 rpathsFromMainExecutable
.push_back("/System/Library/Frameworks/");
285 rpathsFromMainExecutable
.push_back("/usr/lib/swift/");
286 const char* trailingPath
= &path
[7];
287 for (const char* anRPath
: rpathsFromMainExecutable
) {
288 if ( anRPath
[0] != '/' )
290 char possiblePath
[strlen(anRPath
) + strlen(trailingPath
)+2];
291 strcpy(possiblePath
, anRPath
);
292 if ( possiblePath
[strlen(possiblePath
)-1] != '/' )
293 strcat(possiblePath
, "/");
294 strcat(possiblePath
, trailingPath
);
295 if ( hasDylib(possiblePath
, &index
) ) {
301 // handle symlinks embedded in load commands
302 char resolvedPath
[PATH_MAX
];
303 realpath(path
, resolvedPath
);
304 int realpathErrno
= errno
;
305 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
306 if ( (realpathErrno
== ENOENT
) || (realpathErrno
== 0) ) {
307 if ( strcmp(resolvedPath
, path
) != 0 )
308 return findImageIndex(context
, resolvedPath
);
312 dyld::throwf("no cache image with name (%s)", path
);
315 void ImageLoaderMegaDylib::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
, unsigned imageIndex
)
319 it
.loadOrder
= loadOrder
;
320 it
.weakSymbol
= false;
321 it
.symbolMatches
= false;
324 it
.endIndex
= _imageExtras
[imageIndex
].weakBindingsSize
;
328 it
.imageIndex
= imageIndex
;
331 bool ImageLoaderMegaDylib::incrementCoalIterator(CoalIterator
& it
)
336 if ( _imageExtras
[it
.imageIndex
].weakBindingsSize
== 0 ) {
337 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
339 it
.symbolName
= "~~~";
342 const uint8_t* start
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
);
343 const uint8_t* end
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
+ _imageExtras
[it
.imageIndex
].weakBindingsSize
);
344 const uint8_t* p
= start
+ it
.curIndex
;
349 const mach_header
* mh
;
351 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
352 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
355 case BIND_OPCODE_DONE
:
357 it
.curIndex
= p
- start
;
358 it
.symbolName
= "~~~"; // sorts to end
360 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
361 it
.symbolName
= (char*)p
;
362 it
.weakSymbol
= ((immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) == 0);
363 it
.symbolMatches
= false;
367 it
.curIndex
= p
- start
;
369 case BIND_OPCODE_SET_TYPE_IMM
:
372 case BIND_OPCODE_SET_ADDEND_SLEB
:
373 it
.addend
= read_sleb128(p
, end
);
375 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
376 segIndex
= immediate
;
377 segOffset
= read_uleb128(p
, end
);
378 mh
= (mach_header
*)getIndexedMachHeader((unsigned)it
.imageIndex
);
379 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) )
380 it
.address
= segPrefAddress
+ (uintptr_t)segOffset
+ _slide
;
382 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex
);
384 case BIND_OPCODE_ADD_ADDR_ULEB
:
385 it
.address
+= read_uleb128(p
, end
);
387 case BIND_OPCODE_DO_BIND
:
388 it
.address
+= sizeof(intptr_t);
390 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
391 it
.address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
393 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
394 it
.address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
396 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
397 count
= read_uleb128(p
, end
);
398 skip
= read_uleb128(p
, end
);
399 for (uint32_t i
=0; i
< count
; ++i
) {
400 it
.address
+= skip
+ sizeof(intptr_t);
404 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p
, (int)(p
-start
), this->getPath());
407 /// hmmm, BIND_OPCODE_DONE is missing...
409 it
.symbolName
= "~~~";
410 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
414 uintptr_t ImageLoaderMegaDylib::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
)
416 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
418 if ( findInChainedTries(context
, it
.symbolName
, (unsigned)it
.imageIndex
, NULL
, false, &address
) ) {
424 void ImageLoaderMegaDylib::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, unsigned targetIndex
, const LinkContext
& context
)
427 const uint8_t* start
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
);
428 const uint8_t* end
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
+ _imageExtras
[it
.imageIndex
].weakBindingsSize
);
429 const uint8_t* p
= start
+ it
.curIndex
;
431 uint8_t type
= it
.type
;
432 uintptr_t address
= it
.address
;
433 const char* symbolName
= it
.symbolName
;
434 intptr_t addend
= it
.addend
;
437 const mach_header
* mh
;
441 bool boundSomething
= false;
442 const char* targetImagePath
= targetImage
? targetImage
->getIndexedPath(targetIndex
) : NULL
;
443 while ( !done
&& (p
< end
) ) {
444 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
445 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
448 case BIND_OPCODE_DONE
:
451 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
454 case BIND_OPCODE_SET_TYPE_IMM
:
457 case BIND_OPCODE_SET_ADDEND_SLEB
:
458 addend
= read_sleb128(p
, end
);
460 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
461 segIndex
= immediate
;
462 segOffset
= read_uleb128(p
, end
);
463 mh
= (mach_header
*)getIndexedMachHeader((unsigned)it
.imageIndex
);
464 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) )
465 address
= segPrefAddress
+ (uintptr_t)segOffset
+ _slide
;
467 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex
);
469 case BIND_OPCODE_ADD_ADDR_ULEB
:
470 address
+= read_uleb128(p
, end
);
472 case BIND_OPCODE_DO_BIND
:
473 ImageLoaderMachO::bindLocation(context
, 0, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ", NULL
, _slide
);
474 boundSomething
= true;
475 address
+= sizeof(intptr_t);
477 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
478 ImageLoaderMachO::bindLocation(context
, 0, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ", NULL
, _slide
);
479 boundSomething
= true;
480 address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
482 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
483 ImageLoaderMachO::bindLocation(context
, 0, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ", NULL
, _slide
);
484 boundSomething
= true;
485 address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
487 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
488 count
= read_uleb128(p
, end
);
489 skip
= read_uleb128(p
, end
);
490 for (uint32_t i
=0; i
< count
; ++i
) {
491 ImageLoaderMachO::bindLocation(context
, 0, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ", NULL
, _slide
);
492 boundSomething
= true;
493 address
+= skip
+ sizeof(intptr_t);
497 dyld::throwf("bad bind opcode %d in weak binding info", *p
);
500 // C++ weak coalescing cannot be tracked by reference counting. Error on side of never unloading.
501 if ( boundSomething
&& (targetImage
!= this) )
502 context
.addDynamicReference(this, targetImage
);
506 void ImageLoaderMegaDylib::appendImagesNeedingCoalescing(ImageLoader
* images
[], unsigned imageIndexes
[], unsigned& count
)
508 for (unsigned i
=0; i
< _imageCount
; ++i
) {
509 uint16_t index
= _bottomUpArray
[i
];
510 if ( _stateFlags
[index
] == kStateUnused
)
512 if ( _imageExtras
[index
].weakBindingsSize
== 0 )
514 images
[count
] = this;
515 imageIndexes
[count
] = index
;
521 bool ImageLoaderMegaDylib::weakSymbolsBound(unsigned index
)
523 return ( _stateFlags
[index
] >= kStateFlagWeakBound
);
526 void ImageLoaderMegaDylib::setWeakSymbolsBound(unsigned index
)
528 if ( _stateFlags
[index
] == kStateFlagBound
)
529 _stateFlags
[index
] = kStateFlagWeakBound
;
533 void ImageLoaderMegaDylib::recursiveMarkLoaded(const LinkContext
& context
, unsigned imageIndex
)
535 if ( _stateFlags
[imageIndex
] != kStateUnused
)
538 const macho_header
* mh
= getIndexedMachHeader(imageIndex
);
539 const char* path
= getIndexedPath(imageIndex
);
541 if ( context
.verboseLoading
)
542 dyld::log("dyld: loaded: %s\n", path
);
543 if ( context
.verboseMapping
) {
544 dyld::log("dyld: Using shared cached for %s\n", path
);
548 // change state to "loaded" before recursing to break cycles
549 _stateFlags
[imageIndex
] = kStateLoaded
;
550 ++fgImagesUsedFromSharedCache
;
552 dyld_image_info debuggerInfo
;
553 debuggerInfo
.imageLoadAddress
= (mach_header
*)mh
;
554 debuggerInfo
.imageFilePath
= path
;
555 debuggerInfo
.imageFileModDate
= 0;
556 addImagesToAllImages(1, &debuggerInfo
);
558 if ( _imageExtras
[imageIndex
].weakBindingsSize
!= 0 ) {
559 ++fgImagesRequiringCoalescing
;
560 ++fgImagesHasWeakDefinitions
;
563 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
564 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
565 unsigned subDep
= (_dependenciesArray
[i
] & 0x7FFF); // mask off upward bit
566 recursiveMarkLoaded(context
, subDep
);
570 void ImageLoaderMegaDylib::recursiveLoadLibraries(const LinkContext
& context
, bool preflightOnly
, const RPathChain
& loaderRPaths
, const char* loadPath
)
572 unsigned index
= findImageIndex(context
, loadPath
);
573 recursiveMarkLoaded(context
, index
);
576 unsigned int ImageLoaderMegaDylib::recursiveUpdateDepth(unsigned int maxDepth
)
583 const ImageLoader::Symbol
* ImageLoaderMegaDylib::findExportedSymbol(const char* name
, bool searchReExports
, const char* thisPath
, const ImageLoader
** foundIn
) const
586 if ( !hasDylib(thisPath
, &index
) )
588 const uint8_t* exportNode
;
589 const uint8_t* exportTrieEnd
;
590 unsigned foundinIndex
;
591 // <rdar://problem/22068598> always search re-exports
592 // the point of searchReExports was to break cycles in dylibs, we don't have cycles in cache, so ok to search deep
593 searchReExports
= true;
594 if ( searchReExports
) {
595 if ( !exportTrieHasNodeRecursive(name
, index
, &exportNode
, &exportTrieEnd
, &foundinIndex
) )
599 if ( !exportTrieHasNode(name
, index
, &exportNode
, &exportTrieEnd
) )
603 return (ImageLoader::Symbol
*)exportNode
;
606 bool ImageLoaderMegaDylib::exportTrieHasNode(const char* symbolName
, unsigned index
,
607 const uint8_t** exportNode
, const uint8_t** exportTrieEnd
) const
609 const uint8_t* start
= (uint8_t*)(_imageExtras
[index
].exportsTrieAddr
+ _slide
);
610 const uint32_t size
= _imageExtras
[index
].exportsTrieSize
;
613 const uint8_t* end
= start
+ size
;
614 const uint8_t* node
= ImageLoader::trieWalk(start
, end
, symbolName
);
618 *exportTrieEnd
= end
;
622 bool ImageLoaderMegaDylib::exportTrieHasNodeRecursive(const char* symbolName
, unsigned index
,
623 const uint8_t** exportNode
, const uint8_t** exportTrieEnd
,
624 unsigned* foundinIndex
) const
626 // look in trie for image index
627 if ( exportTrieHasNode(symbolName
, index
, exportNode
, exportTrieEnd
) ) {
628 *foundinIndex
= index
;
631 // recursively look in all re-exported tries
632 unsigned startArrayIndex
= _imageExtras
[index
].reExportsStartArrayIndex
;
633 for (int i
=startArrayIndex
; _reExportsArray
[i
] != 0xFFFF; ++i
) {
634 unsigned reExIndex
= _reExportsArray
[i
];
635 if ( exportTrieHasNodeRecursive(symbolName
, reExIndex
, exportNode
, exportTrieEnd
, foundinIndex
) )
641 bool ImageLoaderMegaDylib::findExportedSymbolAddress(const LinkContext
& context
, const char* symbolName
,
642 const ImageLoader
* requestorImage
, int requestorOrdinalOfDef
,
643 bool runResolver
, const ImageLoader
** foundIn
, uintptr_t* address
) const
645 const char* definedImagePath
= requestorImage
->libPath(requestorOrdinalOfDef
-1);
646 unsigned index
= findImageIndex(context
, definedImagePath
);
648 return findInChainedTries(context
, symbolName
, index
, requestorImage
, runResolver
, address
);
651 uintptr_t ImageLoaderMegaDylib::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
652 const ImageLoader
* requestor
, bool runResolver
, const char* symbolName
) const
654 // scan for with trie contains this node
655 const uint8_t* exportTrieEnd
= NULL
;
656 unsigned imageIndex
= 0xFFFF;
657 const macho_header
* mh
= NULL
;
658 uint64_t unslidTrieNode
= ((uintptr_t)sym
) - _slide
;
659 for (unsigned i
=0; i
< _imageCount
; ++i
) {
660 uint64_t start
= _imageExtras
[i
].exportsTrieAddr
;
661 uint64_t end
= _imageExtras
[i
].exportsTrieAddr
+ _imageExtras
[i
].exportsTrieSize
;
662 if ( (start
< unslidTrieNode
) && (unslidTrieNode
< end
) ) {
663 exportTrieEnd
= (uint8_t*)(end
+ _slide
);
665 mh
= (macho_header
*)(_images
[imageIndex
].address
+ _slide
);
671 dyld::throwf("getExportedSymbolAddress(Symbol=%p) not in a cache trie", sym
);
673 const uint8_t* exportNode
= (const uint8_t*)sym
;
675 processExportNode(context
, symbolName
? symbolName
: "unknown", imageIndex
, exportNode
, exportTrieEnd
, requestor
, runResolver
, &address
);
679 void ImageLoaderMegaDylib::processExportNode(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
680 const uint8_t* exportNode
, const uint8_t* exportTrieEnd
,
681 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
683 const macho_header
* mh
= getIndexedMachHeader(definedImageIndex
);
684 uintptr_t flags
= read_uleb128(exportNode
, exportTrieEnd
);
685 uintptr_t rawAddress
;
686 switch ( flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) {
687 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR
:
688 if ( runResolver
&& (flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) ) {
689 // this node has a stub and resolver, run the resolver to get target address
690 uintptr_t stub
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
; // skip over stub
691 // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
692 uintptr_t interposedStub
= interposedAddress(context
, stub
, requestorImage
);
693 if ( interposedStub
!= stub
) {
694 *address
= interposedStub
;
697 // stub was not interposed, so run resolver
698 typedef uintptr_t (*ResolverProc
)(void);
699 ResolverProc resolver
= (ResolverProc
)(read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
);
700 *address
= (*resolver
)();
701 if ( context
.verboseBind
)
702 dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver
, *address
);
705 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
706 // re-export from another dylib, lookup there
707 const uintptr_t ordinal
= read_uleb128(exportNode
, exportTrieEnd
);
708 const char* importedName
= (char*)exportNode
;
709 if ( importedName
[0] == '\0' )
710 importedName
= symbolName
;
711 unsigned startArrayIndex
= _imageExtras
[definedImageIndex
].dependentsStartArrayIndex
;
712 unsigned reExImageIndex
= _dependenciesArray
[startArrayIndex
+ ordinal
-1] & 0x7FFF;
713 if ( findInChainedTries(context
, importedName
, reExImageIndex
, requestorImage
, runResolver
, address
) )
715 dyld::throwf("re-exported symbol '%s' not found for image %s expected re-exported in %s, node=%p",
716 symbolName
, getIndexedShortName(definedImageIndex
), getIndexedShortName(reExImageIndex
), exportNode
);
718 rawAddress
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
;
719 *address
= interposedAddress(context
, rawAddress
, requestorImage
);
721 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
:
722 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
723 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
724 *address
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
;
726 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
:
727 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
728 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
729 *address
= read_uleb128(exportNode
, exportTrieEnd
);
732 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
734 //dyld::throwf("unsupported exported symbol node=%p", exportNode);
737 bool ImageLoaderMegaDylib::findInChainedTries(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
738 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
740 //dyld::log("findInChainedTries(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
741 const uint8_t* exportNode
;
742 const uint8_t* exportTrieEnd
;
743 unsigned foundinIndex
;
744 if ( !exportTrieHasNodeRecursive(symbolName
, definedImageIndex
, &exportNode
, &exportTrieEnd
, &foundinIndex
) )
747 processExportNode(context
, symbolName
, foundinIndex
, exportNode
, exportTrieEnd
, requestorImage
, runResolver
, address
);
752 bool ImageLoaderMegaDylib::findInChainedTriesAndDependentsExcept(const LinkContext
& context
, const char* symbolName
, unsigned imageIndex
,
753 const ImageLoader
* requestorImage
, bool runResolver
, bool alreadyVisited
[], uintptr_t* address
) const
755 //dyld::log("findInChainedTriesAndDependentsExcept(sym=%s, index=%u, path=%s)\n", symbolName, imageIndex, getIndexedPath(imageIndex));
756 if ( alreadyVisited
[imageIndex
] )
758 alreadyVisited
[imageIndex
] = true;
760 if ( findInChainedTries(context
, symbolName
, imageIndex
, requestorImage
, runResolver
, address
) )
763 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
764 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
765 // ignore upward links
766 if ( (_dependenciesArray
[i
] & 0x8000) == 0 ) {
767 unsigned depIndex
= _dependenciesArray
[i
] & 0x7FFF;
768 if ( _stateFlags
[depIndex
] != kStateFlagInitialized
)
770 if ( findInChainedTriesAndDependentsExcept(context
, symbolName
, depIndex
, requestorImage
, runResolver
, alreadyVisited
, address
) )
777 bool ImageLoaderMegaDylib::findInChainedTriesAndDependents(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
778 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
780 //dyld::log("findInChainedTriesAndDependents(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
781 if ( findInChainedTries(context
, symbolName
, definedImageIndex
, requestorImage
, runResolver
, address
) )
784 bool alreadyVisited
[_header
->imagesCount
];
785 bzero(alreadyVisited
, sizeof(alreadyVisited
));
786 return findInChainedTriesAndDependentsExcept(context
, symbolName
, definedImageIndex
, requestorImage
, runResolver
, alreadyVisited
, address
);
790 bool ImageLoaderMegaDylib::flatFindSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
, ImageLoader::CoalesceNotifier notifier
)
793 // check export trie of all in-use images
794 for (unsigned i
=0; i
< _imageCount
; ++i
) {
795 uint16_t imageIndex
= _bottomUpArray
[i
];
796 if ( _stateFlags
[imageIndex
] == kStateUnused
)
798 const macho_header
* mh
= getIndexedMachHeader(imageIndex
);
799 if ( onlyInCoalesced
&& (mh
->flags
& MH_WEAK_DEFINES
) == 0 )
801 const uint8_t* exportNode
;
802 const uint8_t* exportTrieEnd
;
803 if ( exportTrieHasNode(name
, imageIndex
, &exportNode
, &exportTrieEnd
) ) {
805 notifier((Symbol
*)exportNode
, this, (mach_header
*)getIndexedMachHeader(imageIndex
));
807 *sym
= (Symbol
*)exportNode
;
811 if ( !onlyInCoalesced
)
819 void ImageLoaderMegaDylib::markAllbound(const LinkContext
& context
)
821 for (unsigned i
=0; i
< _imageCount
; ++i
) {
822 uint16_t imageIndex
= _bottomUpArray
[i
];
823 if ( _stateFlags
[imageIndex
] == kStateLoaded
) {
824 _stateFlags
[imageIndex
] = kStateFlagBound
;
825 context
.notifySingleFromCache(dyld_image_state_bound
, (mach_header
*)getIndexedMachHeader(imageIndex
), getIndexedPath(imageIndex
));
831 void ImageLoaderMegaDylib::recursiveSpinLockAcquire(unsigned int imageIndex
, mach_port_t thisThread
)
833 pthread_mutex_lock(&_lockArrayGuard
);
834 if ( _lockArray
== NULL
)
835 _lockArray
= (recursive_lock
*)calloc(_imageCount
, sizeof(recursive_lock
));
836 _lockArrayInUseCount
++;
837 pthread_mutex_unlock(&_lockArrayGuard
);
839 recursive_lock
* imagesLock
= &_lockArray
[imageIndex
];
840 while ( !OSAtomicCompareAndSwap32Barrier(0, thisThread
, (int*)&imagesLock
->thread
) ) {
841 if ( imagesLock
->thread
== thisThread
)
847 void ImageLoaderMegaDylib::recursiveSpinLockRelease(unsigned int imageIndex
, mach_port_t thisThread
)
849 recursive_lock
* imagesLock
= &_lockArray
[imageIndex
];
850 if ( --imagesLock
->count
== 0 )
851 imagesLock
->thread
= 0;
853 pthread_mutex_lock(&_lockArrayGuard
);
854 _lockArrayInUseCount
--;
855 if ( _lockArrayInUseCount
== 0 ) {
856 free((void*)_lockArray
);
859 pthread_mutex_unlock(&_lockArrayGuard
);
863 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext
& context
, mach_port_t thisThread
, unsigned int imageIndex
,
864 InitializerTimingList
& timingInfo
, UpwardIndexes
& upInits
)
866 // Don't do any locking until libSystem.dylib is initialized, so we can malloc() the lock array
867 bool useLock
= dyld::gProcessInfo
->libSystemInitialized
;
869 recursiveSpinLockAcquire(imageIndex
, thisThread
);
871 // only run initializers if currently in bound state
872 if ( (_stateFlags
[imageIndex
] == kStateFlagBound
) || (_stateFlags
[imageIndex
] == kStateFlagWeakBound
) ) {
874 // Each image in cache has its own lock. We only set the state to Initialized if we hold the lock for the image.
875 _stateFlags
[imageIndex
] = kStateFlagInitialized
;
877 // first recursively init all dependents
878 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
879 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
880 unsigned subDepIndex
= _dependenciesArray
[i
];
881 // ignore upward links
882 if ( (subDepIndex
& 0x8000) == 0 )
883 recursiveInitialization(context
, thisThread
, subDepIndex
, timingInfo
, upInits
);
885 upInits
.images
[upInits
.count
++] = (subDepIndex
& 0x7FFF);
888 // notify objc about this image
889 context
.notifySingleFromCache(dyld_image_state_dependents_initialized
, (mach_header
*)getIndexedMachHeader(imageIndex
), getIndexedPath(imageIndex
));
891 // run all initializers for imageIndex
892 const dyld_cache_accelerator_initializer
* pInitStart
= _initializers
;
893 const dyld_cache_accelerator_initializer
* pInitEnd
= &pInitStart
[_initializerCount
];
894 bool ranSomeInitializers
= false;
895 uint64_t t1
= mach_absolute_time();
896 for (const dyld_cache_accelerator_initializer
* p
=pInitStart
; p
< pInitEnd
; ++p
) {
897 if ( p
->imageIndex
== imageIndex
) {
898 Initializer func
= (Initializer
)(p
->functionOffset
+ (uintptr_t)_header
);
899 if ( context
.verboseInit
)
900 dyld::log("dyld: calling initializer function %p in %s\n", func
, getIndexedPath(imageIndex
));
901 bool haveLibSystemHelpersBefore
= (dyld::gLibSystemHelpers
!= NULL
);
903 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)getIndexedMachHeader(imageIndex
), (uint64_t)func
, 0);
904 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
906 bool haveLibSystemHelpersAfter
= (dyld::gLibSystemHelpers
!= NULL
);
907 ranSomeInitializers
= true;
908 if ( !haveLibSystemHelpersBefore
&& haveLibSystemHelpersAfter
) {
909 // now safe to use malloc() and other calls in libSystem.dylib
910 dyld::gProcessInfo
->libSystemInitialized
= true;
914 if ( ranSomeInitializers
) {
915 uint64_t t2
= mach_absolute_time();
916 const char* shortName
= strrchr(getIndexedPath(imageIndex
), '/');
917 if ( shortName
== NULL
)
918 shortName
= getIndexedPath(imageIndex
);
921 timingInfo
.images
[timingInfo
.count
].shortName
= shortName
;
922 timingInfo
.images
[timingInfo
.count
].initTime
= (t2
-t1
);
927 // only unlock if this frame locked (note: libSystemInitialized changes after libSystem's initializer is run)
929 recursiveSpinLockRelease(imageIndex
, thisThread
);
933 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext
& context
, mach_port_t thisThread
, const char* pathToInitialize
,
934 InitializerTimingList
& timingInfo
, UninitedUpwards
&)
936 UpwardIndexes upsBuffer
[256];
937 UpwardIndexes
& ups
= upsBuffer
[0];
939 unsigned imageIndex
= findImageIndex(context
, pathToInitialize
);
940 this->recursiveInitialization(context
, thisThread
, imageIndex
, timingInfo
, ups
);
941 for (int i
=0; i
< ups
.count
; ++i
) {
942 UpwardIndexes upsBuffer2
[256];
943 UpwardIndexes
& ignoreUp
= upsBuffer2
[0];
945 this->recursiveInitialization(context
, thisThread
, ups
.images
[i
], timingInfo
, ignoreUp
);
949 void ImageLoaderMegaDylib::recursiveBind(const LinkContext
& context
, bool forceLazysBound
, bool neverUnload
)
951 markAllbound(context
);
954 uint8_t ImageLoaderMegaDylib::dyldStateToCacheState(dyld_image_states state
) {
956 case dyld_image_state_mapped
:
957 case dyld_image_state_dependents_mapped
:
959 case dyld_image_state_bound
:
960 return kStateFlagBound
;
961 case dyld_image_state_initialized
:
962 return kStateFlagInitialized
;
963 case dyld_image_state_rebased
:
964 case dyld_image_state_dependents_initialized
:
965 case dyld_image_state_terminated
:
971 void ImageLoaderMegaDylib::recursiveApplyInterposing(const LinkContext
& context
)
973 if ( context
.verboseInterposing
)
974 dyld::log("dyld: interposing %lu tuples onto shared cache\n", fgInterposingTuples
.size());
979 unsigned ImageLoaderMegaDylib::appendImagesToNotify(dyld_image_states state
, bool orLater
, dyld_image_info
* infos
)
981 uint8_t targetCacheState
= dyldStateToCacheState(state
);
982 if ( targetCacheState
== kStateUnused
)
984 unsigned usedCount
= 0;
985 for (int i
=_imageCount
-1; i
>= 0; --i
) {
986 uint16_t index
= _bottomUpArray
[i
];
987 uint8_t imageState
= _stateFlags
[index
];
988 if ( imageState
== kStateFlagWeakBound
)
989 imageState
= kStateFlagBound
;
990 if ( (imageState
== targetCacheState
) || (orLater
&& (imageState
> targetCacheState
)) ) {
991 infos
[usedCount
].imageLoadAddress
= (mach_header
*)getIndexedMachHeader(index
);
992 infos
[usedCount
].imageFilePath
= getIndexedPath(index
);
993 infos
[usedCount
].imageFileModDate
= 0;
1001 bool ImageLoaderMegaDylib::dlopenFromCache(const LinkContext
& context
, const char* path
, int mode
, void** handle
)
1003 unsigned imageIndex
;
1004 if ( !hasDylib(path
, &imageIndex
) ) {
1008 // RTLD_NOLOAD means return handle if already loaded, but don't now load it
1009 if ( mode
& RTLD_NOLOAD
) {
1010 dyld::gLibSystemHelpers
->releaseGlobalDyldLock();
1011 if ( _stateFlags
[imageIndex
] == kStateUnused
) {
1017 this->recursiveMarkLoaded(context
, imageIndex
);
1018 context
.notifyBatch(dyld_image_state_dependents_mapped
, false);
1019 this->markAllbound(context
);
1020 context
.notifyBatch(dyld_image_state_bound
, false);
1022 this->weakBind(context
);
1024 // <rdar://problem/25069046> Release dyld global lock before running initializers in dlopen() with customer cache
1025 dyld::gLibSystemHelpers
->releaseGlobalDyldLock();
1027 InitializerTimingList timingInfo
[_initializerCount
];
1028 timingInfo
[0].count
= 0;
1029 mach_port_t thisThread
= mach_thread_self();
1030 UpwardIndexes upsBuffer
[256]; // room for 511 dangling upward links
1031 UpwardIndexes
& ups
= upsBuffer
[0];
1033 this->recursiveInitialization(context
, thisThread
, imageIndex
, timingInfo
[0], ups
);
1034 // make sure any upward linked dylibs were initialized
1035 for (int i
=0; i
< ups
.count
; ++i
) {
1036 UpwardIndexes upsBuffer2
[256];
1037 UpwardIndexes
& ignoreUp
= upsBuffer2
[0];
1039 this->recursiveInitialization(context
, thisThread
, ups
.images
[i
], timingInfo
[0], ignoreUp
);
1041 mach_port_deallocate(mach_task_self(), thisThread
);
1042 context
.notifyBatch(dyld_image_state_initialized
, false);
1045 *handle
= makeCacheHandle(imageIndex
, mode
);
1049 bool ImageLoaderMegaDylib::makeCacheHandle(const LinkContext
& context
, unsigned cacheIndex
, int mode
, void** result
)
1051 if ( cacheIndex
>= _imageCount
)
1054 *result
= makeCacheHandle(cacheIndex
, mode
);
1058 void* ImageLoaderMegaDylib::makeCacheHandle(unsigned index
, int mode
)
1060 uint8_t flags
= ((mode
& RTLD_FIRST
) ? 1 : 0);
1063 return (void*)(uintptr_t)( 0xFFEEDDCC00000000LL
| (index
<< 8) | flags
);
1065 return (void*)(uintptr_t)( 0xF8000000 | (index
<< 8) | flags
);
1069 bool ImageLoaderMegaDylib::isCacheHandle(void* handle
, unsigned* index
, uint8_t* flags
)
1072 if ( (((uintptr_t)handle
) >> 32) == 0xFFEEDDCC ) {
1074 *index
= (((uintptr_t)handle
) >> 8) & 0xFFFF;
1076 *flags
= ((uintptr_t)handle
) & 0xFF;
1080 if ( (((uintptr_t)handle
) >> 24) == 0xF8 ) {
1082 *index
= (((uintptr_t)handle
) >> 8) & 0xFFFF;
1084 *flags
= ((uintptr_t)handle
) & 0xFF;
1092 void* ImageLoaderMegaDylib::dlsymFromCache(const LinkContext
& context
, void* handle
, const char* symbolName
, unsigned imageIndex
)
1094 unsigned indexInHandle
;
1096 uintptr_t symAddress
;
1097 if ( handle
== RTLD_SELF
) {
1098 if ( findInChainedTriesAndDependents(context
, symbolName
, imageIndex
, NULL
, true, &symAddress
) )
1099 return (void*)symAddress
;
1101 else if ( handle
== RTLD_NEXT
) {
1102 // FIXME: really need to not look in imageIndex, but look in others.
1103 if ( findInChainedTriesAndDependents(context
, symbolName
, imageIndex
, NULL
, true, &symAddress
) )
1104 return (void*)symAddress
;
1106 else if ( isCacheHandle(handle
, &indexInHandle
, &flags
) ) {
1107 bool searchOnlyFirst
= (flags
& 1); // RTLD_FIRST
1108 // normal dlsym(handle,) semantics is that the handle is just the first place to search. RTLD_FIRST disables that
1109 if ( searchOnlyFirst
) {
1110 if ( findInChainedTries(context
, symbolName
, indexInHandle
, NULL
, true, &symAddress
) )
1111 return (void*)symAddress
;
1114 if ( findInChainedTriesAndDependents(context
, symbolName
, indexInHandle
, NULL
, true, &symAddress
) )
1115 return (void*)symAddress
;
1122 bool ImageLoaderMegaDylib::dladdrFromCache(const void* address
, Dl_info
* info
)
1124 const mach_header
* mh
;
1126 if ( !addressInCache(address
, &mh
, &info
->dli_fname
, &index
) )
1129 info
->dli_fbase
= (void*)mh
;
1130 if ( address
== mh
) {
1131 // special case lookup of header
1132 info
->dli_sname
= "__dso_handle";
1133 info
->dli_saddr
= info
->dli_fbase
;
1137 // find closest symbol in the image
1138 info
->dli_sname
= ImageLoaderMachO::findClosestSymbol(mh
, address
, (const void**)&info
->dli_saddr
);
1140 // never return the mach_header symbol
1141 if ( info
->dli_saddr
== info
->dli_fbase
) {
1142 info
->dli_sname
= NULL
;
1143 info
->dli_saddr
= NULL
;
1147 // strip off leading underscore
1148 if ( info
->dli_sname
!= NULL
) {
1149 if ( info
->dli_sname
[0] == '_' )
1150 info
->dli_sname
= info
->dli_sname
+1;
1156 uintptr_t ImageLoaderMegaDylib::bindLazy(uintptr_t lazyBindingInfoOffset
, const LinkContext
& context
, const mach_header
* mh
, unsigned imageIndex
)
1158 const dyld_info_command
* dyldInfoCmd
= ImageLoaderMachO::findDyldInfoLoadCommand(mh
);
1159 if ( dyldInfoCmd
== NULL
)
1162 const uint8_t* const lazyInfoStart
= &_linkEditBias
[dyldInfoCmd
->lazy_bind_off
];
1163 const uint8_t* const lazyInfoEnd
= &lazyInfoStart
[dyldInfoCmd
->lazy_bind_size
];
1164 uint32_t lbOffset
= (uint32_t)lazyBindingInfoOffset
;
1166 uintptr_t segOffset
;
1168 const char* symbolName
;
1170 if ( ImageLoaderMachO::getLazyBindingInfo(lbOffset
, lazyInfoStart
, lazyInfoEnd
, &segIndex
, &segOffset
, &libraryOrdinal
, &symbolName
, &doneAfterBind
) ) {
1171 //const char* thisPath = getIndexedPath(imageIndex);
1172 //dyld::log("%s needs symbol '%s' from ordinal=%d\n", thisPath, symbolName, libraryOrdinal);
1173 unsigned startDepArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
1174 unsigned targetIndex
;
1175 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_SELF
)
1176 targetIndex
= imageIndex
;
1178 targetIndex
= _dependenciesArray
[startDepArrayIndex
+libraryOrdinal
-1] & 0x7FFF;
1179 //const char* targetPath = getIndexedPath(targetIndex);
1180 //dyld::log("%s needs symbol '%s' from %s\n", thisPath, symbolName, targetPath);
1181 uintptr_t targetAddress
;
1182 if ( findInChainedTries(context
, symbolName
, targetIndex
, this, true, &targetAddress
) ) {
1183 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) ) {
1184 uintptr_t* lp
= (uintptr_t*)(segPrefAddress
+ segOffset
+ _slide
);
1185 //dyld::log(" storing 0x%0lX to lp %p\n", targetAddress, lp);
1186 *lp
= targetAddress
;
1187 return targetAddress
;
1196 #endif // SUPPORT_ACCELERATE_TABLES