]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMegaDylib.cpp
2e45f216e1ebdf239df295a1b40917e8932c92c4
[apple/dyld.git] / src / ImageLoaderMegaDylib.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #if __arm__ || __arm64__
27 #include <System/sys/mman.h>
28 #else
29 #include <sys/mman.h>
30 #endif
31 #include <string.h>
32 #include <dlfcn.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/fcntl.h>
37 #include <sys/stat.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>
43
44 #include "ImageLoaderMegaDylib.h"
45 #include "ImageLoaderMachO.h"
46 #include "mach-o/dyld_images.h"
47 #include "dyldLibSystemInterface.h"
48 #include "dyld.h"
49
50 // from dyld_gdb.cpp
51 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
52
53
54 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
55 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
56 #endif
57
58 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
59 #if __LP64__
60 #define RELOC_SIZE 3
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 {};
66 #else
67 #define RELOC_SIZE 2
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 {};
73 #endif
74
75
76
77 #if SUPPORT_ACCELERATE_TABLES
78
79
80 ImageLoaderMegaDylib* ImageLoaderMegaDylib::makeImageLoaderMegaDylib(const dyld_cache_header* header, long slide, const LinkContext& context)
81 {
82 return new ImageLoaderMegaDylib(header, slide, context);
83 }
84
85 struct DATAdyld {
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
88 ProgramVars vars;
89 };
90
91
92
93
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)
97 {
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;
105 }
106 }
107
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);
128 }
129
130
131 void ImageLoaderMegaDylib::unreachable() const
132 {
133 abort();
134 }
135
136 ImageLoaderMegaDylib::~ImageLoaderMegaDylib()
137 {
138 }
139
140 const char* ImageLoaderMegaDylib::getInstallPath() const {
141 unreachable();
142 }
143
144 const macho_header* ImageLoaderMegaDylib::getIndexedMachHeader(unsigned index) const
145 {
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);
149 }
150
151 const char* ImageLoaderMegaDylib::getIndexedPath(unsigned index) const
152 {
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;
156 }
157
158 const char* ImageLoaderMegaDylib::getIndexedShortName(unsigned index) const
159 {
160 const char* path = getIndexedPath(index);
161 const char* lastSlash = strrchr(path, '/');
162 if ( lastSlash == NULL )
163 return path;
164 else
165 return lastSlash+1;
166 }
167
168 void ImageLoaderMegaDylib::getDylibUUID(unsigned int index, uuid_t uuid) const
169 {
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);
173 }
174
175 void ImageLoaderMegaDylib::printSegments(const macho_header* mh) const
176 {
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) {
182 switch (cmd->cmd) {
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));
186 break;
187 }
188 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
189 }
190 }
191
192 bool ImageLoaderMegaDylib::hasDylib(const char* path, unsigned* index) const
193 {
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);
202 }
203 }
204 if ( imageNode == NULL )
205 return false;
206 #else
207 return false;
208 #endif
209 }
210 *index = (unsigned)read_uleb128(imageNode, _dylibsTrieEnd);
211 return true;
212 }
213
214 bool ImageLoaderMegaDylib::addressInCache(const void* address, const mach_header** mh, const char** path, unsigned* index)
215 {
216 // quick out of bounds check
217 #if __x86_64__
218 if ( (uintptr_t)address < 0x7FFF70000000LL )
219 return false;
220 #else
221 if ( address < (void*)_header )
222 return false;
223 #endif
224 if ( address > _endOfCacheInMemory )
225 return false;
226
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);
235 return true;
236 }
237 }
238
239 return false;
240 }
241
242
243 bool ImageLoaderMegaDylib::findUnwindSections(const void* address, dyld_unwind_sections* info)
244 {
245 const char* path;
246 unsigned index;
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);
251
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);
255
256 return true;
257 }
258 return false;
259 }
260
261
262 unsigned ImageLoaderMegaDylib::findImageIndex(const LinkContext& context, const char* path) const
263 {
264 unsigned index;
265 if ( hasDylib(path, &index) )
266 return index;
267
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] != '/' )
275 continue;
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) ) {
282 return index;
283 }
284 }
285 }
286
287 // handle symlinks embedded in load commands
288 char resolvedPath[PATH_MAX];
289 realpath(path, resolvedPath);
290 int realpathErrno = errno;
291 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
292 if ( (realpathErrno == ENOENT) || (realpathErrno == 0) ) {
293 if ( strcmp(resolvedPath, path) != 0 )
294 return findImageIndex(context, resolvedPath);
295 }
296
297
298 dyld::throwf("no cache image with name (%s)", path);
299 }
300
301 void ImageLoaderMegaDylib::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder, unsigned imageIndex)
302 {
303 it.image = this;
304 it.symbolName = " ";
305 it.loadOrder = loadOrder;
306 it.weakSymbol = false;
307 it.symbolMatches = false;
308 it.done = false;
309 it.curIndex = 0;
310 it.endIndex = _imageExtras[imageIndex].weakBindingsSize;
311 it.address = 0;
312 it.type = 0;
313 it.addend = 0;
314 it.imageIndex = imageIndex;
315 }
316
317 bool ImageLoaderMegaDylib::incrementCoalIterator(CoalIterator& it)
318 {
319 if ( it.done )
320 return false;
321
322 if ( _imageExtras[it.imageIndex].weakBindingsSize == 0 ) {
323 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
324 it.done = true;
325 it.symbolName = "~~~";
326 return true;
327 }
328 const uint8_t* start = (uint8_t*)(_imageExtras[it.imageIndex].weakBindingsAddr + _slide);
329 const uint8_t* end = (uint8_t*)(_imageExtras[it.imageIndex].weakBindingsAddr + _slide + _imageExtras[it.imageIndex].weakBindingsSize);
330 const uint8_t* p = start + it.curIndex;
331 uintptr_t count;
332 uintptr_t skip;
333 uint64_t segOffset;
334 unsigned segIndex;
335 const mach_header* mh;
336 while ( p < end ) {
337 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
338 uint8_t opcode = *p & BIND_OPCODE_MASK;
339 ++p;
340 switch (opcode) {
341 case BIND_OPCODE_DONE:
342 it.done = true;
343 it.curIndex = p - start;
344 it.symbolName = "~~~"; // sorts to end
345 return true;
346 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
347 it.symbolName = (char*)p;
348 it.weakSymbol = ((immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) == 0);
349 it.symbolMatches = false;
350 while (*p != '\0')
351 ++p;
352 ++p;
353 it.curIndex = p - start;
354 return false;
355 case BIND_OPCODE_SET_TYPE_IMM:
356 it.type = immediate;
357 break;
358 case BIND_OPCODE_SET_ADDEND_SLEB:
359 it.addend = read_sleb128(p, end);
360 break;
361 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
362 segIndex = immediate;
363 segOffset = read_uleb128(p, end);
364 mh = (mach_header*)getIndexedMachHeader((unsigned)it.imageIndex);
365 if ( uintptr_t segPrefAddress = ImageLoaderMachO::segPreferredAddress(mh, segIndex) )
366 it.address = segPrefAddress + segOffset + _slide;
367 else
368 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex);
369 break;
370 case BIND_OPCODE_ADD_ADDR_ULEB:
371 it.address += read_uleb128(p, end);
372 break;
373 case BIND_OPCODE_DO_BIND:
374 it.address += sizeof(intptr_t);
375 break;
376 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
377 it.address += read_uleb128(p, end) + sizeof(intptr_t);
378 break;
379 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
380 it.address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
381 break;
382 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
383 count = read_uleb128(p, end);
384 skip = read_uleb128(p, end);
385 for (uint32_t i=0; i < count; ++i) {
386 it.address += skip + sizeof(intptr_t);
387 }
388 break;
389 default:
390 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p, (int)(p-start), this->getPath());
391 }
392 }
393 /// hmmm, BIND_OPCODE_DONE is missing...
394 it.done = true;
395 it.symbolName = "~~~";
396 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
397 return true;
398 }
399
400 uintptr_t ImageLoaderMegaDylib::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
401 {
402 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
403 uintptr_t address;
404 if ( findInChainedTries(context, it.symbolName, (unsigned)it.imageIndex, NULL, false, &address) ) {
405 return address;
406 }
407 return 0;
408 }
409
410 void ImageLoaderMegaDylib::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, unsigned targetIndex, const LinkContext& context)
411 {
412
413 const uint8_t* start = (uint8_t*)(_imageExtras[it.imageIndex].weakBindingsAddr + _slide);
414 const uint8_t* end = (uint8_t*)(_imageExtras[it.imageIndex].weakBindingsAddr + _slide + _imageExtras[it.imageIndex].weakBindingsSize);
415 const uint8_t* p = start + it.curIndex;
416
417 uint8_t type = it.type;
418 uintptr_t address = it.address;
419 const char* symbolName = it.symbolName;
420 intptr_t addend = it.addend;
421 uint64_t segOffset;
422 unsigned segIndex;
423 const mach_header* mh;
424 uintptr_t count;
425 uintptr_t skip;
426 bool done = false;
427 bool boundSomething = false;
428 const char* targetImagePath = targetImage ? targetImage->getIndexedPath(targetIndex) : NULL;
429 while ( !done && (p < end) ) {
430 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
431 uint8_t opcode = *p & BIND_OPCODE_MASK;
432 ++p;
433 switch (opcode) {
434 case BIND_OPCODE_DONE:
435 done = true;
436 break;
437 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
438 done = true;
439 break;
440 case BIND_OPCODE_SET_TYPE_IMM:
441 type = immediate;
442 break;
443 case BIND_OPCODE_SET_ADDEND_SLEB:
444 addend = read_sleb128(p, end);
445 break;
446 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
447 segIndex = immediate;
448 segOffset = read_uleb128(p, end);
449 mh = (mach_header*)getIndexedMachHeader((unsigned)it.imageIndex);
450 if ( uintptr_t segPrefAddress = ImageLoaderMachO::segPreferredAddress(mh, segIndex) )
451 address = segPrefAddress + segOffset + _slide;
452 else
453 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex);
454 break;
455 case BIND_OPCODE_ADD_ADDR_ULEB:
456 address += read_uleb128(p, end);
457 break;
458 case BIND_OPCODE_DO_BIND:
459 ImageLoaderMachO::bindLocation(context, address, value, type, symbolName, addend, getIndexedPath((unsigned)it.imageIndex), targetImagePath, "weak ");
460 boundSomething = true;
461 address += sizeof(intptr_t);
462 break;
463 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
464 ImageLoaderMachO::bindLocation(context, address, value, type, symbolName, addend, getIndexedPath((unsigned)it.imageIndex), targetImagePath, "weak ");
465 boundSomething = true;
466 address += read_uleb128(p, end) + sizeof(intptr_t);
467 break;
468 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
469 ImageLoaderMachO::bindLocation(context, address, value, type, symbolName, addend, getIndexedPath((unsigned)it.imageIndex), targetImagePath, "weak ");
470 boundSomething = true;
471 address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
472 break;
473 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
474 count = read_uleb128(p, end);
475 skip = read_uleb128(p, end);
476 for (uint32_t i=0; i < count; ++i) {
477 ImageLoaderMachO::bindLocation(context, address, value, type, symbolName, addend, getIndexedPath((unsigned)it.imageIndex), targetImagePath, "weak ");
478 boundSomething = true;
479 address += skip + sizeof(intptr_t);
480 }
481 break;
482 default:
483 dyld::throwf("bad bind opcode %d in weak binding info", *p);
484 }
485 }
486 // C++ weak coalescing cannot be tracked by reference counting. Error on side of never unloading.
487 if ( boundSomething && (targetImage != this) )
488 context.addDynamicReference(this, targetImage);
489 }
490
491
492 void ImageLoaderMegaDylib::appendImagesNeedingCoalescing(ImageLoader* images[], unsigned imageIndexes[], unsigned& count)
493 {
494 for (unsigned i=0; i < _imageCount; ++i) {
495 uint16_t index = _bottomUpArray[i];
496 if ( _stateFlags[index] == kStateUnused )
497 continue;
498 if ( _imageExtras[index].weakBindingsSize == 0 )
499 continue;
500 images[count] = this;
501 imageIndexes[count] = index;
502 ++count;
503 }
504 }
505
506
507 bool ImageLoaderMegaDylib::weakSymbolsBound(unsigned index)
508 {
509 return ( _stateFlags[index] >= kStateFlagWeakBound );
510 }
511
512 void ImageLoaderMegaDylib::setWeakSymbolsBound(unsigned index)
513 {
514 if ( _stateFlags[index] == kStateFlagBound )
515 _stateFlags[index] = kStateFlagWeakBound;
516 }
517
518
519 void ImageLoaderMegaDylib::recursiveMarkLoaded(const LinkContext& context, unsigned imageIndex)
520 {
521 if ( _stateFlags[imageIndex] != kStateUnused )
522 return;
523
524 const macho_header* mh = getIndexedMachHeader(imageIndex);
525 const char* path = getIndexedPath(imageIndex);
526
527 if ( context.verboseLoading )
528 dyld::log("dyld: loaded: %s\n", path);
529 if ( context.verboseMapping ) {
530 dyld::log("dyld: Using shared cached for %s\n", path);
531 printSegments(mh);
532 }
533
534 // change state to "loaded" before recursing to break cycles
535 _stateFlags[imageIndex] = kStateLoaded;
536 ++fgImagesUsedFromSharedCache;
537
538 dyld_image_info debuggerInfo;
539 debuggerInfo.imageLoadAddress = (mach_header*)mh;
540 debuggerInfo.imageFilePath = path;
541 debuggerInfo.imageFileModDate = 0;
542 addImagesToAllImages(1, &debuggerInfo);
543
544 if ( _imageExtras[imageIndex].weakBindingsSize != 0 ) {
545 ++fgImagesRequiringCoalescing;
546 ++fgImagesHasWeakDefinitions;
547 }
548
549 unsigned startArrayIndex = _imageExtras[imageIndex].dependentsStartArrayIndex;
550 for (int i=startArrayIndex; _dependenciesArray[i] != 0xFFFF; ++i) {
551 unsigned subDep = (_dependenciesArray[i] & 0x7FFF); // mask off upward bit
552 recursiveMarkLoaded(context, subDep);
553 }
554 }
555
556 void ImageLoaderMegaDylib::recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths, const char* loadPath)
557 {
558 unsigned index = findImageIndex(context, loadPath);
559 recursiveMarkLoaded(context, index);
560 }
561
562 unsigned int ImageLoaderMegaDylib::recursiveUpdateDepth(unsigned int maxDepth)
563 {
564 setDepth(maxDepth);
565 return maxDepth;
566 }
567
568
569 const ImageLoader::Symbol* ImageLoaderMegaDylib::findExportedSymbol(const char* name, bool searchReExports, const char* thisPath, const ImageLoader** foundIn) const
570 {
571 unsigned index;
572 if ( !hasDylib(thisPath, &index) )
573 return NULL;
574 const uint8_t* exportNode;
575 const uint8_t* exportTrieEnd;
576 unsigned foundinIndex;
577 // <rdar://problem/22068598> always search re-exports
578 // the point of searchReExports was to break cycles in dylibs, we don't have cycles in cache, so ok to search deep
579 searchReExports = true;
580 if ( searchReExports ) {
581 if ( !exportTrieHasNodeRecursive(name, index, &exportNode, &exportTrieEnd, &foundinIndex) )
582 return NULL;
583 }
584 else {
585 if ( !exportTrieHasNode(name, index, &exportNode, &exportTrieEnd) )
586 return NULL;
587 }
588 *foundIn = this;
589 return (ImageLoader::Symbol*)exportNode;
590 }
591
592 bool ImageLoaderMegaDylib::exportTrieHasNode(const char* symbolName, unsigned index,
593 const uint8_t** exportNode, const uint8_t** exportTrieEnd) const
594 {
595 const uint8_t* start = (uint8_t*)(_imageExtras[index].exportsTrieAddr + _slide);
596 const uint32_t size = _imageExtras[index].exportsTrieSize;
597 if ( size == 0 )
598 return false;
599 const uint8_t* end = start + size;
600 const uint8_t* node = ImageLoader::trieWalk(start, end, symbolName);
601 if ( node == NULL )
602 return false;
603 *exportNode = node;
604 *exportTrieEnd = end;
605 return true;
606 }
607
608 bool ImageLoaderMegaDylib::exportTrieHasNodeRecursive(const char* symbolName, unsigned index,
609 const uint8_t** exportNode, const uint8_t** exportTrieEnd,
610 unsigned* foundinIndex) const
611 {
612 // look in trie for image index
613 if ( exportTrieHasNode(symbolName, index, exportNode, exportTrieEnd) ) {
614 *foundinIndex = index;
615 return true;
616 }
617 // recursively look in all re-exported tries
618 unsigned startArrayIndex = _imageExtras[index].reExportsStartArrayIndex;
619 for (int i=startArrayIndex; _reExportsArray[i] != 0xFFFF; ++i) {
620 unsigned reExIndex = _reExportsArray[i];
621 if ( exportTrieHasNodeRecursive(symbolName, reExIndex, exportNode, exportTrieEnd, foundinIndex) )
622 return true;
623 }
624 return false;
625 }
626
627 bool ImageLoaderMegaDylib::findExportedSymbolAddress(const LinkContext& context, const char* symbolName,
628 const ImageLoader* requestorImage, int requestorOrdinalOfDef,
629 bool runResolver, const ImageLoader** foundIn, uintptr_t* address) const
630 {
631 const char* definedImagePath = requestorImage->libPath(requestorOrdinalOfDef-1);
632 unsigned index = findImageIndex(context, definedImagePath);
633 *foundIn = this;
634 return findInChainedTries(context, symbolName, index, requestorImage, runResolver, address);
635 }
636
637 uintptr_t ImageLoaderMegaDylib::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
638 const ImageLoader* requestor, bool runResolver, const char* symbolName) const
639 {
640 // scan for with trie contains this node
641 const uint8_t* exportTrieEnd = NULL;
642 unsigned imageIndex = 0xFFFF;
643 const macho_header* mh = NULL;
644 uint64_t unslidTrieNode = ((uintptr_t)sym) - _slide;
645 for (unsigned i=0; i < _imageCount; ++i) {
646 uint64_t start = _imageExtras[i].exportsTrieAddr;
647 uint64_t end = _imageExtras[i].exportsTrieAddr + _imageExtras[i].exportsTrieSize;
648 if ( (start < unslidTrieNode) && (unslidTrieNode < end) ) {
649 exportTrieEnd = (uint8_t*)(end + _slide);
650 imageIndex = i;
651 mh = (macho_header*)(_images[imageIndex].address + _slide);
652 break;
653 }
654 }
655
656 if ( mh == NULL )
657 dyld::throwf("getExportedSymbolAddress(Symbol=%p) not in a cache trie", sym);
658
659 const uint8_t* exportNode = (const uint8_t*)sym;
660 uintptr_t address;
661 processExportNode(context, symbolName ? symbolName : "unknown", imageIndex, exportNode, exportTrieEnd, requestor, runResolver, &address);
662 return address;
663 }
664
665 void ImageLoaderMegaDylib::processExportNode(const LinkContext& context, const char* symbolName, unsigned definedImageIndex,
666 const uint8_t* exportNode, const uint8_t* exportTrieEnd,
667 const ImageLoader* requestorImage, bool runResolver, uintptr_t* address) const
668 {
669 const macho_header* mh = getIndexedMachHeader(definedImageIndex);
670 uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
671 uintptr_t rawAddress;
672 switch ( flags & EXPORT_SYMBOL_FLAGS_KIND_MASK ) {
673 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
674 if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
675 // this node has a stub and resolver, run the resolver to get target address
676 uintptr_t stub = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)mh; // skip over stub
677 // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
678 uintptr_t interposedStub = interposedAddress(context, stub, requestorImage);
679 if ( interposedStub != stub ) {
680 *address = interposedStub;
681 return;
682 }
683 // stub was not interposed, so run resolver
684 typedef uintptr_t (*ResolverProc)(void);
685 ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)mh);
686 *address = (*resolver)();
687 if ( context.verboseBind )
688 dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver, *address);
689 return;
690 }
691 if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
692 // re-export from another dylib, lookup there
693 const uintptr_t ordinal = read_uleb128(exportNode, exportTrieEnd);
694 const char* importedName = (char*)exportNode;
695 if ( importedName[0] == '\0' )
696 importedName = symbolName;
697 unsigned startArrayIndex = _imageExtras[definedImageIndex].dependentsStartArrayIndex;
698 unsigned reExImageIndex = _dependenciesArray[startArrayIndex + ordinal-1] & 0x7FFF;
699 if ( findInChainedTries(context, importedName, reExImageIndex, requestorImage, runResolver, address) )
700 return;
701 dyld::throwf("re-exported symbol '%s' not found for image %s expected re-exported in %s, node=%p",
702 symbolName, getIndexedShortName(definedImageIndex), getIndexedShortName(reExImageIndex), exportNode);
703 }
704 rawAddress = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)mh;
705 *address = interposedAddress(context, rawAddress, requestorImage);
706 return;
707 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
708 if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
709 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, exportNode);
710 *address = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)mh;
711 return;
712 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE:
713 if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
714 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, exportNode);
715 *address = read_uleb128(exportNode, exportTrieEnd);
716 return;
717 default:
718 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, exportNode);
719 }
720 dyld::throwf("unsupported exported symbol node=%p", exportNode);
721 }
722
723 bool ImageLoaderMegaDylib::findInChainedTries(const LinkContext& context, const char* symbolName, unsigned definedImageIndex,
724 const ImageLoader* requestorImage, bool runResolver, uintptr_t* address) const
725 {
726 //dyld::log("findInChainedTries(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
727 const uint8_t* exportNode;
728 const uint8_t* exportTrieEnd;
729 unsigned foundinIndex;
730 if ( !exportTrieHasNodeRecursive(symbolName, definedImageIndex, &exportNode, &exportTrieEnd, &foundinIndex) )
731 return false;
732
733 processExportNode(context, symbolName, foundinIndex, exportNode, exportTrieEnd, requestorImage, runResolver, address);
734 return true;
735 }
736
737
738 bool ImageLoaderMegaDylib::findInChainedTriesAndDependentsExcept(const LinkContext& context, const char* symbolName, unsigned imageIndex,
739 const ImageLoader* requestorImage, bool runResolver, bool alreadyVisited[], uintptr_t* address) const
740 {
741 //dyld::log("findInChainedTriesAndDependentsExcept(sym=%s, index=%u, path=%s)\n", symbolName, imageIndex, getIndexedPath(imageIndex));
742 if ( alreadyVisited[imageIndex] )
743 return false;
744 alreadyVisited[imageIndex] = true;
745
746 if ( findInChainedTries(context, symbolName, imageIndex, requestorImage, runResolver, address) )
747 return true;
748
749 unsigned startArrayIndex = _imageExtras[imageIndex].dependentsStartArrayIndex;
750 for (int i=startArrayIndex; _dependenciesArray[i] != 0xFFFF; ++i) {
751 // ignore upward links
752 if ( (_dependenciesArray[i] & 0x8000) == 0 ) {
753 unsigned depIndex = _dependenciesArray[i] & 0x7FFF;
754 if ( _stateFlags[depIndex] != kStateFlagInitialized )
755 continue;
756 if ( findInChainedTriesAndDependentsExcept(context, symbolName, depIndex, requestorImage, runResolver, alreadyVisited, address) )
757 return true;
758 }
759 }
760 return false;
761 }
762
763 bool ImageLoaderMegaDylib::findInChainedTriesAndDependents(const LinkContext& context, const char* symbolName, unsigned definedImageIndex,
764 const ImageLoader* requestorImage, bool runResolver, uintptr_t* address) const
765 {
766 //dyld::log("findInChainedTriesAndDependents(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
767 if ( findInChainedTries(context, symbolName, definedImageIndex, requestorImage, runResolver, address) )
768 return true;
769
770 bool alreadyVisited[_header->imagesCount];
771 bzero(alreadyVisited, sizeof(alreadyVisited));
772 return findInChainedTriesAndDependentsExcept(context, symbolName, definedImageIndex, requestorImage, runResolver, alreadyVisited, address);
773 }
774
775
776 bool ImageLoaderMegaDylib::flatFindSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, const ImageLoader** image)
777 {
778 // check export trie of all in-use images
779 for (unsigned i=0; i < _imageCount ; ++i) {
780 uint16_t imageIndex = _bottomUpArray[i];
781 if ( _stateFlags[imageIndex] == kStateUnused )
782 continue;
783 if ( onlyInCoalesced && (_imageExtras[imageIndex].weakBindingsSize == 0) )
784 continue;
785 const uint8_t* exportNode;
786 const uint8_t* exportTrieEnd;
787 if ( exportTrieHasNode(name, imageIndex, &exportNode, &exportTrieEnd) ) {
788 *sym = (Symbol*)exportNode;
789 *image = this;
790 return true;
791 }
792 }
793 return false;
794 }
795
796
797 void ImageLoaderMegaDylib::markAllbound(const LinkContext& context)
798 {
799 for (unsigned i=0; i < _imageCount; ++i) {
800 uint16_t imageIndex = _bottomUpArray[i];
801 if ( _stateFlags[imageIndex] == kStateLoaded ) {
802 _stateFlags[imageIndex] = kStateFlagBound;
803 context.notifySingleFromCache(dyld_image_state_bound, (mach_header*)getIndexedMachHeader(imageIndex), getIndexedPath(imageIndex));
804 }
805 }
806 }
807
808
809 void ImageLoaderMegaDylib::recursiveSpinLockAcquire(unsigned int imageIndex, mach_port_t thisThread)
810 {
811 pthread_mutex_lock(&_lockArrayGuard);
812 if ( _lockArray == NULL )
813 _lockArray = (recursive_lock*)calloc(_imageCount, sizeof(recursive_lock));
814 _lockArrayInUseCount++;
815 pthread_mutex_unlock(&_lockArrayGuard);
816
817 recursive_lock* imagesLock = &_lockArray[imageIndex];
818 while ( !OSAtomicCompareAndSwap32Barrier(0, thisThread, (int*)&imagesLock->thread) ) {
819 if ( imagesLock->thread == thisThread )
820 break;
821 }
822 imagesLock->count++;
823 }
824
825 void ImageLoaderMegaDylib::recursiveSpinLockRelease(unsigned int imageIndex, mach_port_t thisThread)
826 {
827 recursive_lock* imagesLock = &_lockArray[imageIndex];
828 if ( --imagesLock->count == 0 )
829 imagesLock->thread = 0;
830
831 pthread_mutex_lock(&_lockArrayGuard);
832 _lockArrayInUseCount--;
833 if ( _lockArrayInUseCount == 0 ) {
834 free((void*)_lockArray);
835 _lockArray = NULL;
836 }
837 pthread_mutex_unlock(&_lockArrayGuard);
838 }
839
840
841 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext& context, mach_port_t thisThread, unsigned int imageIndex,
842 InitializerTimingList& timingInfo)
843 {
844 // Don't do any locking until libSystem.dylib is initialized, so we can malloc() the lock array
845 bool useLock = dyld::gProcessInfo->libSystemInitialized;
846 if ( useLock )
847 recursiveSpinLockAcquire(imageIndex, thisThread);
848
849 // only run initializers if currently in bound state
850 if ( (_stateFlags[imageIndex] == kStateFlagBound) || (_stateFlags[imageIndex] == kStateFlagWeakBound) ) {
851
852 // Each image in cache has its own lock. We only set the state to Initialized if we hold the lock for the image.
853 _stateFlags[imageIndex] = kStateFlagInitialized;
854
855 // first recursively init all dependents
856 unsigned startArrayIndex = _imageExtras[imageIndex].dependentsStartArrayIndex;
857 for (int i=startArrayIndex; _dependenciesArray[i] != 0xFFFF; ++i) {
858 unsigned subDepIndex = _dependenciesArray[i];
859 // ignore upward links
860 if ( (subDepIndex & 0x8000) == 0 )
861 recursiveInitialization(context, thisThread, subDepIndex, timingInfo);
862 }
863
864 // notify objc about this image
865 context.notifySingleFromCache(dyld_image_state_dependents_initialized, (mach_header*)getIndexedMachHeader(imageIndex), getIndexedPath(imageIndex));
866
867 // run all initializers for imageIndex
868 const dyld_cache_accelerator_initializer* pInitStart = _initializers;
869 const dyld_cache_accelerator_initializer* pInitEnd = &pInitStart[_initializerCount];
870 bool ranSomeInitializers = false;
871 uint64_t t1 = mach_absolute_time();
872 for (const dyld_cache_accelerator_initializer* p=pInitStart; p < pInitEnd; ++p) {
873 if ( p->imageIndex == imageIndex ) {
874 Initializer func = (Initializer)(p->functionOffset + (uintptr_t)_header);
875 if ( context.verboseInit )
876 dyld::log("dyld: calling initializer function %p in %s\n", func, getIndexedPath(imageIndex));
877 bool haveLibSystemHelpersBefore = (dyld::gLibSystemHelpers != NULL);
878 func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
879 bool haveLibSystemHelpersAfter = (dyld::gLibSystemHelpers != NULL);
880 ranSomeInitializers = true;
881 if ( !haveLibSystemHelpersBefore && haveLibSystemHelpersAfter ) {
882 // now safe to use malloc() and other calls in libSystem.dylib
883 dyld::gProcessInfo->libSystemInitialized = true;
884 }
885 }
886 }
887 if ( ranSomeInitializers ) {
888 uint64_t t2 = mach_absolute_time();
889 const char* shortName = strrchr(getIndexedPath(imageIndex), '/');
890 if ( shortName == NULL )
891 shortName = getIndexedPath(imageIndex);
892 else
893 ++shortName;
894 timingInfo.images[timingInfo.count].shortName = shortName;
895 timingInfo.images[timingInfo.count].initTime = (t2-t1);
896 timingInfo.count++;
897 }
898 }
899
900 // only unlock if this frame locked (note: libSystemInitialized changes after libSystem's initializer is run)
901 if ( useLock )
902 recursiveSpinLockRelease(imageIndex, thisThread);
903 }
904
905
906 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext& context, mach_port_t thisThread, const char* pathToInitialize,
907 InitializerTimingList& timingInfo, UninitedUpwards& uninitUps)
908 {
909 unsigned imageIndex;
910 if ( hasDylib(pathToInitialize, &imageIndex) ) {
911 this->recursiveInitialization(context, thisThread, imageIndex, timingInfo);
912 }
913 }
914
915 void ImageLoaderMegaDylib::recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload)
916 {
917 markAllbound(context);
918 }
919
920 uint8_t ImageLoaderMegaDylib::dyldStateToCacheState(dyld_image_states state) {
921 switch (state) {
922 case dyld_image_state_mapped:
923 case dyld_image_state_dependents_mapped:
924 return kStateLoaded;
925 case dyld_image_state_bound:
926 return kStateFlagBound;
927 case dyld_image_state_initialized:
928 return kStateFlagInitialized;
929 case dyld_image_state_rebased:
930 case dyld_image_state_dependents_initialized:
931 case dyld_image_state_terminated:
932 return kStateUnused;
933 }
934 return kStateUnused;
935 }
936
937 void ImageLoaderMegaDylib::recursiveApplyInterposing(const LinkContext& context)
938 {
939 if ( context.verboseInterposing )
940 dyld::log("dyld: interposing %lu tuples onto shared cache\n", fgInterposingTuples.size());
941
942
943 }
944
945 unsigned ImageLoaderMegaDylib::appendImagesToNotify(dyld_image_states state, bool orLater, dyld_image_info* infos)
946 {
947 uint8_t targetCacheState = dyldStateToCacheState(state);
948 if ( targetCacheState == kStateUnused )
949 return 0;
950
951 unsigned usedCount = 0;
952 for (int i=_imageCount-1; i > 0; --i) {
953 uint16_t index = _bottomUpArray[i];
954 uint8_t imageState = _stateFlags[index];
955 if ( imageState == kStateFlagWeakBound )
956 imageState = kStateFlagBound;
957 if ( (imageState == targetCacheState) || (orLater && (imageState > targetCacheState)) ) {
958 infos[usedCount].imageLoadAddress = (mach_header*)getIndexedMachHeader(index);
959 infos[usedCount].imageFilePath = getIndexedPath(index);
960 infos[usedCount].imageFileModDate = 0;
961 ++usedCount;
962 }
963 }
964 return usedCount;
965 }
966
967
968 bool ImageLoaderMegaDylib::dlopenFromCache(const LinkContext& context, const char* path, int mode, void** handle)
969 {
970 unsigned imageIndex;
971 if ( !hasDylib(path, &imageIndex) ) {
972 return false;
973 }
974
975 // RTLD_NOLOAD means return handle if already loaded, but don't now load it
976 if ( mode & RTLD_NOLOAD ) {
977 dyld::gLibSystemHelpers->releaseGlobalDyldLock();
978 if ( _stateFlags[imageIndex] == kStateUnused ) {
979 *handle = NULL;
980 return true;
981 }
982 }
983 else {
984 this->recursiveMarkLoaded(context, imageIndex);
985 context.notifyBatch(dyld_image_state_dependents_mapped, false);
986 this->markAllbound(context);
987 context.notifyBatch(dyld_image_state_bound, false);
988
989 this->weakBind(context);
990
991 // <rdar://problem/25069046> Release dyld global lock before running initializers in dlopen() with customer cache
992 dyld::gLibSystemHelpers->releaseGlobalDyldLock();
993
994 InitializerTimingList timingInfo[_initializerCount];
995 timingInfo[0].count = 0;
996 mach_port_t thisThread = mach_thread_self();
997 this->recursiveInitialization(context, thisThread, imageIndex, timingInfo[0]);
998 mach_port_deallocate(mach_task_self(), thisThread);
999 context.notifyBatch(dyld_image_state_initialized, false);
1000 }
1001
1002 *handle = makeCacheHandle(imageIndex, mode);
1003 return true;
1004 }
1005
1006 bool ImageLoaderMegaDylib::makeCacheHandle(const LinkContext& context, unsigned cacheIndex, int mode, void** result)
1007 {
1008 if ( cacheIndex >= _imageCount )
1009 return false;
1010
1011 *result = makeCacheHandle(cacheIndex, mode);
1012 return true;
1013 }
1014
1015 void* ImageLoaderMegaDylib::makeCacheHandle(unsigned index, int mode)
1016 {
1017 uint8_t flags = ((mode & RTLD_FIRST) ? 1 : 0);
1018
1019 #if __LP64__
1020 return (void*)(uintptr_t)( 0xFFEEDDCC00000000LL | (index << 8) | flags);
1021 #else
1022 return (void*)(uintptr_t)( 0xF8000000 | (index << 8) | flags);
1023 #endif
1024 }
1025
1026 bool ImageLoaderMegaDylib::isCacheHandle(void* handle, unsigned* index, uint8_t* flags)
1027 {
1028 #if __LP64__
1029 if ( (((uintptr_t)handle) >> 32) == 0xFFEEDDCC ) {
1030 if ( index )
1031 *index = (((uintptr_t)handle) >> 8) & 0xFFFF;
1032 if ( flags )
1033 *flags = ((uintptr_t)handle) & 0xFF;
1034 return true;
1035 }
1036 #else
1037 if ( (((uintptr_t)handle) >> 24) == 0xF8 ) {
1038 if ( index )
1039 *index = (((uintptr_t)handle) >> 8) & 0xFFFF;
1040 if ( flags )
1041 *flags = ((uintptr_t)handle) & 0xFF;
1042 return true;
1043 }
1044 #endif
1045 return false;
1046 }
1047
1048
1049 void* ImageLoaderMegaDylib::dlsymFromCache(const LinkContext& context, void* handle, const char* symbolName, unsigned imageIndex)
1050 {
1051 unsigned indexInHandle;
1052 uint8_t flags;
1053 uintptr_t symAddress;
1054 if ( handle == RTLD_SELF ) {
1055 if ( findInChainedTriesAndDependents(context, symbolName, imageIndex, NULL, true, &symAddress) )
1056 return (void*)symAddress;
1057 }
1058 else if ( handle == RTLD_NEXT ) {
1059 // FIXME: really need to not look in imageIndex, but look in others.
1060 if ( findInChainedTriesAndDependents(context, symbolName, imageIndex, NULL, true, &symAddress) )
1061 return (void*)symAddress;
1062 }
1063 else if ( isCacheHandle(handle, &indexInHandle, &flags) ) {
1064 bool searchOnlyFirst = (flags & 1); // RTLD_FIRST
1065 // normal dlsym(handle,) semantics is that the handle is just the first place to search. RTLD_FIRST disables that
1066 if ( searchOnlyFirst ) {
1067 if ( findInChainedTries(context, symbolName, indexInHandle, NULL, true, &symAddress) )
1068 return (void*)symAddress;
1069 }
1070 else {
1071 if ( findInChainedTriesAndDependents(context, symbolName, indexInHandle, NULL, true, &symAddress) )
1072 return (void*)symAddress;
1073 }
1074 }
1075
1076 return NULL;
1077 }
1078
1079 bool ImageLoaderMegaDylib::dladdrFromCache(const void* address, Dl_info* info)
1080 {
1081 const mach_header* mh;
1082 unsigned index;
1083 if ( !addressInCache(address, &mh, &info->dli_fname, &index) )
1084 return false;
1085
1086 info->dli_fbase = (void*)mh;
1087 if ( address == mh ) {
1088 // special case lookup of header
1089 info->dli_sname = "__dso_handle";
1090 info->dli_saddr = info->dli_fbase;
1091 return true;
1092 }
1093
1094 // find closest symbol in the image
1095 info->dli_sname = ImageLoaderMachO::findClosestSymbol(mh, address, (const void**)&info->dli_saddr);
1096
1097 // never return the mach_header symbol
1098 if ( info->dli_saddr == info->dli_fbase ) {
1099 info->dli_sname = NULL;
1100 info->dli_saddr = NULL;
1101 return true;
1102 }
1103
1104 // strip off leading underscore
1105 if ( info->dli_sname != NULL ) {
1106 if ( info->dli_sname[0] == '_' )
1107 info->dli_sname = info->dli_sname +1;
1108 }
1109 return true;
1110 }
1111
1112
1113 uintptr_t ImageLoaderMegaDylib::bindLazy(uintptr_t lazyBindingInfoOffset, const LinkContext& context, const mach_header* mh, unsigned imageIndex)
1114 {
1115 const dyld_info_command* dyldInfoCmd = ImageLoaderMachO::findDyldInfoLoadCommand(mh);
1116 if ( dyldInfoCmd == NULL )
1117 return 0;
1118
1119 const uint8_t* const lazyInfoStart = &_linkEditBias[dyldInfoCmd->lazy_bind_off];
1120 const uint8_t* const lazyInfoEnd = &lazyInfoStart[dyldInfoCmd->lazy_bind_size];
1121 uint32_t lbOffset = (uint32_t)lazyBindingInfoOffset;
1122 uint8_t segIndex;
1123 uintptr_t segOffset;
1124 int libraryOrdinal;
1125 const char* symbolName;
1126 bool doneAfterBind;
1127 if ( ImageLoaderMachO::getLazyBindingInfo(lbOffset, lazyInfoStart, lazyInfoEnd, &segIndex, &segOffset, &libraryOrdinal, &symbolName, &doneAfterBind) ) {
1128 //const char* thisPath = getIndexedPath(imageIndex);
1129 //dyld::log("%s needs symbol '%s' from ordinal=%d\n", thisPath, symbolName, libraryOrdinal);
1130 unsigned startDepArrayIndex = _imageExtras[imageIndex].dependentsStartArrayIndex;
1131 unsigned targetIndex;
1132 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF )
1133 targetIndex = imageIndex;
1134 else
1135 targetIndex = _dependenciesArray[startDepArrayIndex+libraryOrdinal-1] & 0x7FFF;
1136 //const char* targetPath = getIndexedPath(targetIndex);
1137 //dyld::log("%s needs symbol '%s' from %s\n", thisPath, symbolName, targetPath);
1138 uintptr_t targetAddress;
1139 if ( findInChainedTries(context, symbolName, targetIndex, this, true, &targetAddress) ) {
1140 if ( uintptr_t segPrefAddress = ImageLoaderMachO::segPreferredAddress(mh, segIndex) ) {
1141 uintptr_t* lp = (uintptr_t*)(segPrefAddress + segOffset + _slide);
1142 //dyld::log(" storing 0x%0lX to lp %p\n", targetAddress, lp);
1143 *lp = targetAddress;
1144 return targetAddress;
1145 }
1146 }
1147 }
1148
1149 return 0;
1150 }
1151
1152
1153 #endif // SUPPORT_ACCELERATE_TABLES
1154
1155
1156