]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMachOCompressed.cpp
329b81dbb0acadd97b5eb3d83ae77dc1715bb6ee
[apple/dyld.git] / src / ImageLoaderMachOCompressed.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008 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 <fcntl.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/fcntl.h>
36 #include <sys/stat.h>
37 #include <sys/param.h>
38 #include <mach/mach.h>
39 #include <mach/thread_status.h>
40 #include <mach-o/loader.h>
41 #include "ImageLoaderMachOCompressed.h"
42 #include "mach-o/dyld_images.h"
43
44 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
45 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
46 #endif
47
48 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
49 #if __LP64__
50 #define RELOC_SIZE 3
51 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
52 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
53 struct macho_segment_command : public segment_command_64 {};
54 struct macho_section : public section_64 {};
55 struct macho_routines_command : public routines_command_64 {};
56 #else
57 #define RELOC_SIZE 2
58 #define LC_SEGMENT_COMMAND LC_SEGMENT
59 #define LC_ROUTINES_COMMAND LC_ROUTINES
60 struct macho_segment_command : public segment_command {};
61 struct macho_section : public section {};
62 struct macho_routines_command : public routines_command {};
63 #endif
64
65
66 static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end)
67 {
68 uint64_t result = 0;
69 int bit = 0;
70 do {
71 if (p == end)
72 dyld::throwf("malformed uleb128");
73
74 uint64_t slice = *p & 0x7f;
75
76 if (bit > 63)
77 dyld::throwf("uleb128 too big for uint64, bit=%d, result=0x%0llX", bit, result);
78 else {
79 result |= (slice << bit);
80 bit += 7;
81 }
82 } while (*p++ & 0x80);
83 return result;
84 }
85
86
87 static intptr_t read_sleb128(const uint8_t*& p, const uint8_t* end)
88 {
89 int64_t result = 0;
90 int bit = 0;
91 uint8_t byte;
92 do {
93 if (p == end)
94 throw "malformed sleb128";
95 byte = *p++;
96 result |= (((int64_t)(byte & 0x7f)) << bit);
97 bit += 7;
98 } while (byte & 0x80);
99 // sign extend negative numbers
100 if ( (byte & 0x40) != 0 )
101 result |= (-1LL) << bit;
102 return result;
103 }
104
105
106 // create image for main executable
107 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path,
108 unsigned int segCount, unsigned int libCount, const LinkContext& context)
109 {
110 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
111
112 // set slide for PIE programs
113 image->setSlide(slide);
114
115 // for PIE record end of program, to know where to start loading dylibs
116 if ( slide != 0 )
117 fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
118
119 image->disableCoverageCheck();
120 image->instantiateFinish(context);
121 image->setMapped(context);
122
123 if ( context.verboseMapping ) {
124 dyld::log("dyld: Main executable mapped %s\n", path);
125 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
126 const char* name = image->segName(i);
127 if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0) )
128 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
129 else
130 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
131 }
132 }
133
134 return image;
135 }
136
137 // create image by mapping in a mach-o file
138 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, size_t lenFileData,
139 uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info,
140 unsigned int segCount, unsigned int libCount,
141 const struct linkedit_data_command* codeSigCmd,
142 const struct encryption_info_command* encryptCmd,
143 const LinkContext& context)
144 {
145 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart((macho_header*)fileData, path, segCount, libCount);
146
147 try {
148 // record info about file
149 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
150
151 // if this image is code signed, let kernel validate signature before mapping any pages from image
152 image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context);
153
154 // Validate that first data we read with pread actually matches with code signature
155 image->validateFirstPages(codeSigCmd, fd, fileData, lenFileData, offsetInFat, context);
156
157 // mmap segments
158 image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
159
160 // if framework is FairPlay encrypted, register with kernel
161 image->registerEncryption(encryptCmd, context);
162
163 // probe to see if code signed correctly
164 image->crashIfInvalidCodeSignature();
165
166 // finish construction
167 image->instantiateFinish(context);
168
169 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
170 const char* installName = image->getInstallPath();
171 if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
172 image->setPathUnowned(installName);
173 #if __MAC_OS_X_VERSION_MIN_REQUIRED
174 // <rdar://problem/6563887> app crashes when libSystem cannot be found
175 else if ( (installName != NULL) && (strcmp(path, "/usr/lib/libgcc_s.1.dylib") == 0) && (strcmp(installName, "/usr/lib/libSystem.B.dylib") == 0) )
176 image->setPathUnowned("/usr/lib/libSystem.B.dylib");
177 #endif
178 else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) {
179 // rdar://problem/10733082 Fix up @rpath based paths during introspection
180 // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
181 char realPath[MAXPATHLEN];
182 if ( fcntl(fd, F_GETPATH, realPath) == 0 )
183 image->setPaths(path, realPath);
184 else
185 image->setPath(path);
186 }
187 else
188 image->setPath(path);
189
190 // make sure path is stable before recording in dyld_all_image_infos
191 image->setMapped(context);
192
193 // pre-fetch content of __DATA and __LINKEDIT segment for faster launches
194 // don't do this on prebound images or if prefetching is disabled
195 if ( !context.preFetchDisabled && !image->isPrebindable()) {
196 image->preFetchDATA(fd, offsetInFat, context);
197 image->markSequentialLINKEDIT(context);
198 }
199 }
200 catch (...) {
201 // ImageLoader::setMapped() can throw an exception to block loading of image
202 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
203 delete image;
204 throw;
205 }
206
207 return image;
208 }
209
210 // create image by using cached mach-o file
211 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(const macho_header* mh, const char* path, long slide,
212 const struct stat& info, unsigned int segCount,
213 unsigned int libCount, const LinkContext& context)
214 {
215 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
216 try {
217 // record info about file
218 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
219
220 // remember this is from shared cache and cannot be unloaded
221 image->fInSharedCache = true;
222 image->setNeverUnload();
223 image->setSlide(slide);
224 image->disableCoverageCheck();
225
226 // segments already mapped in cache
227 if ( context.verboseMapping ) {
228 dyld::log("dyld: Using shared cached for %s\n", path);
229 for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
230 dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
231 }
232 }
233
234 image->instantiateFinish(context);
235 image->setMapped(context);
236 }
237 catch (...) {
238 // ImageLoader::setMapped() can throw an exception to block loading of image
239 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
240 delete image;
241 throw;
242 }
243
244 return image;
245 }
246
247 // create image by copying an in-memory mach-o file
248 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len,
249 unsigned int segCount, unsigned int libCount, const LinkContext& context)
250 {
251 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, moduleName, segCount, libCount);
252 try {
253 // map segments
254 if ( mh->filetype == MH_EXECUTE )
255 throw "can't load another MH_EXECUTE";
256
257 // vmcopy segments
258 image->mapSegments((const void*)mh, len, context);
259
260 // for compatibility, never unload dylibs loaded from memory
261 image->setNeverUnload();
262
263 image->disableCoverageCheck();
264
265 // bundle loads need path copied
266 if ( moduleName != NULL )
267 image->setPath(moduleName);
268
269 image->instantiateFinish(context);
270 image->setMapped(context);
271 }
272 catch (...) {
273 // ImageLoader::setMapped() can throw an exception to block loading of image
274 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
275 delete image;
276 throw;
277 }
278
279 return image;
280 }
281
282
283 ImageLoaderMachOCompressed::ImageLoaderMachOCompressed(const macho_header* mh, const char* path, unsigned int segCount,
284 uint32_t segOffsets[], unsigned int libCount)
285 : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fDyldInfo(NULL)
286 {
287 }
288
289 ImageLoaderMachOCompressed::~ImageLoaderMachOCompressed()
290 {
291 // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
292 destroy();
293 }
294
295
296
297 // construct ImageLoaderMachOCompressed using "placement new" with SegmentMachO objects array at end
298 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateStart(const macho_header* mh, const char* path,
299 unsigned int segCount, unsigned int libCount)
300 {
301 size_t size = sizeof(ImageLoaderMachOCompressed) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
302 ImageLoaderMachOCompressed* allocatedSpace = static_cast<ImageLoaderMachOCompressed*>(malloc(size));
303 if ( allocatedSpace == NULL )
304 throw "malloc failed";
305 uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOCompressed)));
306 bzero(&segOffsets[segCount], libCount*sizeof(void*)); // zero out lib array
307 return new (allocatedSpace) ImageLoaderMachOCompressed(mh, path, segCount, segOffsets, libCount);
308 }
309
310
311 // common code to finish initializing object
312 void ImageLoaderMachOCompressed::instantiateFinish(const LinkContext& context)
313 {
314 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
315 this->parseLoadCmds(context);
316 }
317
318 uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
319 {
320 return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed)));
321 }
322
323
324 ImageLoader* ImageLoaderMachOCompressed::libImage(unsigned int libIndex) const
325 {
326 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
327 // mask off low bits
328 return (ImageLoader*)(images[libIndex] & (-4));
329 }
330
331 bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
332 {
333 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
334 // re-export flag is low bit
335 return ((images[libIndex] & 1) != 0);
336 }
337
338 bool ImageLoaderMachOCompressed::libIsUpward(unsigned int libIndex) const
339 {
340 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
341 // re-export flag is second bit
342 return ((images[libIndex] & 2) != 0);
343 }
344
345
346 void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward)
347 {
348 uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
349 uintptr_t value = (uintptr_t)image;
350 if ( reExported )
351 value |= 1;
352 if ( upward )
353 value |= 2;
354 images[libIndex] = value;
355 }
356
357
358 void ImageLoaderMachOCompressed::markFreeLINKEDIT(const LinkContext& context)
359 {
360 // mark that we are done with rebase and bind info
361 markLINKEDIT(context, MADV_FREE);
362 }
363
364 void ImageLoaderMachOCompressed::markSequentialLINKEDIT(const LinkContext& context)
365 {
366 // mark the rebase and bind info and using sequential access
367 markLINKEDIT(context, MADV_SEQUENTIAL);
368 }
369
370 void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int advise)
371 {
372 // if not loaded at preferred address, mark rebase info
373 uintptr_t start = 0;
374 if ( (fSlide != 0) && (fDyldInfo->rebase_size != 0) )
375 start = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off;
376 else if ( fDyldInfo->bind_off != 0 )
377 start = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off;
378 else
379 return; // no binding info to prefetch
380
381 // end is at end of bind info
382 uintptr_t end = 0;
383 if ( fDyldInfo->bind_off != 0 )
384 end = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off + fDyldInfo->bind_size;
385 else if ( fDyldInfo->rebase_off != 0 )
386 end = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off + fDyldInfo->rebase_size;
387 else
388 return;
389
390
391 // round to whole pages
392 start = dyld_page_trunc(start);
393 end = dyld_page_round(end);
394
395 // do nothing if only one page of rebase/bind info
396 if ( (end-start) <= dyld_page_size )
397 return;
398
399 // tell kernel about our access to these pages
400 madvise((void*)start, end-start, advise);
401 if ( context.verboseMapping ) {
402 const char* adstr = "sequential";
403 if ( advise == MADV_FREE )
404 adstr = "free";
405 dyld::log("%18s %s 0x%0lX -> 0x%0lX for %s\n", "__LINKEDIT", adstr, start, end-1, this->getPath());
406 }
407 }
408
409
410
411 void ImageLoaderMachOCompressed::rebaseAt(const LinkContext& context, uintptr_t addr, uintptr_t slide, uint8_t type)
412 {
413 if ( context.verboseRebase ) {
414 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)addr, slide);
415 }
416 //dyld::log("0x%08lX type=%d\n", addr, type);
417 uintptr_t* locationToFix = (uintptr_t*)addr;
418 switch (type) {
419 case REBASE_TYPE_POINTER:
420 *locationToFix += slide;
421 break;
422 case REBASE_TYPE_TEXT_ABSOLUTE32:
423 *locationToFix += slide;
424 break;
425 default:
426 dyld::throwf("bad rebase type %d", type);
427 }
428 }
429
430 void ImageLoaderMachOCompressed::throwBadRebaseAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex,
431 const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
432 {
433 dyld::throwf("malformed rebase opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
434 (intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex),
435 segActualLoadAddress(segmentIndex), segmentEndAddress);
436 }
437
438 void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
439 {
440 CRSetCrashLogMessage2(this->getPath());
441 const uintptr_t slide = this->fSlide;
442 const uint8_t* const start = fLinkEditBase + fDyldInfo->rebase_off;
443 const uint8_t* const end = &start[fDyldInfo->rebase_size];
444 const uint8_t* p = start;
445
446 try {
447 uint8_t type = 0;
448 int segmentIndex = 0;
449 uintptr_t address = segActualLoadAddress(0);
450 uintptr_t segmentEndAddress = segActualEndAddress(0);
451 uintptr_t count;
452 uintptr_t skip;
453 bool done = false;
454 while ( !done && (p < end) ) {
455 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
456 uint8_t opcode = *p & REBASE_OPCODE_MASK;
457 ++p;
458 switch (opcode) {
459 case REBASE_OPCODE_DONE:
460 done = true;
461 break;
462 case REBASE_OPCODE_SET_TYPE_IMM:
463 type = immediate;
464 break;
465 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
466 segmentIndex = immediate;
467 if ( segmentIndex >= fSegmentsCount )
468 dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
469 segmentIndex, fSegmentsCount-1);
470 address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
471 segmentEndAddress = segActualEndAddress(segmentIndex);
472 break;
473 case REBASE_OPCODE_ADD_ADDR_ULEB:
474 address += read_uleb128(p, end);
475 break;
476 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
477 address += immediate*sizeof(uintptr_t);
478 break;
479 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
480 for (int i=0; i < immediate; ++i) {
481 if ( address >= segmentEndAddress )
482 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
483 rebaseAt(context, address, slide, type);
484 address += sizeof(uintptr_t);
485 }
486 fgTotalRebaseFixups += immediate;
487 break;
488 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
489 count = read_uleb128(p, end);
490 for (uint32_t i=0; i < count; ++i) {
491 if ( address >= segmentEndAddress )
492 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
493 rebaseAt(context, address, slide, type);
494 address += sizeof(uintptr_t);
495 }
496 fgTotalRebaseFixups += count;
497 break;
498 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
499 if ( address >= segmentEndAddress )
500 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
501 rebaseAt(context, address, slide, type);
502 address += read_uleb128(p, end) + sizeof(uintptr_t);
503 ++fgTotalRebaseFixups;
504 break;
505 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
506 count = read_uleb128(p, end);
507 skip = read_uleb128(p, end);
508 for (uint32_t i=0; i < count; ++i) {
509 if ( address >= segmentEndAddress )
510 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
511 rebaseAt(context, address, slide, type);
512 address += skip + sizeof(uintptr_t);
513 }
514 fgTotalRebaseFixups += count;
515 break;
516 default:
517 dyld::throwf("bad rebase opcode %d", *p);
518 }
519 }
520 }
521 catch (const char* msg) {
522 const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
523 free((void*)msg);
524 throw newMsg;
525 }
526 CRSetCrashLogMessage2(NULL);
527 }
528
529 //
530 // This function is the hotspot of symbol lookup. It was pulled out of findExportedSymbol()
531 // to enable it to be re-written in assembler if needed.
532 //
533 const uint8_t* ImageLoaderMachOCompressed::trieWalk(const uint8_t* start, const uint8_t* end, const char* s)
534 {
535 const uint8_t* p = start;
536 while ( p != NULL ) {
537 uintptr_t terminalSize = *p++;
538 if ( terminalSize > 127 ) {
539 // except for re-export-with-rename, all terminal sizes fit in one byte
540 --p;
541 terminalSize = read_uleb128(p, end);
542 }
543 if ( (*s == '\0') && (terminalSize != 0) ) {
544 //dyld::log("trieWalk(%p) returning %p\n", start, p);
545 return p;
546 }
547 const uint8_t* children = p + terminalSize;
548 //dyld::log("trieWalk(%p) sym=%s, terminalSize=%d, children=%p\n", start, s, terminalSize, children);
549 uint8_t childrenRemaining = *children++;
550 p = children;
551 uintptr_t nodeOffset = 0;
552 for (; childrenRemaining > 0; --childrenRemaining) {
553 const char* ss = s;
554 //dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p);
555 bool wrongEdge = false;
556 // scan whole edge to get to next edge
557 // if edge is longer than target symbol name, don't read past end of symbol name
558 char c = *p;
559 while ( c != '\0' ) {
560 if ( !wrongEdge ) {
561 if ( c != *ss )
562 wrongEdge = true;
563 ++ss;
564 }
565 ++p;
566 c = *p;
567 }
568 if ( wrongEdge ) {
569 // advance to next child
570 ++p; // skip over zero terminator
571 // skip over uleb128 until last byte is found
572 while ( (*p & 0x80) != 0 )
573 ++p;
574 ++p; // skil over last byte of uleb128
575 }
576 else {
577 // the symbol so far matches this edge (child)
578 // so advance to the child's node
579 ++p;
580 nodeOffset = read_uleb128(p, end);
581 s = ss;
582 //dyld::log("trieWalk() found matching edge advancing to node 0x%x\n", nodeOffset);
583 break;
584 }
585 }
586 if ( nodeOffset != 0 )
587 p = &start[nodeOffset];
588 else
589 p = NULL;
590 }
591 //dyld::log("trieWalk(%p) return NULL\n", start);
592 return NULL;
593 }
594
595
596 const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol, const ImageLoader** foundIn) const
597 {
598 //dyld::log("Compressed::findExportedSymbol(%s) in %s\n", symbol, this->getShortName());
599 if ( fDyldInfo->export_size == 0 )
600 return NULL;
601 #if LOG_BINDINGS
602 dyld::logBindings("%s: %s\n", this->getShortName(), symbol);
603 #endif
604 ++ImageLoaderMachO::fgSymbolTrieSearchs;
605 const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
606 const uint8_t* end = &start[fDyldInfo->export_size];
607 const uint8_t* foundNodeStart = this->trieWalk(start, end, symbol);
608 if ( foundNodeStart != NULL ) {
609 const uint8_t* p = foundNodeStart;
610 const uintptr_t flags = read_uleb128(p, end);
611 // found match, return pointer to terminal part of node
612 if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
613 // re-export from another dylib, lookup there
614 const uintptr_t ordinal = read_uleb128(p, end);
615 const char* importedName = (char*)p;
616 if ( importedName[0] == '\0' )
617 importedName = symbol;
618 if ( (ordinal > 0) && (ordinal <= libraryCount()) ) {
619 const ImageLoader* reexportedFrom = libImage((unsigned int)ordinal-1);
620 //dyld::log("Compressed::findExportedSymbol(), %s -> %s/%s\n", symbol, reexportedFrom->getShortName(), importedName);
621 return reexportedFrom->findExportedSymbol(importedName, true, foundIn);
622 }
623 else {
624 //dyld::throwf("bad mach-o binary, library ordinal (%u) invalid (max %u) for re-exported symbol %s in %s",
625 // ordinal, libraryCount(), symbol, this->getPath());
626 }
627 }
628 else {
629 //dyld::log("findExportedSymbol(%s) in %s found match, returning %p\n", symbol, this->getShortName(), p);
630 if ( foundIn != NULL )
631 *foundIn = (ImageLoader*)this;
632 // return pointer to terminal part of node
633 return (Symbol*)foundNodeStart;
634 }
635 }
636 return NULL;
637 }
638
639
640 bool ImageLoaderMachOCompressed::containsSymbol(const void* addr) const
641 {
642 const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
643 const uint8_t* end = &start[fDyldInfo->export_size];
644 return ( (start <= addr) && (addr < end) );
645 }
646
647
648 uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
649 {
650 const uint8_t* exportNode = (uint8_t*)symbol;
651 const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
652 const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
653 if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
654 throw "symbol is not in trie";
655 //dyld::log("exportedSymbolAddress(): node=%p, nodeOffset=0x%04X in %s\n", symbol, (int)((uint8_t*)symbol - exportTrieStart), this->getShortName());
656 uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
657 switch ( flags & EXPORT_SYMBOL_FLAGS_KIND_MASK ) {
658 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
659 if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
660 // this node has a stub and resolver, run the resolver to get target address
661 uintptr_t stub = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData; // skip over stub
662 // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
663 uintptr_t interposedStub = interposedAddress(context, stub, requestor);
664 if ( interposedStub != stub )
665 return interposedStub;
666 // stub was not interposed, so run resolver
667 typedef uintptr_t (*ResolverProc)(void);
668 ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
669 uintptr_t result = (*resolver)();
670 if ( context.verboseBind )
671 dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver, result);
672 return result;
673 }
674 return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
675 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
676 if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
677 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
678 return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
679 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE:
680 if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
681 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
682 return read_uleb128(exportNode, exportTrieEnd);
683 default:
684 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
685 }
686 }
687
688 bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
689 {
690 const uint8_t* exportNode = (uint8_t*)symbol;
691 const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
692 const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
693 if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
694 throw "symbol is not in trie";
695 uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
696 return ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION );
697 }
698
699
700 const char* ImageLoaderMachOCompressed::exportedSymbolName(const Symbol* symbol) const
701 {
702 throw "NSNameOfSymbol() not supported with compressed LINKEDIT";
703 }
704
705 unsigned int ImageLoaderMachOCompressed::exportedSymbolCount() const
706 {
707 throw "NSSymbolDefinitionCountInObjectFileImage() not supported with compressed LINKEDIT";
708 }
709
710 const ImageLoader::Symbol* ImageLoaderMachOCompressed::exportedSymbolIndexed(unsigned int index) const
711 {
712 throw "NSSymbolDefinitionNameInObjectFileImage() not supported with compressed LINKEDIT";
713 }
714
715 unsigned int ImageLoaderMachOCompressed::importedSymbolCount() const
716 {
717 throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
718 }
719
720 const ImageLoader::Symbol* ImageLoaderMachOCompressed::importedSymbolIndexed(unsigned int index) const
721 {
722 throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
723 }
724
725 const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol* symbol) const
726 {
727 throw "NSSymbolReferenceNameInObjectFileImage() not supported with compressed LINKEDIT";
728 }
729
730
731
732 uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import,
733 bool runResolver, const ImageLoader** foundIn)
734 {
735 const Symbol* sym;
736 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
737 if ( *foundIn != this )
738 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
739 return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
740 }
741 // if a bundle is loaded privately the above will not find its exports
742 if ( this->isBundle() && this->hasHiddenExports() ) {
743 // look in self for needed symbol
744 sym = this->ImageLoaderMachO::findExportedSymbol(symbolName, false, foundIn);
745 if ( sym != NULL )
746 return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
747 }
748 if ( weak_import ) {
749 // definition can't be found anywhere, ok because it is weak, just return 0
750 return 0;
751 }
752 throwSymbolNotFound(context, symbolName, this->getPath(), "", "flat namespace");
753 }
754
755
756 uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import,
757 const char* symbolName, bool runResolver, const ImageLoader** foundIn)
758 {
759 // two level lookup
760 const Symbol* sym = targetImage->findExportedSymbol(symbolName, true, foundIn);
761 if ( sym != NULL ) {
762 return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
763 }
764
765 if ( weak_import ) {
766 // definition can't be found anywhere, ok because it is weak, just return 0
767 return 0;
768 }
769
770 // nowhere to be found, check if maybe this image is too new for this OS
771 char versMismatch[256];
772 versMismatch[0] = '\0';
773 uint32_t imageMinOS = this->minOSVersion();
774 // dyld is always built for the current OS, so we can get the current OS version
775 // from the load command in dyld itself.
776 extern const mach_header __dso_handle;
777 uint32_t dyldMinOS = ImageLoaderMachO::minOSVersion(&__dso_handle);
778 if ( imageMinOS > dyldMinOS ) {
779 #if __MAC_OS_X_VERSION_MIN_REQUIRED
780 const char* msg = dyld::mkstringf(" (which was built for Mac OS X %d.%d)", imageMinOS >> 16, (imageMinOS >> 8) & 0xFF);
781 #else
782 const char* msg = dyld::mkstringf(" (which was built for iOS %d.%d)", imageMinOS >> 16, (imageMinOS >> 8) & 0xFF);
783 #endif
784 strcpy(versMismatch, msg);
785 ::free((void*)msg);
786 }
787 throwSymbolNotFound(context, symbolName, this->getPath(), versMismatch, targetImage->getPath());
788 }
789
790
791 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const char* symbolName,
792 uint8_t symboFlags, long libraryOrdinal, const ImageLoader** targetImage,
793 LastLookup* last, bool runResolver)
794 {
795 *targetImage = NULL;
796
797 // only clients that benefit from caching last lookup pass in a LastLookup struct
798 if ( last != NULL ) {
799 if ( (last->ordinal == libraryOrdinal)
800 && (last->flags == symboFlags)
801 && (last->name == symbolName) ) {
802 *targetImage = last->foundIn;
803 return last->result;
804 }
805 }
806
807 bool weak_import = (symboFlags & BIND_SYMBOL_FLAGS_WEAK_IMPORT);
808 uintptr_t symbolAddress;
809 if ( context.bindFlat || (libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ) {
810 symbolAddress = this->resolveFlat(context, symbolName, weak_import, runResolver, targetImage);
811 }
812 else {
813 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
814 *targetImage = context.mainExecutable;
815 }
816 else if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF ) {
817 *targetImage = this;
818 }
819 else if ( libraryOrdinal <= 0 ) {
820 dyld::throwf("bad mach-o binary, unknown special library ordinal (%ld) too big for symbol %s in %s",
821 libraryOrdinal, symbolName, this->getPath());
822 }
823 else if ( (unsigned)libraryOrdinal <= libraryCount() ) {
824 *targetImage = libImage((unsigned int)libraryOrdinal-1);
825 }
826 else {
827 dyld::throwf("bad mach-o binary, library ordinal (%ld) too big (max %u) for symbol %s in %s",
828 libraryOrdinal, libraryCount(), symbolName, this->getPath());
829 }
830 if ( *targetImage == NULL ) {
831 if ( weak_import ) {
832 // if target library not loaded and reference is weak or library is weak return 0
833 symbolAddress = 0;
834 }
835 else {
836 dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%ld could not be loaded",
837 symbolName, this->getPath(), libraryOrdinal);
838 }
839 }
840 else {
841 symbolAddress = resolveTwolevel(context, *targetImage, weak_import, symbolName, runResolver, targetImage);
842 }
843 }
844
845 // save off lookup results if client wants
846 if ( last != NULL ) {
847 last->ordinal = libraryOrdinal;
848 last->flags = symboFlags;
849 last->name = symbolName;
850 last->foundIn = *targetImage;
851 last->result = symbolAddress;
852 }
853
854 return symbolAddress;
855 }
856
857 uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName,
858 uint8_t symboFlags, intptr_t addend, long libraryOrdinal, const char* msg,
859 LastLookup* last, bool runResolver)
860 {
861 const ImageLoader* targetImage;
862 uintptr_t symbolAddress;
863
864 // resolve symbol
865 symbolAddress = this->resolve(context, symbolName, symboFlags, libraryOrdinal, &targetImage, last, runResolver);
866
867 // do actual update
868 return this->bindLocation(context, addr, symbolAddress, targetImage, type, symbolName, addend, msg);
869 }
870
871 void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex,
872 const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
873 {
874 dyld::throwf("malformed binding opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
875 (intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex),
876 segActualLoadAddress(segmentIndex), segmentEndAddress);
877 }
878
879
880 void ImageLoaderMachOCompressed::doBind(const LinkContext& context, bool forceLazysBound)
881 {
882 CRSetCrashLogMessage2(this->getPath());
883
884 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
885 // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
886 if ( this->usablePrebinding(context) ) {
887 // don't need to bind
888 }
889 else {
890
891 #if TEXT_RELOC_SUPPORT
892 // if there are __TEXT fixups, temporarily make __TEXT writable
893 if ( fTextSegmentBinds )
894 this->makeTextSegmentWritable(context, true);
895 #endif
896
897 // run through all binding opcodes
898 eachBind(context, &ImageLoaderMachOCompressed::bindAt);
899
900 #if TEXT_RELOC_SUPPORT
901 // if there were __TEXT fixups, restore write protection
902 if ( fTextSegmentBinds )
903 this->makeTextSegmentWritable(context, false);
904 #endif
905
906 // if this image is in the shared cache, but depends on something no longer in the shared cache,
907 // there is no way to reset the lazy pointers, so force bind them now
908 if ( forceLazysBound || fInSharedCache )
909 this->doBindJustLazies(context);
910
911 // this image is in cache, but something below it is not. If
912 // this image has lazy pointer to a resolver function, then
913 // the stub may have been altered to point to a shared lazy pointer.
914 if ( fInSharedCache )
915 this->updateOptimizedLazyPointers(context);
916
917 // tell kernel we are done with chunks of LINKEDIT
918 if ( !context.preFetchDisabled )
919 this->markFreeLINKEDIT(context);
920 }
921
922 // set up dyld entry points in image
923 // do last so flat main executables will have __dyld or __program_vars set up
924 this->setupLazyPointerHandler(context);
925 CRSetCrashLogMessage2(NULL);
926 }
927
928
929 void ImageLoaderMachOCompressed::doBindJustLazies(const LinkContext& context)
930 {
931 eachLazyBind(context, &ImageLoaderMachOCompressed::bindAt);
932 }
933
934 void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handler handler)
935 {
936 try {
937 uint8_t type = 0;
938 int segmentIndex = 0;
939 uintptr_t address = segActualLoadAddress(0);
940 uintptr_t segmentEndAddress = segActualEndAddress(0);
941 const char* symbolName = NULL;
942 uint8_t symboFlags = 0;
943 long libraryOrdinal = 0;
944 intptr_t addend = 0;
945 uintptr_t count;
946 uintptr_t skip;
947 LastLookup last = { 0, 0, NULL, 0, NULL };
948 const uint8_t* const start = fLinkEditBase + fDyldInfo->bind_off;
949 const uint8_t* const end = &start[fDyldInfo->bind_size];
950 const uint8_t* p = start;
951 bool done = false;
952 while ( !done && (p < end) ) {
953 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
954 uint8_t opcode = *p & BIND_OPCODE_MASK;
955 ++p;
956 switch (opcode) {
957 case BIND_OPCODE_DONE:
958 done = true;
959 break;
960 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
961 libraryOrdinal = immediate;
962 break;
963 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
964 libraryOrdinal = read_uleb128(p, end);
965 break;
966 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
967 // the special ordinals are negative numbers
968 if ( immediate == 0 )
969 libraryOrdinal = 0;
970 else {
971 int8_t signExtended = BIND_OPCODE_MASK | immediate;
972 libraryOrdinal = signExtended;
973 }
974 break;
975 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
976 symbolName = (char*)p;
977 symboFlags = immediate;
978 while (*p != '\0')
979 ++p;
980 ++p;
981 break;
982 case BIND_OPCODE_SET_TYPE_IMM:
983 type = immediate;
984 break;
985 case BIND_OPCODE_SET_ADDEND_SLEB:
986 addend = read_sleb128(p, end);
987 break;
988 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
989 segmentIndex = immediate;
990 if ( segmentIndex >= fSegmentsCount )
991 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
992 segmentIndex, fSegmentsCount-1);
993 address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
994 segmentEndAddress = segActualEndAddress(segmentIndex);
995 break;
996 case BIND_OPCODE_ADD_ADDR_ULEB:
997 address += read_uleb128(p, end);
998 break;
999 case BIND_OPCODE_DO_BIND:
1000 if ( address >= segmentEndAddress )
1001 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1002 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
1003 address += sizeof(intptr_t);
1004 break;
1005 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1006 if ( address >= segmentEndAddress )
1007 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1008 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
1009 address += read_uleb128(p, end) + sizeof(intptr_t);
1010 break;
1011 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1012 if ( address >= segmentEndAddress )
1013 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1014 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
1015 address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1016 break;
1017 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1018 count = read_uleb128(p, end);
1019 skip = read_uleb128(p, end);
1020 for (uint32_t i=0; i < count; ++i) {
1021 if ( address >= segmentEndAddress )
1022 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1023 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
1024 address += skip + sizeof(intptr_t);
1025 }
1026 break;
1027 default:
1028 dyld::throwf("bad bind opcode %d in bind info", *p);
1029 }
1030 }
1031 }
1032 catch (const char* msg) {
1033 const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
1034 free((void*)msg);
1035 throw newMsg;
1036 }
1037 }
1038
1039 void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_handler handler)
1040 {
1041 try {
1042 uint8_t type = BIND_TYPE_POINTER;
1043 int segmentIndex = 0;
1044 uintptr_t address = segActualLoadAddress(0);
1045 uintptr_t segmentEndAddress = segActualEndAddress(0);
1046 const char* symbolName = NULL;
1047 uint8_t symboFlags = 0;
1048 long libraryOrdinal = 0;
1049 intptr_t addend = 0;
1050 const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
1051 const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
1052 const uint8_t* p = start;
1053 bool done = false;
1054 while ( !done && (p < end) ) {
1055 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1056 uint8_t opcode = *p & BIND_OPCODE_MASK;
1057 ++p;
1058 switch (opcode) {
1059 case BIND_OPCODE_DONE:
1060 // there is BIND_OPCODE_DONE at end of each lazy bind, don't stop until end of whole sequence
1061 break;
1062 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1063 libraryOrdinal = immediate;
1064 break;
1065 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1066 libraryOrdinal = read_uleb128(p, end);
1067 break;
1068 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1069 // the special ordinals are negative numbers
1070 if ( immediate == 0 )
1071 libraryOrdinal = 0;
1072 else {
1073 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1074 libraryOrdinal = signExtended;
1075 }
1076 break;
1077 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1078 symbolName = (char*)p;
1079 symboFlags = immediate;
1080 while (*p != '\0')
1081 ++p;
1082 ++p;
1083 break;
1084 case BIND_OPCODE_SET_TYPE_IMM:
1085 type = immediate;
1086 break;
1087 case BIND_OPCODE_SET_ADDEND_SLEB:
1088 addend = read_sleb128(p, end);
1089 break;
1090 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1091 segmentIndex = immediate;
1092 if ( segmentIndex >= fSegmentsCount )
1093 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1094 segmentIndex, fSegmentsCount-1);
1095 address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
1096 segmentEndAddress = segActualEndAddress(segmentIndex);
1097 break;
1098 case BIND_OPCODE_ADD_ADDR_ULEB:
1099 address += read_uleb128(p, end);
1100 break;
1101 case BIND_OPCODE_DO_BIND:
1102 if ( address >= segmentEndAddress )
1103 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
1104 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "forced lazy ", NULL, false);
1105 address += sizeof(intptr_t);
1106 break;
1107 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1108 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1109 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1110 default:
1111 dyld::throwf("bad lazy bind opcode %d", *p);
1112 }
1113 }
1114 }
1115
1116 catch (const char* msg) {
1117 const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
1118 free((void*)msg);
1119 throw newMsg;
1120 }
1121 }
1122
1123 // A program built targeting 10.5 will have hybrid stubs. When used with weak symbols
1124 // the classic lazy loader is used even when running on 10.6
1125 uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
1126 {
1127 // only works with compressed LINKEDIT if classic symbol table is also present
1128 const macho_nlist* symbolTable = NULL;
1129 const char* symbolTableStrings = NULL;
1130 const dysymtab_command* dynSymbolTable = NULL;
1131 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1132 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1133 const struct load_command* cmd = cmds;
1134 for (uint32_t i = 0; i < cmd_count; ++i) {
1135 switch (cmd->cmd) {
1136 case LC_SYMTAB:
1137 {
1138 const struct symtab_command* symtab = (struct symtab_command*)cmd;
1139 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
1140 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
1141 }
1142 break;
1143 case LC_DYSYMTAB:
1144 dynSymbolTable = (struct dysymtab_command*)cmd;
1145 break;
1146 }
1147 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1148 }
1149 // no symbol table => no lookup by address
1150 if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
1151 dyld::throwf("classic lazy binding used with compressed LINKEDIT at %p in image %s", lazyPointer, this->getPath());
1152
1153 // scan for all lazy-pointer sections
1154 const bool twoLevel = this->usesTwoLevelNameSpace();
1155 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
1156 cmd = cmds;
1157 for (uint32_t i = 0; i < cmd_count; ++i) {
1158 switch (cmd->cmd) {
1159 case LC_SEGMENT_COMMAND:
1160 {
1161 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1162 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1163 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1164 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1165 const uint8_t type = sect->flags & SECTION_TYPE;
1166 uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
1167 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1168 const size_t pointerCount = sect->size / sizeof(uintptr_t);
1169 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1170 if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
1171 const uint32_t indirectTableOffset = sect->reserved1;
1172 const size_t lazyIndex = lazyPointer - symbolPointers;
1173 symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
1174 }
1175 }
1176 if ( (symbolIndex != INDIRECT_SYMBOL_ABS) && (symbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
1177 const macho_nlist* symbol = &symbolTable[symbolIndex];
1178 const char* symbolName = &symbolTableStrings[symbol->n_un.n_strx];
1179 int libraryOrdinal = GET_LIBRARY_ORDINAL(symbol->n_desc);
1180 if ( !twoLevel || context.bindFlat )
1181 libraryOrdinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
1182 uintptr_t ptrToBind = (uintptr_t)lazyPointer;
1183 uintptr_t symbolAddr = bindAt(context, ptrToBind, BIND_TYPE_POINTER, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL);
1184 ++fgTotalLazyBindFixups;
1185 return symbolAddr;
1186 }
1187 }
1188 }
1189 break;
1190 }
1191 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1192 }
1193 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
1194 }
1195
1196
1197 uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context,
1198 void (*lock)(), void (*unlock)())
1199 {
1200 // <rdar://problem/8663923> race condition with flat-namespace lazy binding
1201 if ( this->usesTwoLevelNameSpace() ) {
1202 // two-level namespace lookup does not require lock because dependents can't be unloaded before this image
1203 }
1204 else {
1205 // acquire dyld global lock
1206 if ( lock != NULL )
1207 lock();
1208 }
1209
1210 const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
1211 const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
1212 if ( lazyBindingInfoOffset > fDyldInfo->lazy_bind_size ) {
1213 dyld::throwf("fast lazy bind offset out of range (%u, max=%u) in image %s",
1214 lazyBindingInfoOffset, fDyldInfo->lazy_bind_size, this->getPath());
1215 }
1216
1217 uint8_t type = BIND_TYPE_POINTER;
1218 uintptr_t address = 0;
1219 const char* symbolName = NULL;
1220 uint8_t symboFlags = 0;
1221 long libraryOrdinal = 0;
1222 bool done = false;
1223 uintptr_t result = 0;
1224 const uint8_t* p = &start[lazyBindingInfoOffset];
1225 while ( !done && (p < end) ) {
1226 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1227 uint8_t opcode = *p & BIND_OPCODE_MASK;
1228 ++p;
1229 switch (opcode) {
1230 case BIND_OPCODE_DONE:
1231 done = true;
1232 break;
1233 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1234 libraryOrdinal = immediate;
1235 break;
1236 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1237 libraryOrdinal = read_uleb128(p, end);
1238 break;
1239 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1240 // the special ordinals are negative numbers
1241 if ( immediate == 0 )
1242 libraryOrdinal = 0;
1243 else {
1244 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1245 libraryOrdinal = signExtended;
1246 }
1247 break;
1248 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1249 symbolName = (char*)p;
1250 symboFlags = immediate;
1251 while (*p != '\0')
1252 ++p;
1253 ++p;
1254 break;
1255 case BIND_OPCODE_SET_TYPE_IMM:
1256 type = immediate;
1257 break;
1258 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1259 if ( immediate >= fSegmentsCount )
1260 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1261 immediate, fSegmentsCount-1);
1262 address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1263 break;
1264 case BIND_OPCODE_DO_BIND:
1265
1266
1267 result = this->bindAt(context, address, type, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL, true);
1268 break;
1269 case BIND_OPCODE_SET_ADDEND_SLEB:
1270 case BIND_OPCODE_ADD_ADDR_ULEB:
1271 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1272 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1273 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1274 default:
1275 dyld::throwf("bad lazy bind opcode %d", *p);
1276 }
1277 }
1278
1279 if ( !this->usesTwoLevelNameSpace() ) {
1280 // release dyld global lock
1281 if ( unlock != NULL )
1282 unlock();
1283 }
1284 return result;
1285 }
1286
1287 void ImageLoaderMachOCompressed::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder)
1288 {
1289 it.image = this;
1290 it.symbolName = " ";
1291 it.loadOrder = loadOrder;
1292 it.weakSymbol = false;
1293 it.symbolMatches = false;
1294 it.done = false;
1295 it.curIndex = 0;
1296 it.endIndex = this->fDyldInfo->weak_bind_size;
1297 it.address = 0;
1298 it.type = 0;
1299 it.addend = 0;
1300 }
1301
1302
1303 bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
1304 {
1305 if ( it.done )
1306 return false;
1307
1308 if ( this->fDyldInfo->weak_bind_size == 0 ) {
1309 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
1310 it.done = true;
1311 it.symbolName = "~~~";
1312 return true;
1313 }
1314 const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
1315 const uint8_t* p = start + it.curIndex;
1316 const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
1317 uintptr_t count;
1318 uintptr_t skip;
1319 while ( p < end ) {
1320 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1321 uint8_t opcode = *p & BIND_OPCODE_MASK;
1322 ++p;
1323 switch (opcode) {
1324 case BIND_OPCODE_DONE:
1325 it.done = true;
1326 it.curIndex = p - start;
1327 it.symbolName = "~~~"; // sorts to end
1328 return true;
1329 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1330 it.symbolName = (char*)p;
1331 it.weakSymbol = ((immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) == 0);
1332 it.symbolMatches = false;
1333 while (*p != '\0')
1334 ++p;
1335 ++p;
1336 it.curIndex = p - start;
1337 return false;
1338 case BIND_OPCODE_SET_TYPE_IMM:
1339 it.type = immediate;
1340 break;
1341 case BIND_OPCODE_SET_ADDEND_SLEB:
1342 it.addend = read_sleb128(p, end);
1343 break;
1344 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1345 if ( immediate >= fSegmentsCount )
1346 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1347 immediate, fSegmentsCount-1);
1348 it.address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1349 break;
1350 case BIND_OPCODE_ADD_ADDR_ULEB:
1351 it.address += read_uleb128(p, end);
1352 break;
1353 case BIND_OPCODE_DO_BIND:
1354 it.address += sizeof(intptr_t);
1355 break;
1356 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1357 it.address += read_uleb128(p, end) + sizeof(intptr_t);
1358 break;
1359 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1360 it.address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1361 break;
1362 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1363 count = read_uleb128(p, end);
1364 skip = read_uleb128(p, end);
1365 for (uint32_t i=0; i < count; ++i) {
1366 it.address += skip + sizeof(intptr_t);
1367 }
1368 break;
1369 default:
1370 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p, (int)(p-start), this->getPath());
1371 }
1372 }
1373 /// hmmm, BIND_OPCODE_DONE is missing...
1374 it.done = true;
1375 it.symbolName = "~~~";
1376 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
1377 return true;
1378 }
1379
1380 uintptr_t ImageLoaderMachOCompressed::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
1381 {
1382 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
1383 const ImageLoader* foundIn = NULL;
1384 const ImageLoader::Symbol* sym = this->findExportedSymbol(it.symbolName, &foundIn);
1385 if ( sym != NULL ) {
1386 //dyld::log("sym=%p, foundIn=%p\n", sym, foundIn);
1387 return foundIn->getExportedSymbolAddress(sym, context, this);
1388 }
1389 return 0;
1390 }
1391
1392
1393 void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context)
1394 {
1395 // <rdar://problem/6570879> weak binding done too early with inserted libraries
1396 if ( this->getState() < dyld_image_state_bound )
1397 return;
1398
1399 const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
1400 const uint8_t* p = start + it.curIndex;
1401 const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
1402
1403 uint8_t type = it.type;
1404 uintptr_t address = it.address;
1405 const char* symbolName = it.symbolName;
1406 intptr_t addend = it.addend;
1407 uintptr_t count;
1408 uintptr_t skip;
1409 bool done = false;
1410 bool boundSomething = false;
1411 while ( !done && (p < end) ) {
1412 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1413 uint8_t opcode = *p & BIND_OPCODE_MASK;
1414 ++p;
1415 switch (opcode) {
1416 case BIND_OPCODE_DONE:
1417 done = true;
1418 break;
1419 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1420 done = true;
1421 break;
1422 case BIND_OPCODE_SET_TYPE_IMM:
1423 type = immediate;
1424 break;
1425 case BIND_OPCODE_SET_ADDEND_SLEB:
1426 addend = read_sleb128(p, end);
1427 break;
1428 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1429 if ( immediate >= fSegmentsCount )
1430 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
1431 immediate, fSegmentsCount-1);
1432 address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1433 break;
1434 case BIND_OPCODE_ADD_ADDR_ULEB:
1435 address += read_uleb128(p, end);
1436 break;
1437 case BIND_OPCODE_DO_BIND:
1438 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1439 boundSomething = true;
1440 address += sizeof(intptr_t);
1441 break;
1442 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1443 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1444 boundSomething = true;
1445 address += read_uleb128(p, end) + sizeof(intptr_t);
1446 break;
1447 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1448 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1449 boundSomething = true;
1450 address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1451 break;
1452 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1453 count = read_uleb128(p, end);
1454 skip = read_uleb128(p, end);
1455 for (uint32_t i=0; i < count; ++i) {
1456 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1457 boundSomething = true;
1458 address += skip + sizeof(intptr_t);
1459 }
1460 break;
1461 default:
1462 dyld::throwf("bad bind opcode %d in weak binding info", *p);
1463 }
1464 }
1465 // C++ weak coalescing cannot be tracked by reference counting. Error on side of never unloading.
1466 if ( boundSomething && (targetImage != this) )
1467 context.addDynamicReference(this, targetImage);
1468 }
1469
1470 uintptr_t ImageLoaderMachOCompressed::interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*,
1471 uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver)
1472 {
1473 if ( type == BIND_TYPE_POINTER ) {
1474 uintptr_t* fixupLocation = (uintptr_t*)addr;
1475 uintptr_t curValue = *fixupLocation;
1476 uintptr_t newValue = interposedAddress(context, curValue, this);
1477 if ( newValue != curValue)
1478 *fixupLocation = newValue;
1479 }
1480 return 0;
1481 }
1482
1483 void ImageLoaderMachOCompressed::doInterpose(const LinkContext& context)
1484 {
1485 if ( context.verboseInterposing )
1486 dyld::log("dyld: interposing %lu tuples onto image: %s\n", fgInterposingTuples.size(), this->getPath());
1487
1488 // update prebound symbols
1489 eachBind(context, &ImageLoaderMachOCompressed::interposeAt);
1490 eachLazyBind(context, &ImageLoaderMachOCompressed::interposeAt);
1491 }
1492
1493
1494 uintptr_t ImageLoaderMachOCompressed::dynamicInterposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName,
1495 uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver)
1496 {
1497 if ( type == BIND_TYPE_POINTER ) {
1498 uintptr_t* fixupLocation = (uintptr_t*)addr;
1499 uintptr_t value = *fixupLocation;
1500 // don't apply interposing to table entries.
1501 if ( (context.dynamicInterposeArray <= (void*)addr) && ((void*)addr < &context.dynamicInterposeArray[context.dynamicInterposeCount]) )
1502 return 0;
1503 for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
1504 if ( value == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
1505 if ( context.verboseInterposing ) {
1506 dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",
1507 fixupLocation, context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
1508 }
1509 *fixupLocation = (uintptr_t)context.dynamicInterposeArray[i].replacement;
1510 }
1511 }
1512 }
1513 return 0;
1514 }
1515
1516 void ImageLoaderMachOCompressed::dynamicInterpose(const LinkContext& context)
1517 {
1518 if ( context.verboseInterposing )
1519 dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context.dynamicInterposeCount, this->getPath());
1520
1521 // update already bound references to symbols
1522 eachBind(context, &ImageLoaderMachOCompressed::dynamicInterposeAt);
1523 eachLazyBind(context, &ImageLoaderMachOCompressed::dynamicInterposeAt);
1524 }
1525
1526
1527 const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr, const void** closestAddr) const
1528 {
1529 // called by dladdr()
1530 // only works with compressed LINKEDIT if classic symbol table is also present
1531 const macho_nlist* symbolTable = NULL;
1532 const char* symbolTableStrings = NULL;
1533 const dysymtab_command* dynSymbolTable = NULL;
1534 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1535 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1536 const struct load_command* cmd = cmds;
1537 for (uint32_t i = 0; i < cmd_count; ++i) {
1538 switch (cmd->cmd) {
1539 case LC_SYMTAB:
1540 {
1541 const struct symtab_command* symtab = (struct symtab_command*)cmd;
1542 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
1543 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
1544 }
1545 break;
1546 case LC_DYSYMTAB:
1547 dynSymbolTable = (struct dysymtab_command*)cmd;
1548 break;
1549 }
1550 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1551 }
1552 // no symbol table => no lookup by address
1553 if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
1554 return NULL;
1555
1556 uintptr_t targetAddress = (uintptr_t)addr - fSlide;
1557 const struct macho_nlist* bestSymbol = NULL;
1558 // first walk all global symbols
1559 const struct macho_nlist* const globalsStart = &symbolTable[dynSymbolTable->iextdefsym];
1560 const struct macho_nlist* const globalsEnd= &globalsStart[dynSymbolTable->nextdefsym];
1561 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
1562 if ( (s->n_type & N_TYPE) == N_SECT ) {
1563 if ( bestSymbol == NULL ) {
1564 if ( s->n_value <= targetAddress )
1565 bestSymbol = s;
1566 }
1567 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
1568 bestSymbol = s;
1569 }
1570 }
1571 }
1572 // next walk all local symbols
1573 const struct macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
1574 const struct macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
1575 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
1576 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
1577 if ( bestSymbol == NULL ) {
1578 if ( s->n_value <= targetAddress )
1579 bestSymbol = s;
1580 }
1581 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
1582 bestSymbol = s;
1583 }
1584 }
1585 }
1586 if ( bestSymbol != NULL ) {
1587 #if __arm__
1588 if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
1589 *closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
1590 else
1591 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
1592 #else
1593 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
1594 #endif
1595 return &symbolTableStrings[bestSymbol->n_un.n_strx];
1596 }
1597 return NULL;
1598 }
1599
1600
1601 #if PREBOUND_IMAGE_SUPPORT
1602 void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& context)
1603 {
1604 // no way to back off a prebound compress image
1605 }
1606 #endif
1607
1608
1609 #if __arm__ || __x86_64__
1610 void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr, const LinkContext& context)
1611 {
1612 #if __arm__
1613 uint32_t* instructions = (uint32_t*)stub;
1614 // sanity check this is a stub we understand
1615 if ( (instructions[0] != 0xe59fc004) || (instructions[1] != 0xe08fc00c) || (instructions[2] != 0xe59cf000) )
1616 return;
1617
1618 void** lazyPointerAddr = (void**)(instructions[3] + (stub + 12));
1619 #endif
1620 #if __x86_64__
1621 // sanity check this is a stub we understand
1622 if ( (stub[0] != 0xFF) || (stub[1] != 0x25) )
1623 return;
1624 int32_t ripOffset = *((int32_t*)(&stub[2]));
1625 void** lazyPointerAddr = (void**)(ripOffset + stub + 6);
1626 #endif
1627
1628 // if stub does not use original lazy pointer (meaning it was optimized by update_dyld_shared_cache)
1629 if ( lazyPointerAddr != originalLazyPointerAddr ) {
1630 // <rdar://problem/12928448> only de-optimization lazy pointers if they are part of shared cache not loaded (because overridden)
1631 const ImageLoader* lazyPointerImage = context.findImageContainingAddress(lazyPointerAddr);
1632 if ( lazyPointerImage != NULL )
1633 return;
1634
1635 // copy newly re-bound lazy pointer value to shared lazy pointer
1636 *lazyPointerAddr = *originalLazyPointerAddr;
1637
1638 if ( context.verboseBind )
1639 dyld::log("dyld: alter bind: %s: *0x%08lX = 0x%08lX \n",
1640 this->getShortName(), (long)lazyPointerAddr, (long)*originalLazyPointerAddr);
1641 }
1642 }
1643 #endif
1644
1645
1646 // <rdar://problem/8890875> overriding shared cache dylibs with resolvers fails
1647 void ImageLoaderMachOCompressed::updateOptimizedLazyPointers(const LinkContext& context)
1648 {
1649 #if __arm__ || __x86_64__
1650 // find stubs and lazy pointer sections
1651 const struct macho_section* stubsSection = NULL;
1652 const struct macho_section* lazyPointerSection = NULL;
1653 const dysymtab_command* dynSymbolTable = NULL;
1654 const macho_header* mh = (macho_header*)fMachOData;
1655 const uint32_t cmd_count = mh->ncmds;
1656 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1657 const struct load_command* cmd = cmds;
1658 for (uint32_t i = 0; i < cmd_count; ++i) {
1659 if (cmd->cmd == LC_SEGMENT_COMMAND) {
1660 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1661 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1662 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1663 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1664 const uint8_t type = sect->flags & SECTION_TYPE;
1665 if ( type == S_SYMBOL_STUBS )
1666 stubsSection = sect;
1667 else if ( type == S_LAZY_SYMBOL_POINTERS )
1668 lazyPointerSection = sect;
1669 }
1670 }
1671 else if ( cmd->cmd == LC_DYSYMTAB ) {
1672 dynSymbolTable = (struct dysymtab_command*)cmd;
1673 }
1674 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1675 }
1676
1677 // sanity check
1678 if ( dynSymbolTable == NULL )
1679 return;
1680 if ( (stubsSection == NULL) || (lazyPointerSection == NULL) )
1681 return;
1682 const uint32_t stubsCount = stubsSection->size / stubsSection->reserved2;
1683 const uint32_t lazyPointersCount = lazyPointerSection->size / sizeof(void*);
1684 if ( stubsCount != lazyPointersCount )
1685 return;
1686 const uint32_t stubsIndirectTableOffset = stubsSection->reserved1;
1687 const uint32_t lazyPointersIndirectTableOffset = lazyPointerSection->reserved1;
1688 if ( (stubsIndirectTableOffset+stubsCount) > dynSymbolTable->nindirectsyms )
1689 return;
1690 if ( (lazyPointersIndirectTableOffset+lazyPointersCount) > dynSymbolTable->nindirectsyms )
1691 return;
1692
1693 // walk stubs and lazy pointers
1694 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
1695 void** const lazyPointersStartAddr = (void**)(lazyPointerSection->addr + this->fSlide);
1696 uint8_t* const stubsStartAddr = (uint8_t*)(stubsSection->addr + this->fSlide);
1697 uint8_t* stub = stubsStartAddr;
1698 void** lpa = lazyPointersStartAddr;
1699 for(uint32_t i=0; i < stubsCount; ++i, stub += stubsSection->reserved2, ++lpa) {
1700 // sanity check symbol index of stub and lazy pointer match
1701 if ( indirectTable[stubsIndirectTableOffset+i] != indirectTable[lazyPointersIndirectTableOffset+i] )
1702 continue;
1703 this->updateAlternateLazyPointer(stub, lpa, context);
1704 }
1705
1706 #endif
1707 }
1708
1709
1710 void ImageLoaderMachOCompressed::registerEncryption(const encryption_info_command* encryptCmd, const LinkContext& context)
1711 {
1712 #if __arm__ || __arm64__
1713 if ( encryptCmd == NULL )
1714 return;
1715 const mach_header* mh = NULL;
1716 for(unsigned int i=0; i < fSegmentsCount; ++i) {
1717 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
1718 mh = (mach_header*)segActualLoadAddress(i);
1719 break;
1720 }
1721 }
1722 void* start = ((uint8_t*)mh) + encryptCmd->cryptoff;
1723 size_t len = encryptCmd->cryptsize;
1724 uint32_t cputype = mh->cputype;
1725 uint32_t cpusubtype = mh->cpusubtype;
1726 uint32_t cryptid = encryptCmd->cryptid;
1727 if (context.verboseMapping) {
1728 dyld::log(" 0x%08lX->0x%08lX configured for FairPlay decryption\n", (long)start, (long)start+len);
1729 }
1730 int result = mremap_encrypted(start, len, cryptid, cputype, cpusubtype);
1731 if ( result != 0 ) {
1732 dyld::throwf("mremap_encrypted() => %d, errno=%d for %s\n", result, errno, this->getPath());
1733 }
1734 #endif
1735 }
1736
1737
1738