]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMegaDylib.cpp
dyld-750.6.tar.gz
[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 <mach-o/dyld_images.h>
43 #include <libkern/OSAtomic.h>
44
45 #include "ImageLoaderMegaDylib.h"
46 #include "ImageLoaderMachO.h"
47 #include "dyldLibSystemInterface.h"
48 #include "Tracing.h"
49 #include "dyld2.h"
50
51 // from dyld_gdb.cpp
52 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
53
54 extern "C" int _dyld_func_lookup(const char* name, void** address);
55
56
57 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
58 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
59 #endif
60
61 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
62 #if __LP64__
63 #define RELOC_SIZE 3
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 {};
69 #else
70 #define RELOC_SIZE 2
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 {};
76 #endif
77
78
79
80 #if SUPPORT_ACCELERATE_TABLES
81
82
83 ImageLoaderMegaDylib* ImageLoaderMegaDylib::makeImageLoaderMegaDylib(const dyld_cache_header* header, long slide, const macho_header* mainMH, const LinkContext& context)
84 {
85 return new ImageLoaderMegaDylib(header, slide, mainMH, context);
86 }
87
88 struct DATAdyld {
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
91 ProgramVars vars;
92 };
93
94
95
96
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)
100 {
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;
108 }
109 }
110
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);
131 }
132
133
134 void ImageLoaderMegaDylib::unreachable() const
135 {
136 abort();
137 }
138
139 ImageLoaderMegaDylib::~ImageLoaderMegaDylib()
140 {
141 }
142
143 const char* ImageLoaderMegaDylib::getInstallPath() const {
144 unreachable();
145 }
146
147 const macho_header* ImageLoaderMegaDylib::getIndexedMachHeader(unsigned index) const
148 {
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);
152 }
153
154 const char* ImageLoaderMegaDylib::getIndexedPath(unsigned index) const
155 {
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;
159 }
160
161 const char* ImageLoaderMegaDylib::getIndexedShortName(unsigned index) const
162 {
163 const char* path = getIndexedPath(index);
164 const char* lastSlash = strrchr(path, '/');
165 if ( lastSlash == NULL )
166 return path;
167 else
168 return lastSlash+1;
169 }
170
171 void ImageLoaderMegaDylib::getDylibUUID(unsigned int index, uuid_t uuid) const
172 {
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);
176 }
177
178 void ImageLoaderMegaDylib::printSegments(const macho_header* mh) const
179 {
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) {
185 switch (cmd->cmd) {
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));
189 break;
190 }
191 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
192 }
193 }
194
195 bool ImageLoaderMegaDylib::hasDylib(const char* path, unsigned* index) const
196 {
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);
205 }
206 }
207 if ( imageNode == NULL )
208 return false;
209 #else
210 return false;
211 #endif
212 }
213 *index = (unsigned)read_uleb128(imageNode, _dylibsTrieEnd);
214 return true;
215 }
216
217 bool ImageLoaderMegaDylib::addressInCache(const void* address, const mach_header** mh, const char** path, unsigned* index)
218 {
219 // quick out of bounds check
220 #if __x86_64__
221 if ( (uintptr_t)address < 0x7FFF70000000LL )
222 return false;
223 #else
224 if ( address < (void*)_header )
225 return false;
226 #endif
227 if ( address > _endOfCacheInMemory )
228 return false;
229
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);
238 return true;
239 }
240 }
241
242 return false;
243 }
244
245
246 bool ImageLoaderMegaDylib::findUnwindSections(const void* address, dyld_unwind_sections* info)
247 {
248 const char* path;
249 unsigned index;
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);
254
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);
258
259 return true;
260 }
261 return false;
262 }
263
264
265 unsigned ImageLoaderMegaDylib::findImageIndex(const LinkContext& context, const char* path) const
266 {
267 unsigned index;
268 if ( hasDylib(path, &index) )
269 return index;
270
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) )
278 return index;
279 }
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] != '/' )
289 continue;
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) ) {
296 return index;
297 }
298 }
299 }
300 else {
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);
309 }
310 }
311
312 dyld::throwf("no cache image with name (%s)", path);
313 }
314
315 void ImageLoaderMegaDylib::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder, unsigned imageIndex)
316 {
317 it.image = this;
318 it.symbolName = " ";
319 it.loadOrder = loadOrder;
320 it.weakSymbol = false;
321 it.symbolMatches = false;
322 it.done = false;
323 it.curIndex = 0;
324 it.endIndex = _imageExtras[imageIndex].weakBindingsSize;
325 it.address = 0;
326 it.type = 0;
327 it.addend = 0;
328 it.imageIndex = imageIndex;
329 }
330
331 bool ImageLoaderMegaDylib::incrementCoalIterator(CoalIterator& it)
332 {
333 if ( it.done )
334 return false;
335
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
338 it.done = true;
339 it.symbolName = "~~~";
340 return true;
341 }
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;
345 uintptr_t count;
346 uintptr_t skip;
347 uint64_t segOffset;
348 unsigned segIndex;
349 const mach_header* mh;
350 while ( p < end ) {
351 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
352 uint8_t opcode = *p & BIND_OPCODE_MASK;
353 ++p;
354 switch (opcode) {
355 case BIND_OPCODE_DONE:
356 it.done = true;
357 it.curIndex = p - start;
358 it.symbolName = "~~~"; // sorts to end
359 return true;
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;
364 while (*p != '\0')
365 ++p;
366 ++p;
367 it.curIndex = p - start;
368 return false;
369 case BIND_OPCODE_SET_TYPE_IMM:
370 it.type = immediate;
371 break;
372 case BIND_OPCODE_SET_ADDEND_SLEB:
373 it.addend = read_sleb128(p, end);
374 break;
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;
381 else
382 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex);
383 break;
384 case BIND_OPCODE_ADD_ADDR_ULEB:
385 it.address += read_uleb128(p, end);
386 break;
387 case BIND_OPCODE_DO_BIND:
388 it.address += sizeof(intptr_t);
389 break;
390 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
391 it.address += read_uleb128(p, end) + sizeof(intptr_t);
392 break;
393 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
394 it.address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
395 break;
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);
401 }
402 break;
403 default:
404 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p, (int)(p-start), this->getPath());
405 }
406 }
407 /// hmmm, BIND_OPCODE_DONE is missing...
408 it.done = true;
409 it.symbolName = "~~~";
410 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
411 return true;
412 }
413
414 uintptr_t ImageLoaderMegaDylib::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
415 {
416 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
417 uintptr_t address;
418 if ( findInChainedTries(context, it.symbolName, (unsigned)it.imageIndex, NULL, false, &address) ) {
419 return address;
420 }
421 return 0;
422 }
423
424 void ImageLoaderMegaDylib::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, unsigned targetIndex, const LinkContext& context)
425 {
426
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;
430
431 uint8_t type = it.type;
432 uintptr_t address = it.address;
433 const char* symbolName = it.symbolName;
434 intptr_t addend = it.addend;
435 uint64_t segOffset;
436 unsigned segIndex;
437 const mach_header* mh;
438 uintptr_t count;
439 uintptr_t skip;
440 bool done = false;
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;
446 ++p;
447 switch (opcode) {
448 case BIND_OPCODE_DONE:
449 done = true;
450 break;
451 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
452 done = true;
453 break;
454 case BIND_OPCODE_SET_TYPE_IMM:
455 type = immediate;
456 break;
457 case BIND_OPCODE_SET_ADDEND_SLEB:
458 addend = read_sleb128(p, end);
459 break;
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;
466 else
467 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large", segIndex);
468 break;
469 case BIND_OPCODE_ADD_ADDR_ULEB:
470 address += read_uleb128(p, end);
471 break;
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);
476 break;
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);
481 break;
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);
486 break;
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);
494 }
495 break;
496 default:
497 dyld::throwf("bad bind opcode %d in weak binding info", *p);
498 }
499 }
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);
503 }
504
505
506 void ImageLoaderMegaDylib::appendImagesNeedingCoalescing(ImageLoader* images[], unsigned imageIndexes[], unsigned& count)
507 {
508 for (unsigned i=0; i < _imageCount; ++i) {
509 uint16_t index = _bottomUpArray[i];
510 if ( _stateFlags[index] == kStateUnused )
511 continue;
512 if ( _imageExtras[index].weakBindingsSize == 0 )
513 continue;
514 images[count] = this;
515 imageIndexes[count] = index;
516 ++count;
517 }
518 }
519
520
521 bool ImageLoaderMegaDylib::weakSymbolsBound(unsigned index) const
522 {
523 return ( _stateFlags[index] >= kStateFlagWeakBound );
524 }
525
526 void ImageLoaderMegaDylib::setWeakSymbolsBound(unsigned index)
527 {
528 if ( _stateFlags[index] == kStateFlagBound )
529 _stateFlags[index] = kStateFlagWeakBound;
530 }
531
532
533 void ImageLoaderMegaDylib::recursiveMarkLoaded(const LinkContext& context, unsigned imageIndex)
534 {
535 if ( _stateFlags[imageIndex] != kStateUnused )
536 return;
537
538 const macho_header* mh = getIndexedMachHeader(imageIndex);
539 const char* path = getIndexedPath(imageIndex);
540
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);
545 printSegments(mh);
546 }
547
548 // change state to "loaded" before recursing to break cycles
549 _stateFlags[imageIndex] = kStateLoaded;
550 ++fgImagesUsedFromSharedCache;
551
552 dyld_image_info debuggerInfo;
553 debuggerInfo.imageLoadAddress = (mach_header*)mh;
554 debuggerInfo.imageFilePath = path;
555 debuggerInfo.imageFileModDate = 0;
556 addImagesToAllImages(1, &debuggerInfo);
557
558 if ( _imageExtras[imageIndex].weakBindingsSize != 0 ) {
559 ++fgImagesRequiringCoalescing;
560 ++fgImagesHasWeakDefinitions;
561 }
562
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);
567 }
568 }
569
570 void ImageLoaderMegaDylib::recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths, const char* loadPath)
571 {
572 unsigned index = findImageIndex(context, loadPath);
573 recursiveMarkLoaded(context, index);
574 }
575
576 unsigned int ImageLoaderMegaDylib::recursiveUpdateDepth(unsigned int maxDepth)
577 {
578 setDepth(maxDepth);
579 return maxDepth;
580 }
581
582
583 const ImageLoader::Symbol* ImageLoaderMegaDylib::findExportedSymbol(const char* name, bool searchReExports, const char* thisPath, const ImageLoader** foundIn) const
584 {
585 unsigned index;
586 if ( !hasDylib(thisPath, &index) )
587 return NULL;
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) )
596 return NULL;
597 }
598 else {
599 if ( !exportTrieHasNode(name, index, &exportNode, &exportTrieEnd) )
600 return NULL;
601 }
602 *foundIn = this;
603 return (ImageLoader::Symbol*)exportNode;
604 }
605
606 bool ImageLoaderMegaDylib::exportTrieHasNode(const char* symbolName, unsigned index,
607 const uint8_t** exportNode, const uint8_t** exportTrieEnd) const
608 {
609 const uint8_t* start = (uint8_t*)(_imageExtras[index].exportsTrieAddr + _slide);
610 const uint32_t size = _imageExtras[index].exportsTrieSize;
611 if ( size == 0 )
612 return false;
613 const uint8_t* end = start + size;
614 const uint8_t* node = ImageLoader::trieWalk(start, end, symbolName);
615 if ( node == NULL )
616 return false;
617 *exportNode = node;
618 *exportTrieEnd = end;
619 return true;
620 }
621
622 bool ImageLoaderMegaDylib::exportTrieHasNodeRecursive(const char* symbolName, unsigned index,
623 const uint8_t** exportNode, const uint8_t** exportTrieEnd,
624 unsigned* foundinIndex) const
625 {
626 // look in trie for image index
627 if ( exportTrieHasNode(symbolName, index, exportNode, exportTrieEnd) ) {
628 *foundinIndex = index;
629 return true;
630 }
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) )
636 return true;
637 }
638 return false;
639 }
640
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
644 {
645 const char* definedImagePath = requestorImage->libPath(requestorOrdinalOfDef-1);
646 unsigned index = findImageIndex(context, definedImagePath);
647 *foundIn = this;
648 return findInChainedTries(context, symbolName, index, requestorImage, runResolver, address);
649 }
650
651 uintptr_t ImageLoaderMegaDylib::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context,
652 const ImageLoader* requestor, bool runResolver, const char* symbolName) const
653 {
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);
664 imageIndex = i;
665 mh = (macho_header*)(_images[imageIndex].address + _slide);
666 break;
667 }
668 }
669
670 if ( mh == NULL )
671 dyld::throwf("getExportedSymbolAddress(Symbol=%p) not in a cache trie", sym);
672
673 const uint8_t* exportNode = (const uint8_t*)sym;
674 uintptr_t address;
675 processExportNode(context, symbolName ? symbolName : "unknown", imageIndex, exportNode, exportTrieEnd, requestor, runResolver, &address);
676 return address;
677 }
678
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
682 {
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;
695 return;
696 }
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);
703 return;
704 }
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) )
714 return;
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);
717 }
718 rawAddress = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)mh;
719 *address = interposedAddress(context, rawAddress, requestorImage);
720 return;
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;
725 return;
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);
730 return;
731 default:
732 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, exportNode);
733 }
734 //dyld::throwf("unsupported exported symbol node=%p", exportNode);
735 }
736
737 bool ImageLoaderMegaDylib::findInChainedTries(const LinkContext& context, const char* symbolName, unsigned definedImageIndex,
738 const ImageLoader* requestorImage, bool runResolver, uintptr_t* address) const
739 {
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) )
745 return false;
746
747 processExportNode(context, symbolName, foundinIndex, exportNode, exportTrieEnd, requestorImage, runResolver, address);
748 return true;
749 }
750
751
752 bool ImageLoaderMegaDylib::findInChainedTriesAndDependentsExcept(const LinkContext& context, const char* symbolName, unsigned imageIndex,
753 const ImageLoader* requestorImage, bool runResolver, bool alreadyVisited[], uintptr_t* address) const
754 {
755 //dyld::log("findInChainedTriesAndDependentsExcept(sym=%s, index=%u, path=%s)\n", symbolName, imageIndex, getIndexedPath(imageIndex));
756 if ( alreadyVisited[imageIndex] )
757 return false;
758 alreadyVisited[imageIndex] = true;
759
760 if ( findInChainedTries(context, symbolName, imageIndex, requestorImage, runResolver, address) )
761 return true;
762
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 )
769 continue;
770 if ( findInChainedTriesAndDependentsExcept(context, symbolName, depIndex, requestorImage, runResolver, alreadyVisited, address) )
771 return true;
772 }
773 }
774 return false;
775 }
776
777 bool ImageLoaderMegaDylib::findInChainedTriesAndDependents(const LinkContext& context, const char* symbolName, unsigned definedImageIndex,
778 const ImageLoader* requestorImage, bool runResolver, uintptr_t* address) const
779 {
780 //dyld::log("findInChainedTriesAndDependents(sym=%s, index=%u, path=%s)\n", symbolName, definedImageIndex, getIndexedPath(definedImageIndex));
781 if ( findInChainedTries(context, symbolName, definedImageIndex, requestorImage, runResolver, address) )
782 return true;
783
784 bool alreadyVisited[_header->imagesCount];
785 bzero(alreadyVisited, sizeof(alreadyVisited));
786 return findInChainedTriesAndDependentsExcept(context, symbolName, definedImageIndex, requestorImage, runResolver, alreadyVisited, address);
787 }
788
789
790 bool ImageLoaderMegaDylib::flatFindSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, const ImageLoader** image, ImageLoader::CoalesceNotifier notifier)
791 {
792 bool found = false;
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 )
797 continue;
798 const macho_header* mh = getIndexedMachHeader(imageIndex);
799 if ( onlyInCoalesced && (mh->flags & MH_WEAK_DEFINES) == 0 )
800 continue;
801 const uint8_t* exportNode;
802 const uint8_t* exportTrieEnd;
803 if ( exportTrieHasNode(name, imageIndex, &exportNode, &exportTrieEnd) ) {
804 if ( notifier )
805 notifier((Symbol*)exportNode, this, (mach_header*)getIndexedMachHeader(imageIndex));
806 if ( !found ) {
807 *sym = (Symbol*)exportNode;
808 *image = this;
809 found = true;
810 }
811 if ( !onlyInCoalesced )
812 return true;
813 }
814 }
815 return found;
816 }
817
818
819 void ImageLoaderMegaDylib::markAllbound(const LinkContext& context)
820 {
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));
826 }
827 }
828 }
829
830
831 void ImageLoaderMegaDylib::recursiveSpinLockAcquire(unsigned int imageIndex, mach_port_t thisThread)
832 {
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);
838
839 recursive_lock* imagesLock = &_lockArray[imageIndex];
840 while ( !OSAtomicCompareAndSwap32Barrier(0, thisThread, (int*)&imagesLock->thread) ) {
841 if ( imagesLock->thread == thisThread )
842 break;
843 }
844 imagesLock->count++;
845 }
846
847 void ImageLoaderMegaDylib::recursiveSpinLockRelease(unsigned int imageIndex, mach_port_t thisThread)
848 {
849 recursive_lock* imagesLock = &_lockArray[imageIndex];
850 if ( --imagesLock->count == 0 )
851 imagesLock->thread = 0;
852
853 pthread_mutex_lock(&_lockArrayGuard);
854 _lockArrayInUseCount--;
855 if ( _lockArrayInUseCount == 0 ) {
856 free((void*)_lockArray);
857 _lockArray = NULL;
858 }
859 pthread_mutex_unlock(&_lockArrayGuard);
860 }
861
862
863 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext& context, mach_port_t thisThread, unsigned int imageIndex,
864 InitializerTimingList& timingInfo, UpwardIndexes& upInits)
865 {
866 // Don't do any locking until libSystem.dylib is initialized, so we can malloc() the lock array
867 bool useLock = dyld::gProcessInfo->libSystemInitialized;
868 if ( useLock )
869 recursiveSpinLockAcquire(imageIndex, thisThread);
870
871 // only run initializers if currently in bound state
872 if ( (_stateFlags[imageIndex] == kStateFlagBound) || (_stateFlags[imageIndex] == kStateFlagWeakBound) ) {
873
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;
876
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);
884 else
885 upInits.images[upInits.count++] = (subDepIndex & 0x7FFF);
886 }
887
888 // notify objc about this image
889 context.notifySingleFromCache(dyld_image_state_dependents_initialized, (mach_header*)getIndexedMachHeader(imageIndex), getIndexedPath(imageIndex));
890
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);
902 {
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);
905 };
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;
911 }
912 }
913 }
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);
919 else
920 ++shortName;
921 timingInfo.images[timingInfo.count].shortName = shortName;
922 timingInfo.images[timingInfo.count].initTime = (t2-t1);
923 timingInfo.count++;
924 }
925 }
926
927 // only unlock if this frame locked (note: libSystemInitialized changes after libSystem's initializer is run)
928 if ( useLock )
929 recursiveSpinLockRelease(imageIndex, thisThread);
930 }
931
932
933 void ImageLoaderMegaDylib::recursiveInitialization(const LinkContext& context, mach_port_t thisThread, const char* pathToInitialize,
934 InitializerTimingList& timingInfo, UninitedUpwards&)
935 {
936 UpwardIndexes upsBuffer[256];
937 UpwardIndexes& ups = upsBuffer[0];
938 ups.count = 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];
944 ignoreUp.count = 0;
945 this->recursiveInitialization(context, thisThread, ups.images[i], timingInfo, ignoreUp);
946 }
947 }
948
949 void ImageLoaderMegaDylib::recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload)
950 {
951 markAllbound(context);
952 }
953
954 uint8_t ImageLoaderMegaDylib::dyldStateToCacheState(dyld_image_states state) {
955 switch (state) {
956 case dyld_image_state_mapped:
957 case dyld_image_state_dependents_mapped:
958 return kStateLoaded;
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:
966 return kStateUnused;
967 }
968 return kStateUnused;
969 }
970
971 void ImageLoaderMegaDylib::recursiveApplyInterposing(const LinkContext& context)
972 {
973 if ( context.verboseInterposing )
974 dyld::log("dyld: interposing %lu tuples onto shared cache\n", fgInterposingTuples.size());
975
976
977 }
978
979 unsigned ImageLoaderMegaDylib::appendImagesToNotify(dyld_image_states state, bool orLater, dyld_image_info* infos)
980 {
981 uint8_t targetCacheState = dyldStateToCacheState(state);
982 if ( targetCacheState == kStateUnused )
983 return 0;
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;
994 ++usedCount;
995 }
996 }
997 return usedCount;
998 }
999
1000
1001 bool ImageLoaderMegaDylib::dlopenFromCache(const LinkContext& context, const char* path, int mode, void** handle)
1002 {
1003 unsigned imageIndex;
1004 if ( !hasDylib(path, &imageIndex) ) {
1005 return false;
1006 }
1007
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 ) {
1012 *handle = NULL;
1013 return true;
1014 }
1015 }
1016 else {
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);
1021
1022 this->weakBind(context);
1023
1024 // <rdar://problem/25069046> Release dyld global lock before running initializers in dlopen() with customer cache
1025 dyld::gLibSystemHelpers->releaseGlobalDyldLock();
1026
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];
1032 ups.count = 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];
1038 ignoreUp.count = 0;
1039 this->recursiveInitialization(context, thisThread, ups.images[i], timingInfo[0], ignoreUp);
1040 }
1041 mach_port_deallocate(mach_task_self(), thisThread);
1042 context.notifyBatch(dyld_image_state_initialized, false);
1043 }
1044
1045 *handle = makeCacheHandle(imageIndex, mode);
1046 return true;
1047 }
1048
1049 bool ImageLoaderMegaDylib::makeCacheHandle(const LinkContext& context, unsigned cacheIndex, int mode, void** result)
1050 {
1051 if ( cacheIndex >= _imageCount )
1052 return false;
1053
1054 *result = makeCacheHandle(cacheIndex, mode);
1055 return true;
1056 }
1057
1058 void* ImageLoaderMegaDylib::makeCacheHandle(unsigned index, int mode)
1059 {
1060 uint8_t flags = ((mode & RTLD_FIRST) ? 1 : 0);
1061
1062 #if __LP64__
1063 return (void*)(uintptr_t)( 0xFFEEDDCC00000000LL | (index << 8) | flags);
1064 #else
1065 return (void*)(uintptr_t)( 0xF8000000 | (index << 8) | flags);
1066 #endif
1067 }
1068
1069 bool ImageLoaderMegaDylib::isCacheHandle(void* handle, unsigned* index, uint8_t* flags)
1070 {
1071 #if __LP64__
1072 if ( (((uintptr_t)handle) >> 32) == 0xFFEEDDCC ) {
1073 if ( index )
1074 *index = (((uintptr_t)handle) >> 8) & 0xFFFF;
1075 if ( flags )
1076 *flags = ((uintptr_t)handle) & 0xFF;
1077 return true;
1078 }
1079 #else
1080 if ( (((uintptr_t)handle) >> 24) == 0xF8 ) {
1081 if ( index )
1082 *index = (((uintptr_t)handle) >> 8) & 0xFFFF;
1083 if ( flags )
1084 *flags = ((uintptr_t)handle) & 0xFF;
1085 return true;
1086 }
1087 #endif
1088 return false;
1089 }
1090
1091
1092 void* ImageLoaderMegaDylib::dlsymFromCache(const LinkContext& context, void* handle, const char* symbolName, unsigned imageIndex)
1093 {
1094 unsigned indexInHandle;
1095 uint8_t flags;
1096 uintptr_t symAddress;
1097 if ( handle == RTLD_SELF ) {
1098 if ( findInChainedTriesAndDependents(context, symbolName, imageIndex, NULL, true, &symAddress) )
1099 return (void*)symAddress;
1100 }
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;
1105 }
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;
1112 }
1113 else {
1114 if ( findInChainedTriesAndDependents(context, symbolName, indexInHandle, NULL, true, &symAddress) )
1115 return (void*)symAddress;
1116 }
1117 }
1118
1119 return NULL;
1120 }
1121
1122 bool ImageLoaderMegaDylib::dladdrFromCache(const void* address, Dl_info* info)
1123 {
1124 const mach_header* mh;
1125 unsigned index;
1126 if ( !addressInCache(address, &mh, &info->dli_fname, &index) )
1127 return false;
1128
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;
1134 return true;
1135 }
1136
1137 // find closest symbol in the image
1138 info->dli_sname = ImageLoaderMachO::findClosestSymbol(mh, address, (const void**)&info->dli_saddr);
1139
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;
1144 return true;
1145 }
1146
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;
1151 }
1152 return true;
1153 }
1154
1155
1156 uintptr_t ImageLoaderMegaDylib::bindLazy(uintptr_t lazyBindingInfoOffset, const LinkContext& context, const mach_header* mh, unsigned imageIndex)
1157 {
1158 const dyld_info_command* dyldInfoCmd = ImageLoaderMachO::findDyldInfoLoadCommand(mh);
1159 if ( dyldInfoCmd == NULL )
1160 return 0;
1161
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;
1165 uint8_t segIndex;
1166 uintptr_t segOffset;
1167 int libraryOrdinal;
1168 const char* symbolName;
1169 bool doneAfterBind;
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;
1177 else
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;
1188 }
1189 }
1190 }
1191
1192 return 0;
1193 }
1194
1195
1196 #endif // SUPPORT_ACCELERATE_TABLES
1197
1198
1199