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"
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 // <rdar://problem/26934069> Somehow we found the dylib in the cache, but it is not this literal string, try simple expansions of @rpath
272 if ( strncmp(path
, "@rpath/", 7) == 0 ) {
273 std::vector
<const char*> rpathsFromMainExecutable
;
274 context
.mainExecutable
->getRPaths(context
, rpathsFromMainExecutable
);
275 rpathsFromMainExecutable
.push_back("/System/Library/Frameworks/");
276 const char* trailingPath
= &path
[7];
277 for (const char* anRPath
: rpathsFromMainExecutable
) {
278 if ( anRPath
[0] != '/' )
280 char possiblePath
[strlen(anRPath
) + strlen(trailingPath
)+2];
281 strcpy(possiblePath
, anRPath
);
282 if ( possiblePath
[strlen(possiblePath
)-1] != '/' )
283 strcat(possiblePath
, "/");
284 strcat(possiblePath
, trailingPath
);
285 if ( hasDylib(possiblePath
, &index
) ) {
291 // handle symlinks embedded in load commands
292 char resolvedPath
[PATH_MAX
];
293 realpath(path
, resolvedPath
);
294 int realpathErrno
= errno
;
295 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
296 if ( (realpathErrno
== ENOENT
) || (realpathErrno
== 0) ) {
297 if ( strcmp(resolvedPath
, path
) != 0 )
298 return findImageIndex(context
, resolvedPath
);
302 dyld::throwf("no cache image with name (%s)", path
);
305 void ImageLoaderMegaDylib::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
, unsigned imageIndex
)
309 it
.loadOrder
= loadOrder
;
310 it
.weakSymbol
= false;
311 it
.symbolMatches
= false;
314 it
.endIndex
= _imageExtras
[imageIndex
].weakBindingsSize
;
318 it
.imageIndex
= imageIndex
;
321 bool ImageLoaderMegaDylib::incrementCoalIterator(CoalIterator
& it
)
326 if ( _imageExtras
[it
.imageIndex
].weakBindingsSize
== 0 ) {
327 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
329 it
.symbolName
= "~~~";
332 const uint8_t* start
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
);
333 const uint8_t* end
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
+ _imageExtras
[it
.imageIndex
].weakBindingsSize
);
334 const uint8_t* p
= start
+ it
.curIndex
;
339 const mach_header
* mh
;
341 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
342 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
345 case BIND_OPCODE_DONE
:
347 it
.curIndex
= p
- start
;
348 it
.symbolName
= "~~~"; // sorts to end
350 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
351 it
.symbolName
= (char*)p
;
352 it
.weakSymbol
= ((immediate
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) == 0);
353 it
.symbolMatches
= false;
357 it
.curIndex
= p
- start
;
359 case BIND_OPCODE_SET_TYPE_IMM
:
362 case BIND_OPCODE_SET_ADDEND_SLEB
:
363 it
.addend
= read_sleb128(p
, end
);
365 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
366 segIndex
= immediate
;
367 segOffset
= read_uleb128(p
, end
);
368 mh
= (mach_header
*)getIndexedMachHeader((unsigned)it
.imageIndex
);
369 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) )
370 it
.address
= segPrefAddress
+ segOffset
+ _slide
;
372 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex
);
374 case BIND_OPCODE_ADD_ADDR_ULEB
:
375 it
.address
+= read_uleb128(p
, end
);
377 case BIND_OPCODE_DO_BIND
:
378 it
.address
+= sizeof(intptr_t);
380 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
381 it
.address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
383 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
384 it
.address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
386 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
387 count
= read_uleb128(p
, end
);
388 skip
= read_uleb128(p
, end
);
389 for (uint32_t i
=0; i
< count
; ++i
) {
390 it
.address
+= skip
+ sizeof(intptr_t);
394 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p
, (int)(p
-start
), this->getPath());
397 /// hmmm, BIND_OPCODE_DONE is missing...
399 it
.symbolName
= "~~~";
400 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
404 uintptr_t ImageLoaderMegaDylib::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
)
406 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
408 if ( findInChainedTries(context
, it
.symbolName
, (unsigned)it
.imageIndex
, NULL
, false, &address
) ) {
414 void ImageLoaderMegaDylib::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, unsigned targetIndex
, const LinkContext
& context
)
417 const uint8_t* start
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
);
418 const uint8_t* end
= (uint8_t*)(_imageExtras
[it
.imageIndex
].weakBindingsAddr
+ _slide
+ _imageExtras
[it
.imageIndex
].weakBindingsSize
);
419 const uint8_t* p
= start
+ it
.curIndex
;
421 uint8_t type
= it
.type
;
422 uintptr_t address
= it
.address
;
423 const char* symbolName
= it
.symbolName
;
424 intptr_t addend
= it
.addend
;
427 const mach_header
* mh
;
431 bool boundSomething
= false;
432 const char* targetImagePath
= targetImage
? targetImage
->getIndexedPath(targetIndex
) : NULL
;
433 while ( !done
&& (p
< end
) ) {
434 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
435 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
438 case BIND_OPCODE_DONE
:
441 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
444 case BIND_OPCODE_SET_TYPE_IMM
:
447 case BIND_OPCODE_SET_ADDEND_SLEB
:
448 addend
= read_sleb128(p
, end
);
450 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
451 segIndex
= immediate
;
452 segOffset
= read_uleb128(p
, end
);
453 mh
= (mach_header
*)getIndexedMachHeader((unsigned)it
.imageIndex
);
454 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) )
455 address
= segPrefAddress
+ segOffset
+ _slide
;
457 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex
);
459 case BIND_OPCODE_ADD_ADDR_ULEB
:
460 address
+= read_uleb128(p
, end
);
462 case BIND_OPCODE_DO_BIND
:
463 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
464 boundSomething
= true;
465 address
+= sizeof(intptr_t);
467 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
468 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
469 boundSomething
= true;
470 address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
472 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
473 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
474 boundSomething
= true;
475 address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
477 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
478 count
= read_uleb128(p
, end
);
479 skip
= read_uleb128(p
, end
);
480 for (uint32_t i
=0; i
< count
; ++i
) {
481 ImageLoaderMachO::bindLocation(context
, address
, value
, type
, symbolName
, addend
, getIndexedPath((unsigned)it
.imageIndex
), targetImagePath
, "weak ");
482 boundSomething
= true;
483 address
+= skip
+ sizeof(intptr_t);
487 dyld::throwf("bad bind opcode %d in weak binding info", *p
);
490 // C++ weak coalescing cannot be tracked by reference counting. Error on side of never unloading.
491 if ( boundSomething
&& (targetImage
!= this) )
492 context
.addDynamicReference(this, targetImage
);
496 void ImageLoaderMegaDylib::appendImagesNeedingCoalescing(ImageLoader
* images
[], unsigned imageIndexes
[], unsigned& count
)
498 for (unsigned i
=0; i
< _imageCount
; ++i
) {
499 uint16_t index
= _bottomUpArray
[i
];
500 if ( _stateFlags
[index
] == kStateUnused
)
502 if ( _imageExtras
[index
].weakBindingsSize
== 0 )
504 images
[count
] = this;
505 imageIndexes
[count
] = index
;
511 bool ImageLoaderMegaDylib::weakSymbolsBound(unsigned index
)
513 return ( _stateFlags
[index
] >= kStateFlagWeakBound
);
516 void ImageLoaderMegaDylib::setWeakSymbolsBound(unsigned index
)
518 if ( _stateFlags
[index
] == kStateFlagBound
)
519 _stateFlags
[index
] = kStateFlagWeakBound
;
523 void ImageLoaderMegaDylib::recursiveMarkLoaded(const LinkContext
& context
, unsigned imageIndex
)
525 if ( _stateFlags
[imageIndex
] != kStateUnused
)
528 const macho_header
* mh
= getIndexedMachHeader(imageIndex
);
529 const char* path
= getIndexedPath(imageIndex
);
531 if ( context
.verboseLoading
)
532 dyld::log("dyld: loaded: %s\n", path
);
533 if ( context
.verboseMapping
) {
534 dyld::log("dyld: Using shared cached for %s\n", path
);
538 // change state to "loaded" before recursing to break cycles
539 _stateFlags
[imageIndex
] = kStateLoaded
;
540 ++fgImagesUsedFromSharedCache
;
542 dyld_image_info debuggerInfo
;
543 debuggerInfo
.imageLoadAddress
= (mach_header
*)mh
;
544 debuggerInfo
.imageFilePath
= path
;
545 debuggerInfo
.imageFileModDate
= 0;
546 addImagesToAllImages(1, &debuggerInfo
);
548 if ( _imageExtras
[imageIndex
].weakBindingsSize
!= 0 ) {
549 ++fgImagesRequiringCoalescing
;
550 ++fgImagesHasWeakDefinitions
;
553 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
554 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
555 unsigned subDep
= (_dependenciesArray
[i
] & 0x7FFF); // mask off upward bit
556 recursiveMarkLoaded(context
, subDep
);
560 void ImageLoaderMegaDylib::recursiveLoadLibraries(const LinkContext
& context
, bool preflightOnly
, const RPathChain
& loaderRPaths
, const char* loadPath
)
562 unsigned index
= findImageIndex(context
, loadPath
);
563 recursiveMarkLoaded(context
, index
);
566 unsigned int ImageLoaderMegaDylib::recursiveUpdateDepth(unsigned int maxDepth
)
573 const ImageLoader::Symbol
* ImageLoaderMegaDylib::findExportedSymbol(const char* name
, bool searchReExports
, const char* thisPath
, const ImageLoader
** foundIn
) const
576 if ( !hasDylib(thisPath
, &index
) )
578 const uint8_t* exportNode
;
579 const uint8_t* exportTrieEnd
;
580 unsigned foundinIndex
;
581 // <rdar://problem/22068598> always search re-exports
582 // the point of searchReExports was to break cycles in dylibs, we don't have cycles in cache, so ok to search deep
583 searchReExports
= true;
584 if ( searchReExports
) {
585 if ( !exportTrieHasNodeRecursive(name
, index
, &exportNode
, &exportTrieEnd
, &foundinIndex
) )
589 if ( !exportTrieHasNode(name
, index
, &exportNode
, &exportTrieEnd
) )
593 return (ImageLoader::Symbol
*)exportNode
;
596 bool ImageLoaderMegaDylib::exportTrieHasNode(const char* symbolName
, unsigned index
,
597 const uint8_t** exportNode
, const uint8_t** exportTrieEnd
) const
599 const uint8_t* start
= (uint8_t*)(_imageExtras
[index
].exportsTrieAddr
+ _slide
);
600 const uint32_t size
= _imageExtras
[index
].exportsTrieSize
;
603 const uint8_t* end
= start
+ size
;
604 const uint8_t* node
= ImageLoader::trieWalk(start
, end
, symbolName
);
608 *exportTrieEnd
= end
;
612 bool ImageLoaderMegaDylib::exportTrieHasNodeRecursive(const char* symbolName
, unsigned index
,
613 const uint8_t** exportNode
, const uint8_t** exportTrieEnd
,
614 unsigned* foundinIndex
) const
616 // look in trie for image index
617 if ( exportTrieHasNode(symbolName
, index
, exportNode
, exportTrieEnd
) ) {
618 *foundinIndex
= index
;
621 // recursively look in all re-exported tries
622 unsigned startArrayIndex
= _imageExtras
[index
].reExportsStartArrayIndex
;
623 for (int i
=startArrayIndex
; _reExportsArray
[i
] != 0xFFFF; ++i
) {
624 unsigned reExIndex
= _reExportsArray
[i
];
625 if ( exportTrieHasNodeRecursive(symbolName
, reExIndex
, exportNode
, exportTrieEnd
, foundinIndex
) )
631 bool ImageLoaderMegaDylib::findExportedSymbolAddress(const LinkContext
& context
, const char* symbolName
,
632 const ImageLoader
* requestorImage
, int requestorOrdinalOfDef
,
633 bool runResolver
, const ImageLoader
** foundIn
, uintptr_t* address
) const
635 const char* definedImagePath
= requestorImage
->libPath(requestorOrdinalOfDef
-1);
636 unsigned index
= findImageIndex(context
, definedImagePath
);
638 return findInChainedTries(context
, symbolName
, index
, requestorImage
, runResolver
, address
);
641 uintptr_t ImageLoaderMegaDylib::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
642 const ImageLoader
* requestor
, bool runResolver
, const char* symbolName
) const
644 // scan for with trie contains this node
645 const uint8_t* exportTrieEnd
= NULL
;
646 unsigned imageIndex
= 0xFFFF;
647 const macho_header
* mh
= NULL
;
648 uint64_t unslidTrieNode
= ((uintptr_t)sym
) - _slide
;
649 for (unsigned i
=0; i
< _imageCount
; ++i
) {
650 uint64_t start
= _imageExtras
[i
].exportsTrieAddr
;
651 uint64_t end
= _imageExtras
[i
].exportsTrieAddr
+ _imageExtras
[i
].exportsTrieSize
;
652 if ( (start
< unslidTrieNode
) && (unslidTrieNode
< end
) ) {
653 exportTrieEnd
= (uint8_t*)(end
+ _slide
);
655 mh
= (macho_header
*)(_images
[imageIndex
].address
+ _slide
);
661 dyld::throwf("getExportedSymbolAddress(Symbol=%p) not in a cache trie", sym
);
663 const uint8_t* exportNode
= (const uint8_t*)sym
;
665 processExportNode(context
, symbolName
? symbolName
: "unknown", imageIndex
, exportNode
, exportTrieEnd
, requestor
, runResolver
, &address
);
669 void ImageLoaderMegaDylib::processExportNode(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
670 const uint8_t* exportNode
, const uint8_t* exportTrieEnd
,
671 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
673 const macho_header
* mh
= getIndexedMachHeader(definedImageIndex
);
674 uintptr_t flags
= read_uleb128(exportNode
, exportTrieEnd
);
675 uintptr_t rawAddress
;
676 switch ( flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) {
677 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR
:
678 if ( runResolver
&& (flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) ) {
679 // this node has a stub and resolver, run the resolver to get target address
680 uintptr_t stub
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
; // skip over stub
681 // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
682 uintptr_t interposedStub
= interposedAddress(context
, stub
, requestorImage
);
683 if ( interposedStub
!= stub
) {
684 *address
= interposedStub
;
687 // stub was not interposed, so run resolver
688 typedef uintptr_t (*ResolverProc
)(void);
689 ResolverProc resolver
= (ResolverProc
)(read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
);
690 *address
= (*resolver
)();
691 if ( context
.verboseBind
)
692 dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver
, *address
);
695 if ( flags
& EXPORT_SYMBOL_FLAGS_REEXPORT
) {
696 // re-export from another dylib, lookup there
697 const uintptr_t ordinal
= read_uleb128(exportNode
, exportTrieEnd
);
698 const char* importedName
= (char*)exportNode
;
699 if ( importedName
[0] == '\0' )
700 importedName
= symbolName
;
701 unsigned startArrayIndex
= _imageExtras
[definedImageIndex
].dependentsStartArrayIndex
;
702 unsigned reExImageIndex
= _dependenciesArray
[startArrayIndex
+ ordinal
-1] & 0x7FFF;
703 if ( findInChainedTries(context
, importedName
, reExImageIndex
, requestorImage
, runResolver
, address
) )
705 dyld::throwf("re-exported symbol '%s' not found for image %s expected re-exported in %s, node=%p",
706 symbolName
, getIndexedShortName(definedImageIndex
), getIndexedShortName(reExImageIndex
), exportNode
);
708 rawAddress
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
;
709 *address
= interposedAddress(context
, rawAddress
, requestorImage
);
711 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
:
712 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
713 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
714 *address
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)mh
;
716 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
:
717 if ( flags
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
)
718 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
719 *address
= read_uleb128(exportNode
, exportTrieEnd
);
722 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, exportNode
);
724 dyld::throwf("unsupported exported symbol node=%p", exportNode
);
727 bool ImageLoaderMegaDylib::findInChainedTries(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
728 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
730 //dyld::log("findInChainedTries(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
731 const uint8_t* exportNode
;
732 const uint8_t* exportTrieEnd
;
733 unsigned foundinIndex
;
734 if ( !exportTrieHasNodeRecursive(symbolName
, definedImageIndex
, &exportNode
, &exportTrieEnd
, &foundinIndex
) )
737 processExportNode(context
, symbolName
, foundinIndex
, exportNode
, exportTrieEnd
, requestorImage
, runResolver
, address
);
742 bool ImageLoaderMegaDylib::findInChainedTriesAndDependentsExcept(const LinkContext
& context
, const char* symbolName
, unsigned imageIndex
,
743 const ImageLoader
* requestorImage
, bool runResolver
, bool alreadyVisited
[], uintptr_t* address
) const
745 //dyld::log("findInChainedTriesAndDependentsExcept(sym=%s, index=%u, path=%s)\n", symbolName, imageIndex, getIndexedPath(imageIndex));
746 if ( alreadyVisited
[imageIndex
] )
748 alreadyVisited
[imageIndex
] = true;
750 if ( findInChainedTries(context
, symbolName
, imageIndex
, requestorImage
, runResolver
, address
) )
753 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
754 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
755 // ignore upward links
756 if ( (_dependenciesArray
[i
] & 0x8000) == 0 ) {
757 unsigned depIndex
= _dependenciesArray
[i
] & 0x7FFF;
758 if ( _stateFlags
[depIndex
] != kStateFlagInitialized
)
760 if ( findInChainedTriesAndDependentsExcept(context
, symbolName
, depIndex
, requestorImage
, runResolver
, alreadyVisited
, address
) )
767 bool ImageLoaderMegaDylib::findInChainedTriesAndDependents(const LinkContext
& context
, const char* symbolName
, unsigned definedImageIndex
,
768 const ImageLoader
* requestorImage
, bool runResolver
, uintptr_t* address
) const
770 //dyld::log("findInChainedTriesAndDependents(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
771 if ( findInChainedTries(context
, symbolName
, definedImageIndex
, requestorImage
, runResolver
, address
) )
774 bool alreadyVisited
[_header
->imagesCount
];
775 bzero(alreadyVisited
, sizeof(alreadyVisited
));
776 return findInChainedTriesAndDependentsExcept(context
, symbolName
, definedImageIndex
, requestorImage
, runResolver
, alreadyVisited
, address
);
780 bool ImageLoaderMegaDylib::flatFindSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
782 // check export trie of all in-use images
783 for (unsigned i
=0; i
< _imageCount
; ++i
) {
784 uint16_t imageIndex
= _bottomUpArray
[i
];
785 if ( _stateFlags
[imageIndex
] == kStateUnused
)
787 if ( onlyInCoalesced
&& (_imageExtras
[imageIndex
].weakBindingsSize
== 0) )
789 const uint8_t* exportNode
;
790 const uint8_t* exportTrieEnd
;
791 if ( exportTrieHasNode(name
, imageIndex
, &exportNode
, &exportTrieEnd
) ) {
792 *sym
= (Symbol
*)exportNode
;
801 void ImageLoaderMegaDylib::markAllbound(const LinkContext
& context
)
803 for (unsigned i
=0; i
< _imageCount
; ++i
) {
804 uint16_t imageIndex
= _bottomUpArray
[i
];
805 if ( _stateFlags
[imageIndex
] == kStateLoaded
) {
806 _stateFlags
[imageIndex
] = kStateFlagBound
;
807 context
.notifySingleFromCache(dyld_image_state_bound
, (mach_header
*)getIndexedMachHeader(imageIndex
), getIndexedPath(imageIndex
));
813 void ImageLoaderMegaDylib::recursiveSpinLockAcquire(unsigned int imageIndex
, mach_port_t thisThread
)
815 pthread_mutex_lock(&_lockArrayGuard
);
816 if ( _lockArray
== NULL
)
817 _lockArray
= (recursive_lock
*)calloc(_imageCount
, sizeof(recursive_lock
));
818 _lockArrayInUseCount
++;
819 pthread_mutex_unlock(&_lockArrayGuard
);
821 recursive_lock
* imagesLock
= &_lockArray
[imageIndex
];
822 while ( !OSAtomicCompareAndSwap32Barrier(0, thisThread
, (int*)&imagesLock
->thread
) ) {
823 if ( imagesLock
->thread
== thisThread
)
829 void ImageLoaderMegaDylib::recursiveSpinLockRelease(unsigned int imageIndex
, mach_port_t thisThread
)
831 recursive_lock
* imagesLock
= &_lockArray
[imageIndex
];
832 if ( --imagesLock
->count
== 0 )
833 imagesLock
->thread
= 0;
835 pthread_mutex_lock(&_lockArrayGuard
);
836 _lockArrayInUseCount
--;
837 if ( _lockArrayInUseCount
== 0 ) {
838 free((void*)_lockArray
);
841 pthread_mutex_unlock(&_lockArrayGuard
);
845 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext
& context
, mach_port_t thisThread
, unsigned int imageIndex
,
846 InitializerTimingList
& timingInfo
, UpwardIndexes
& upInits
)
848 // Don't do any locking until libSystem.dylib is initialized, so we can malloc() the lock array
849 bool useLock
= dyld::gProcessInfo
->libSystemInitialized
;
851 recursiveSpinLockAcquire(imageIndex
, thisThread
);
853 // only run initializers if currently in bound state
854 if ( (_stateFlags
[imageIndex
] == kStateFlagBound
) || (_stateFlags
[imageIndex
] == kStateFlagWeakBound
) ) {
856 // Each image in cache has its own lock. We only set the state to Initialized if we hold the lock for the image.
857 _stateFlags
[imageIndex
] = kStateFlagInitialized
;
859 // first recursively init all dependents
860 unsigned startArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
861 for (int i
=startArrayIndex
; _dependenciesArray
[i
] != 0xFFFF; ++i
) {
862 unsigned subDepIndex
= _dependenciesArray
[i
];
863 // ignore upward links
864 if ( (subDepIndex
& 0x8000) == 0 )
865 recursiveInitialization(context
, thisThread
, subDepIndex
, timingInfo
, upInits
);
867 upInits
.images
[upInits
.count
++] = (subDepIndex
& 0x7FFF);
870 // notify objc about this image
871 context
.notifySingleFromCache(dyld_image_state_dependents_initialized
, (mach_header
*)getIndexedMachHeader(imageIndex
), getIndexedPath(imageIndex
));
873 // run all initializers for imageIndex
874 const dyld_cache_accelerator_initializer
* pInitStart
= _initializers
;
875 const dyld_cache_accelerator_initializer
* pInitEnd
= &pInitStart
[_initializerCount
];
876 bool ranSomeInitializers
= false;
877 uint64_t t1
= mach_absolute_time();
878 for (const dyld_cache_accelerator_initializer
* p
=pInitStart
; p
< pInitEnd
; ++p
) {
879 if ( p
->imageIndex
== imageIndex
) {
880 Initializer func
= (Initializer
)(p
->functionOffset
+ (uintptr_t)_header
);
881 if ( context
.verboseInit
)
882 dyld::log("dyld: calling initializer function %p in %s\n", func
, getIndexedPath(imageIndex
));
883 bool haveLibSystemHelpersBefore
= (dyld::gLibSystemHelpers
!= NULL
);
884 dyld3::kdebug_trace_dyld_duration(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)func
, 0, ^{
885 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
887 bool haveLibSystemHelpersAfter
= (dyld::gLibSystemHelpers
!= NULL
);
888 ranSomeInitializers
= true;
889 if ( !haveLibSystemHelpersBefore
&& haveLibSystemHelpersAfter
) {
890 // now safe to use malloc() and other calls in libSystem.dylib
891 dyld::gProcessInfo
->libSystemInitialized
= true;
895 if ( ranSomeInitializers
) {
896 uint64_t t2
= mach_absolute_time();
897 const char* shortName
= strrchr(getIndexedPath(imageIndex
), '/');
898 if ( shortName
== NULL
)
899 shortName
= getIndexedPath(imageIndex
);
902 timingInfo
.images
[timingInfo
.count
].shortName
= shortName
;
903 timingInfo
.images
[timingInfo
.count
].initTime
= (t2
-t1
);
908 // only unlock if this frame locked (note: libSystemInitialized changes after libSystem's initializer is run)
910 recursiveSpinLockRelease(imageIndex
, thisThread
);
914 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext
& context
, mach_port_t thisThread
, const char* pathToInitialize
,
915 InitializerTimingList
& timingInfo
, UninitedUpwards
&)
918 if ( hasDylib(pathToInitialize
, &imageIndex
) ) {
919 UpwardIndexes upsBuffer
[256];
920 UpwardIndexes
& ups
= upsBuffer
[0];
922 this->recursiveInitialization(context
, thisThread
, imageIndex
, timingInfo
, ups
);
923 for (int i
=0; i
< ups
.count
; ++i
) {
924 UpwardIndexes upsBuffer2
[256];
925 UpwardIndexes
& ignoreUp
= upsBuffer2
[0];
927 this->recursiveInitialization(context
, thisThread
, ups
.images
[i
], timingInfo
, ignoreUp
);
932 void ImageLoaderMegaDylib::recursiveBind(const LinkContext
& context
, bool forceLazysBound
, bool neverUnload
)
934 markAllbound(context
);
937 uint8_t ImageLoaderMegaDylib::dyldStateToCacheState(dyld_image_states state
) {
939 case dyld_image_state_mapped
:
940 case dyld_image_state_dependents_mapped
:
942 case dyld_image_state_bound
:
943 return kStateFlagBound
;
944 case dyld_image_state_initialized
:
945 return kStateFlagInitialized
;
946 case dyld_image_state_rebased
:
947 case dyld_image_state_dependents_initialized
:
948 case dyld_image_state_terminated
:
954 void ImageLoaderMegaDylib::recursiveApplyInterposing(const LinkContext
& context
)
956 if ( context
.verboseInterposing
)
957 dyld::log("dyld: interposing %lu tuples onto shared cache\n", fgInterposingTuples
.size());
962 unsigned ImageLoaderMegaDylib::appendImagesToNotify(dyld_image_states state
, bool orLater
, dyld_image_info
* infos
)
964 uint8_t targetCacheState
= dyldStateToCacheState(state
);
965 if ( targetCacheState
== kStateUnused
)
967 unsigned usedCount
= 0;
968 for (int i
=_imageCount
-1; i
>= 0; --i
) {
969 uint16_t index
= _bottomUpArray
[i
];
970 uint8_t imageState
= _stateFlags
[index
];
971 if ( imageState
== kStateFlagWeakBound
)
972 imageState
= kStateFlagBound
;
973 if ( (imageState
== targetCacheState
) || (orLater
&& (imageState
> targetCacheState
)) ) {
974 infos
[usedCount
].imageLoadAddress
= (mach_header
*)getIndexedMachHeader(index
);
975 infos
[usedCount
].imageFilePath
= getIndexedPath(index
);
976 infos
[usedCount
].imageFileModDate
= 0;
984 bool ImageLoaderMegaDylib::dlopenFromCache(const LinkContext
& context
, const char* path
, int mode
, void** handle
)
987 if ( !hasDylib(path
, &imageIndex
) ) {
991 // RTLD_NOLOAD means return handle if already loaded, but don't now load it
992 if ( mode
& RTLD_NOLOAD
) {
993 dyld::gLibSystemHelpers
->releaseGlobalDyldLock();
994 if ( _stateFlags
[imageIndex
] == kStateUnused
) {
1000 this->recursiveMarkLoaded(context
, imageIndex
);
1001 context
.notifyBatch(dyld_image_state_dependents_mapped
, false);
1002 this->markAllbound(context
);
1003 context
.notifyBatch(dyld_image_state_bound
, false);
1005 this->weakBind(context
);
1007 // <rdar://problem/25069046> Release dyld global lock before running initializers in dlopen() with customer cache
1008 dyld::gLibSystemHelpers
->releaseGlobalDyldLock();
1010 InitializerTimingList timingInfo
[_initializerCount
];
1011 timingInfo
[0].count
= 0;
1012 mach_port_t thisThread
= mach_thread_self();
1013 UpwardIndexes upsBuffer
[256]; // room for 511 dangling upward links
1014 UpwardIndexes
& ups
= upsBuffer
[0];
1016 this->recursiveInitialization(context
, thisThread
, imageIndex
, timingInfo
[0], ups
);
1017 // make sure any upward linked dylibs were initialized
1018 for (int i
=0; i
< ups
.count
; ++i
) {
1019 UpwardIndexes upsBuffer2
[256];
1020 UpwardIndexes
& ignoreUp
= upsBuffer2
[0];
1022 this->recursiveInitialization(context
, thisThread
, ups
.images
[i
], timingInfo
[0], ignoreUp
);
1024 mach_port_deallocate(mach_task_self(), thisThread
);
1025 context
.notifyBatch(dyld_image_state_initialized
, false);
1028 *handle
= makeCacheHandle(imageIndex
, mode
);
1032 bool ImageLoaderMegaDylib::makeCacheHandle(const LinkContext
& context
, unsigned cacheIndex
, int mode
, void** result
)
1034 if ( cacheIndex
>= _imageCount
)
1037 *result
= makeCacheHandle(cacheIndex
, mode
);
1041 void* ImageLoaderMegaDylib::makeCacheHandle(unsigned index
, int mode
)
1043 uint8_t flags
= ((mode
& RTLD_FIRST
) ? 1 : 0);
1046 return (void*)(uintptr_t)( 0xFFEEDDCC00000000LL
| (index
<< 8) | flags
);
1048 return (void*)(uintptr_t)( 0xF8000000 | (index
<< 8) | flags
);
1052 bool ImageLoaderMegaDylib::isCacheHandle(void* handle
, unsigned* index
, uint8_t* flags
)
1055 if ( (((uintptr_t)handle
) >> 32) == 0xFFEEDDCC ) {
1057 *index
= (((uintptr_t)handle
) >> 8) & 0xFFFF;
1059 *flags
= ((uintptr_t)handle
) & 0xFF;
1063 if ( (((uintptr_t)handle
) >> 24) == 0xF8 ) {
1065 *index
= (((uintptr_t)handle
) >> 8) & 0xFFFF;
1067 *flags
= ((uintptr_t)handle
) & 0xFF;
1075 void* ImageLoaderMegaDylib::dlsymFromCache(const LinkContext
& context
, void* handle
, const char* symbolName
, unsigned imageIndex
)
1077 unsigned indexInHandle
;
1079 uintptr_t symAddress
;
1080 if ( handle
== RTLD_SELF
) {
1081 if ( findInChainedTriesAndDependents(context
, symbolName
, imageIndex
, NULL
, true, &symAddress
) )
1082 return (void*)symAddress
;
1084 else if ( handle
== RTLD_NEXT
) {
1085 // FIXME: really need to not look in imageIndex, but look in others.
1086 if ( findInChainedTriesAndDependents(context
, symbolName
, imageIndex
, NULL
, true, &symAddress
) )
1087 return (void*)symAddress
;
1089 else if ( isCacheHandle(handle
, &indexInHandle
, &flags
) ) {
1090 bool searchOnlyFirst
= (flags
& 1); // RTLD_FIRST
1091 // normal dlsym(handle,) semantics is that the handle is just the first place to search. RTLD_FIRST disables that
1092 if ( searchOnlyFirst
) {
1093 if ( findInChainedTries(context
, symbolName
, indexInHandle
, NULL
, true, &symAddress
) )
1094 return (void*)symAddress
;
1097 if ( findInChainedTriesAndDependents(context
, symbolName
, indexInHandle
, NULL
, true, &symAddress
) )
1098 return (void*)symAddress
;
1105 bool ImageLoaderMegaDylib::dladdrFromCache(const void* address
, Dl_info
* info
)
1107 const mach_header
* mh
;
1109 if ( !addressInCache(address
, &mh
, &info
->dli_fname
, &index
) )
1112 info
->dli_fbase
= (void*)mh
;
1113 if ( address
== mh
) {
1114 // special case lookup of header
1115 info
->dli_sname
= "__dso_handle";
1116 info
->dli_saddr
= info
->dli_fbase
;
1120 // find closest symbol in the image
1121 info
->dli_sname
= ImageLoaderMachO::findClosestSymbol(mh
, address
, (const void**)&info
->dli_saddr
);
1123 // never return the mach_header symbol
1124 if ( info
->dli_saddr
== info
->dli_fbase
) {
1125 info
->dli_sname
= NULL
;
1126 info
->dli_saddr
= NULL
;
1130 // strip off leading underscore
1131 if ( info
->dli_sname
!= NULL
) {
1132 if ( info
->dli_sname
[0] == '_' )
1133 info
->dli_sname
= info
->dli_sname
+1;
1139 uintptr_t ImageLoaderMegaDylib::bindLazy(uintptr_t lazyBindingInfoOffset
, const LinkContext
& context
, const mach_header
* mh
, unsigned imageIndex
)
1141 const dyld_info_command
* dyldInfoCmd
= ImageLoaderMachO::findDyldInfoLoadCommand(mh
);
1142 if ( dyldInfoCmd
== NULL
)
1145 const uint8_t* const lazyInfoStart
= &_linkEditBias
[dyldInfoCmd
->lazy_bind_off
];
1146 const uint8_t* const lazyInfoEnd
= &lazyInfoStart
[dyldInfoCmd
->lazy_bind_size
];
1147 uint32_t lbOffset
= (uint32_t)lazyBindingInfoOffset
;
1149 uintptr_t segOffset
;
1151 const char* symbolName
;
1153 if ( ImageLoaderMachO::getLazyBindingInfo(lbOffset
, lazyInfoStart
, lazyInfoEnd
, &segIndex
, &segOffset
, &libraryOrdinal
, &symbolName
, &doneAfterBind
) ) {
1154 //const char* thisPath = getIndexedPath(imageIndex);
1155 //dyld::log("%s needs symbol '%s' from ordinal=%d\n", thisPath, symbolName, libraryOrdinal);
1156 unsigned startDepArrayIndex
= _imageExtras
[imageIndex
].dependentsStartArrayIndex
;
1157 unsigned targetIndex
;
1158 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_SELF
)
1159 targetIndex
= imageIndex
;
1161 targetIndex
= _dependenciesArray
[startDepArrayIndex
+libraryOrdinal
-1] & 0x7FFF;
1162 //const char* targetPath = getIndexedPath(targetIndex);
1163 //dyld::log("%s needs symbol '%s' from %s\n", thisPath, symbolName, targetPath);
1164 uintptr_t targetAddress
;
1165 if ( findInChainedTries(context
, symbolName
, targetIndex
, this, true, &targetAddress
) ) {
1166 if ( uintptr_t segPrefAddress
= ImageLoaderMachO::segPreferredAddress(mh
, segIndex
) ) {
1167 uintptr_t* lp
= (uintptr_t*)(segPrefAddress
+ segOffset
+ _slide
);
1168 //dyld::log(" storing 0x%0lX to lp %p\n", targetAddress, lp);
1169 *lp
= targetAddress
;
1170 return targetAddress
;
1179 #endif // SUPPORT_ACCELERATE_TABLES