]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoaderMachOCompressed.cpp
7d3812bd6617cb174c7be99243b07498bbf7aad6
[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 #include <string.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/fcntl.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <sys/param.h>
34 #include <mach/mach.h>
35 #include <mach/thread_status.h>
36 #include <mach-o/loader.h>
37
38 #include "ImageLoaderMachOCompressed.h"
39 #include "mach-o/dyld_images.h"
40
41
42 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
43 #if __LP64__
44 #define RELOC_SIZE 3
45 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
46 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
47 struct macho_segment_command : public segment_command_64 {};
48 struct macho_section : public section_64 {};
49 struct macho_routines_command : public routines_command_64 {};
50 #else
51 #define RELOC_SIZE 2
52 #define LC_SEGMENT_COMMAND LC_SEGMENT
53 #define LC_ROUTINES_COMMAND LC_ROUTINES
54 struct macho_segment_command : public segment_command {};
55 struct macho_section : public section {};
56 struct macho_routines_command : public routines_command {};
57 #endif
58
59
60 static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end)
61 {
62 uint64_t result = 0;
63 int bit = 0;
64 do {
65 if (p == end)
66 dyld::throwf("malformed uleb128");
67
68 uint64_t slice = *p & 0x7f;
69
70 if (bit >= 64 || slice << bit >> bit != slice)
71 dyld::throwf("uleb128 too big");
72 else {
73 result |= (slice << bit);
74 bit += 7;
75 }
76 }
77 while (*p++ & 0x80);
78 return result;
79 }
80
81
82 static intptr_t read_sleb128(const uint8_t*& p, const uint8_t* end)
83 {
84 int64_t result = 0;
85 int bit = 0;
86 uint8_t byte;
87 do {
88 if (p == end)
89 throw "malformed sleb128";
90 byte = *p++;
91 result |= ((byte & 0x7f) << bit);
92 bit += 7;
93 } while (byte & 0x80);
94 // sign extend negative numbers
95 if ( (byte & 0x40) != 0 )
96 result |= (-1LL) << bit;
97 return result;
98 }
99
100
101 // create image for main executable
102 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path,
103 unsigned int segCount, unsigned int libCount, const LinkContext& context)
104 {
105 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
106
107 // set slide for PIE programs
108 image->setSlide(slide);
109
110 // for PIE record end of program, to know where to start loading dylibs
111 if ( (mh->flags & MH_PIE) && !context.noPIE )
112 fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
113
114 image->setNeverUnload();
115 image->instantiateFinish(context);
116
117 if ( context.verboseMapping ) {
118 dyld::log("dyld: Main executable mapped %s\n", path);
119 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
120 const char* name = image->segName(i);
121 if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0) )
122 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
123 else
124 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
125 }
126 }
127
128 return image;
129 }
130
131 // create image by mapping in a mach-o file
132 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(const char* path, int fd, const uint8_t* fileData,
133 uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info,
134 unsigned int segCount, unsigned int libCount, const LinkContext& context)
135 {
136 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart((macho_header*)fileData, path, segCount, libCount);
137
138 try {
139 // record info about file
140 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
141
142 // mmap segments
143 image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
144
145 // finish construction
146 image->instantiateFinish(context);
147
148 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
149 const char* installName = image->getInstallPath();
150 if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
151 image->setPathUnowned(installName);
152 #if __MAC_OS_X_VERSION_MIN_REQUIRED
153 // <rdar://problem/6563887> app crashes when libSystem cannot be found
154 else if ( (installName != NULL) && (strcmp(path, "/usr/lib/libgcc_s.1.dylib") == 0) && (strcmp(installName, "/usr/lib/libSystem.B.dylib") == 0) )
155 image->setPathUnowned("/usr/lib/libSystem.B.dylib");
156 #endif
157 else if ( path[0] != '/' ) {
158 // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
159 char realPath[MAXPATHLEN];
160 if ( realpath(path, realPath) != NULL )
161 image->setPath(realPath);
162 else
163 image->setPath(path);
164 }
165 else
166 image->setPath(path);
167
168 // pre-fetch content of __DATA and __LINKEDIT segment for faster launches
169 // don't do this on prebound images or if prefetching is disabled
170 if ( !context.preFetchDisabled && !image->isPrebindable()) {
171 image->preFetchDATA(fd, offsetInFat, context);
172 image->markSequentialLINKEDIT(context);
173 }
174 }
175 catch (...) {
176 // ImageLoader::setMapped() can throw an exception to block loading of image
177 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
178 delete image;
179 throw;
180 }
181
182 return image;
183 }
184
185 // create image by using cached mach-o file
186 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info,
187 unsigned int segCount, unsigned int libCount, const LinkContext& context)
188 {
189 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
190 try {
191 // record info about file
192 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
193
194 // remember this is from shared cache and cannot be unloaded
195 image->fInSharedCache = true;
196 image->setNeverUnload();
197
198 // segments already mapped in cache
199 if ( context.verboseMapping ) {
200 dyld::log("dyld: Using shared cached for %s\n", path);
201 for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
202 dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
203 }
204 }
205
206 image->instantiateFinish(context);
207 }
208 catch (...) {
209 // ImageLoader::setMapped() can throw an exception to block loading of image
210 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
211 delete image;
212 throw;
213 }
214
215 return image;
216 }
217
218 // create image by copying an in-memory mach-o file
219 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len,
220 unsigned int segCount, unsigned int libCount, const LinkContext& context)
221 {
222 ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, moduleName, segCount, libCount);
223 try {
224 // map segments
225 if ( mh->filetype == MH_EXECUTE )
226 throw "can't load another MH_EXECUTE";
227
228 // vmcopy segments
229 image->mapSegments((const void*)mh, len, context);
230
231 // for compatibility, never unload dylibs loaded from memory
232 image->setNeverUnload();
233
234 // bundle loads need path copied
235 if ( moduleName != NULL )
236 image->setPath(moduleName);
237
238 image->instantiateFinish(context);
239 }
240 catch (...) {
241 // ImageLoader::setMapped() can throw an exception to block loading of image
242 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
243 delete image;
244 throw;
245 }
246
247 return image;
248 }
249
250
251 ImageLoaderMachOCompressed::ImageLoaderMachOCompressed(const macho_header* mh, const char* path, unsigned int segCount,
252 uint32_t segOffsets[], unsigned int libCount)
253 : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fDyldInfo(NULL)
254 {
255 }
256
257 ImageLoaderMachOCompressed::~ImageLoaderMachOCompressed()
258 {
259 // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
260 destroy();
261 }
262
263
264
265 // construct ImageLoaderMachOCompressed using "placement new" with SegmentMachO objects array at end
266 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateStart(const macho_header* mh, const char* path,
267 unsigned int segCount, unsigned int libCount)
268 {
269 size_t size = sizeof(ImageLoaderMachOCompressed) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
270 ImageLoaderMachOCompressed* allocatedSpace = static_cast<ImageLoaderMachOCompressed*>(malloc(size));
271 if ( allocatedSpace == NULL )
272 throw "malloc failed";
273 uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOCompressed)));
274 bzero(&segOffsets[segCount], libCount*sizeof(void*)); // zero out lib array
275 return new (allocatedSpace) ImageLoaderMachOCompressed(mh, path, segCount, segOffsets, libCount);
276 }
277
278
279 // common code to finish initializing object
280 void ImageLoaderMachOCompressed::instantiateFinish(const LinkContext& context)
281 {
282 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
283 this->parseLoadCmds();
284
285 // notify state change
286 this->setMapped(context);
287 }
288
289 uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
290 {
291 return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed)));
292 }
293
294
295 ImageLoader* ImageLoaderMachOCompressed::libImage(unsigned int libIndex) const
296 {
297 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
298 // mask off low bit
299 return (ImageLoader*)(images[libIndex] & (-2));
300 }
301
302 bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
303 {
304 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
305 // re-export flag is low bit
306 return ((images[libIndex] & 1) != 0);
307 }
308
309
310 void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported)
311 {
312 uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
313 uintptr_t value = (uintptr_t)image;
314 if ( reExported )
315 value |= 1;
316 images[libIndex] = value;
317 }
318
319
320 void ImageLoaderMachOCompressed::markFreeLINKEDIT(const LinkContext& context)
321 {
322 // mark that we are done with rebase and bind info
323 markLINKEDIT(context, MADV_FREE);
324 }
325
326 void ImageLoaderMachOCompressed::markSequentialLINKEDIT(const LinkContext& context)
327 {
328 // mark the rebase and bind info and using sequential access
329 markLINKEDIT(context, MADV_SEQUENTIAL);
330 }
331
332 void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int advise)
333 {
334 // if not loaded at preferred address, mark rebase info
335 uintptr_t start = 0;
336 if ( (fSlide != 0) && (fDyldInfo->rebase_size != 0) )
337 start = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off;
338 else if ( fDyldInfo->bind_off != 0 )
339 start = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off;
340 else
341 return; // no binding info to prefetch
342
343 // end is at end of bind info
344 uintptr_t end = 0;
345 if ( fDyldInfo->bind_off != 0 )
346 end = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off + fDyldInfo->bind_size;
347 else if ( fDyldInfo->rebase_off != 0 )
348 end = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off + fDyldInfo->rebase_size;
349 else
350 return;
351
352
353 // round to whole pages
354 start = start & (-4096);
355 end = (end + 4095) & (-4096);
356
357 // do nothing if only one page of rebase/bind info
358 if ( (end-start) <= 4096 )
359 return;
360
361 // tell kernel about our access to these pages
362 madvise((void*)start, end-start, advise);
363 if ( context.verboseMapping ) {
364 const char* adstr = "sequential";
365 if ( advise == MADV_FREE )
366 adstr = "free";
367 dyld::log("%18s %s 0x%0lX -> 0x%0lX\n", "__LINKEDIT", adstr, start, end-1);
368 }
369 }
370
371
372
373 void ImageLoaderMachOCompressed::rebaseAt(const LinkContext& context, uintptr_t addr, uintptr_t slide, uint8_t type)
374 {
375 //dyld::log("0x%08lX type=%d\n", addr, type);
376 uintptr_t* locationToFix = (uintptr_t*)addr;
377 switch (type) {
378 case REBASE_TYPE_POINTER:
379 *locationToFix += slide;
380 break;
381 case REBASE_TYPE_TEXT_ABSOLUTE32:
382 *locationToFix += slide;
383 break;
384 default:
385 dyld::throwf("bad rebase type %d", type);
386 }
387 }
388
389 void ImageLoaderMachOCompressed::throwBadRebaseAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex,
390 const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
391 {
392 dyld::throwf("malformed rebase opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
393 (intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex),
394 segActualLoadAddress(segmentIndex), segmentEndAddress);
395 }
396
397 void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
398 {
399 const uintptr_t slide = this->fSlide;
400 const uint8_t* const start = fLinkEditBase + fDyldInfo->rebase_off;
401 const uint8_t* const end = &start[fDyldInfo->rebase_size];
402 const uint8_t* p = start;
403
404 try {
405 uint8_t type = 0;
406 int segmentIndex = 0;
407 uintptr_t address = segActualLoadAddress(0);
408 uintptr_t segmentEndAddress = segActualEndAddress(0);
409 uint32_t count;
410 uint32_t skip;
411 bool done = false;
412 while ( !done && (p < end) ) {
413 uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
414 uint8_t opcode = *p & REBASE_OPCODE_MASK;
415 ++p;
416 switch (opcode) {
417 case REBASE_OPCODE_DONE:
418 done = true;
419 break;
420 case REBASE_OPCODE_SET_TYPE_IMM:
421 type = immediate;
422 break;
423 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
424 segmentIndex = immediate;
425 if ( segmentIndex > fSegmentsCount )
426 dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n",
427 segmentIndex, fSegmentsCount);
428 address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
429 segmentEndAddress = segActualEndAddress(segmentIndex);
430 break;
431 case REBASE_OPCODE_ADD_ADDR_ULEB:
432 address += read_uleb128(p, end);
433 break;
434 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
435 address += immediate*sizeof(uintptr_t);
436 break;
437 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
438 for (int i=0; i < immediate; ++i) {
439 if ( address >= segmentEndAddress )
440 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
441 rebaseAt(context, address, slide, type);
442 address += sizeof(uintptr_t);
443 }
444 fgTotalRebaseFixups += immediate;
445 break;
446 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
447 count = read_uleb128(p, end);
448 for (uint32_t i=0; i < count; ++i) {
449 if ( address >= segmentEndAddress )
450 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
451 rebaseAt(context, address, slide, type);
452 address += sizeof(uintptr_t);
453 }
454 fgTotalRebaseFixups += count;
455 break;
456 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
457 if ( address >= segmentEndAddress )
458 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
459 rebaseAt(context, address, slide, type);
460 address += read_uleb128(p, end) + sizeof(uintptr_t);
461 ++fgTotalRebaseFixups;
462 break;
463 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
464 count = read_uleb128(p, end);
465 skip = read_uleb128(p, end);
466 for (uint32_t i=0; i < count; ++i) {
467 if ( address >= segmentEndAddress )
468 throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
469 rebaseAt(context, address, slide, type);
470 address += skip + sizeof(uintptr_t);
471 }
472 fgTotalRebaseFixups += count;
473 break;
474 default:
475 dyld::throwf("bad rebase opcode %d", *p);
476 }
477 }
478 }
479 catch (const char* msg) {
480 const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
481 free((void*)msg);
482 throw newMsg;
483 }
484 }
485
486
487
488
489 const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol, const ImageLoader** foundIn) const
490 {
491 //dyld::log("findExportedSymbolCompressed(%s) in %s\n", symbol, this->getShortName());
492 if ( fDyldInfo->export_size == 0 )
493 return NULL;
494 ++ImageLoaderMachO::fgSymbolTrieSearchs;
495 const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
496 const uint8_t* end = &start[fDyldInfo->export_size];
497 const uint8_t* p = start;
498 const char* s = symbol;
499 do {
500 const uint8_t terminalSize = *p++;
501 const uint8_t* children = p + terminalSize;
502 if ( (*s == '\0') && (terminalSize != 0) ) {
503 // found match, return pointer to terminal part of node
504 //dyld::log("findExportedSymbol(%s) in %s found match, returning %p\n", symbol, this->getShortName(), p);
505 if ( foundIn != NULL )
506 *foundIn = (ImageLoader*)this;
507 return (Symbol*)p;
508 }
509 const uint8_t childrenCount = *children++;
510 const uint8_t* e = children;
511 const uint8_t* newNode = NULL;
512 for (uint8_t i=0; i < childrenCount; ++i) {
513 const char* ss = s;
514 bool wrongEdge = false;
515 //dyld::log("findExportedSymbol() looking at edge %s for match to %s\n", e, s);
516 // scan whole edge to get to next edge
517 // if edge is longer than target symbol name, don't read past end of symbol name
518 while ( *e != '\0' ) {
519 if ( !wrongEdge ) {
520 if ( *e != *ss++ )
521 wrongEdge = true;
522 }
523 ++e;
524 }
525 if ( wrongEdge ) {
526 // advance to next child
527 ++e;
528 read_uleb128(e, end);
529 }
530 else {
531 // the symbol so far matches this edge (child)
532 // so advance to the child's node
533 ++e;
534 uint32_t nodeOffset = read_uleb128(e, end);
535 newNode = &start[nodeOffset];
536 s = ss;
537 //dyld::log("findExportedSymbol() found matching edge advancing to node 0x%x\n", nodeOffset);
538 break;
539 }
540 }
541 if ( newNode != NULL )
542 p = newNode;
543 else {
544 //dyld::log("findExportedSymbol(%s) in %s failed\n", symbol, this->getShortName());
545 return NULL;
546 }
547 } while ( true );
548 }
549
550
551 bool ImageLoaderMachOCompressed::containsSymbol(const void* addr) const
552 {
553 const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
554 const uint8_t* end = &start[fDyldInfo->export_size];
555 return ( (start <= addr) && (addr < end) );
556 }
557
558
559 uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const Symbol* symbol) const
560 {
561 const uint8_t* exportNode = (uint8_t*)symbol;
562 const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
563 const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
564 if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
565 throw "symbol is not in trie";
566 uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
567 if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
568 return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
569 else
570 throw "unsupported exported symbol kind";
571 }
572
573 bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
574 {
575 const uint8_t* exportNode = (uint8_t*)symbol;
576 const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
577 const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
578 if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
579 throw "symbol is not in trie";
580 uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
581 return ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION );
582 }
583
584
585 const char* ImageLoaderMachOCompressed::exportedSymbolName(const Symbol* symbol) const
586 {
587 throw "NSNameOfSymbol() not supported with compressed LINKEDIT";
588 }
589
590 unsigned int ImageLoaderMachOCompressed::exportedSymbolCount() const
591 {
592 throw "NSSymbolDefinitionCountInObjectFileImage() not supported with compressed LINKEDIT";
593 }
594
595 const ImageLoader::Symbol* ImageLoaderMachOCompressed::exportedSymbolIndexed(unsigned int index) const
596 {
597 throw "NSSymbolDefinitionNameInObjectFileImage() not supported with compressed LINKEDIT";
598 }
599
600 unsigned int ImageLoaderMachOCompressed::importedSymbolCount() const
601 {
602 throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
603 }
604
605 const ImageLoader::Symbol* ImageLoaderMachOCompressed::importedSymbolIndexed(unsigned int index) const
606 {
607 throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
608 }
609
610 const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol* symbol) const
611 {
612 throw "NSSymbolReferenceNameInObjectFileImage() not supported with compressed LINKEDIT";
613 }
614
615
616
617 uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, const ImageLoader** foundIn)
618 {
619 const Symbol* sym;
620 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
621 if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
622 this->addDynamicReference(*foundIn);
623 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
624 }
625 // if a bundle is loaded privately the above will not find its exports
626 if ( this->isBundle() && this->hasHiddenExports() ) {
627 // look in self for needed symbol
628 sym = this->ImageLoaderMachO::findExportedSymbol(symbolName, false, foundIn);
629 if ( sym != NULL )
630 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
631 }
632 if ( weak_import ) {
633 // definition can't be found anywhere, ok because it is weak, just return 0
634 return 0;
635 }
636 throwSymbolNotFound(symbolName, this->getPath(), "flat namespace");
637 }
638
639
640 uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import,
641 const char* symbolName, const ImageLoader** foundIn)
642 {
643 // two level lookup
644 const Symbol* sym = targetImage->findExportedSymbol(symbolName, true, foundIn);
645 if ( sym != NULL ) {
646 return (*foundIn)->getExportedSymbolAddress(sym, context, this);
647 }
648
649 if ( weak_import ) {
650 // definition can't be found anywhere, ok because it is weak, just return 0
651 return 0;
652 }
653
654 // nowhere to be found
655 throwSymbolNotFound(symbolName, this->getPath(), targetImage->getPath());
656 }
657
658
659 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const char* symbolName,
660 uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage,
661 LastLookup* last)
662 {
663 *targetImage = NULL;
664
665 // only clients that benefit from caching last lookup pass in a LastLookup struct
666 if ( last != NULL ) {
667 if ( (last->ordinal == libraryOrdinal)
668 && (last->flags == symboFlags)
669 && (last->name == symbolName) ) {
670 *targetImage = last->foundIn;
671 return last->result;
672 }
673 }
674
675 bool weak_import = (symboFlags & BIND_SYMBOL_FLAGS_WEAK_IMPORT);
676 uintptr_t symbolAddress;
677 if ( context.bindFlat || (libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ) {
678 symbolAddress = this->resolveFlat(context, symbolName, weak_import, targetImage);
679 }
680 else {
681 if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
682 *targetImage = context.mainExecutable;
683 }
684 else if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF ) {
685 *targetImage = this;
686 }
687 else if ( libraryOrdinal <= 0 ) {
688 dyld::throwf("bad mach-o binary, unknown special library ordinal (%u) too big for symbol %s in %s",
689 libraryOrdinal, symbolName, this->getPath());
690 }
691 else if ( (unsigned)libraryOrdinal <= libraryCount() ) {
692 *targetImage = libImage(libraryOrdinal-1);
693 }
694 else {
695 dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
696 libraryOrdinal, libraryCount(), symbolName, this->getPath());
697 }
698 if ( *targetImage == NULL ) {
699 if ( weak_import ) {
700 // if target library not loaded and reference is weak or library is weak return 0
701 symbolAddress = 0;
702 }
703 else {
704 dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%d could not be loaded",
705 symbolName, this->getPath(), libraryOrdinal);
706 }
707 }
708 else {
709 symbolAddress = resolveTwolevel(context, *targetImage, weak_import, symbolName, targetImage);
710 }
711 }
712
713 // save off lookup results if client wants
714 if ( last != NULL ) {
715 last->ordinal = libraryOrdinal;
716 last->flags = symboFlags;
717 last->name = symbolName;
718 last->foundIn = *targetImage;
719 last->result = symbolAddress;
720 }
721
722 return symbolAddress;
723 }
724
725 uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName,
726 uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg, LastLookup* last)
727 {
728 const ImageLoader* targetImage;
729 uintptr_t symbolAddress;
730
731 // resolve symbol
732 symbolAddress = this->resolve(context, symbolName, symboFlags, libraryOrdinal, &targetImage, last);
733
734 // do actual update
735 return this->bindLocation(context, addr, symbolAddress, targetImage, type, symbolName, addend, msg);
736 }
737
738 void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex,
739 const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
740 {
741 dyld::throwf("malformed binding opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
742 (intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex),
743 segActualLoadAddress(segmentIndex), segmentEndAddress);
744 }
745
746
747 void ImageLoaderMachOCompressed::doBind(const LinkContext& context, bool forceLazysBound)
748 {
749 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
750 // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
751 if ( this->usablePrebinding(context) ) {
752 // don't need to bind
753 }
754 else {
755 // run through all binding opcodes
756 eachBind(context, &ImageLoaderMachOCompressed::bindAt);
757
758 // if this image is in the shared cache, but depends on someting no longer in the shared cache,
759 // there is no way to reset the lazy pointers, so force bind them now
760 if ( forceLazysBound || fInSharedCache )
761 this->doBindJustLazies(context);
762 }
763
764 // set up dyld entry points in image
765 // do last so flat main executables will have __dyld or __program_vars set up
766 this->setupLazyPointerHandler(context);
767
768 // tell kernel we are done with chunks of LINKEDIT
769 if ( !context.preFetchDisabled )
770 this->markFreeLINKEDIT(context);
771 }
772
773
774 void ImageLoaderMachOCompressed::doBindJustLazies(const LinkContext& context)
775 {
776 eachLazyBind(context, &ImageLoaderMachOCompressed::bindAt);
777 }
778
779 void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handler handler)
780 {
781 try {
782 uint8_t type = 0;
783 int segmentIndex = 0;
784 uintptr_t address = segActualLoadAddress(0);
785 uintptr_t segmentEndAddress = segActualEndAddress(0);
786 const char* symbolName = NULL;
787 uint8_t symboFlags = 0;
788 int libraryOrdinal = 0;
789 intptr_t addend = 0;
790 uint32_t count;
791 uint32_t skip;
792 LastLookup last = { 0, 0, NULL, 0, NULL };
793 const uint8_t* const start = fLinkEditBase + fDyldInfo->bind_off;
794 const uint8_t* const end = &start[fDyldInfo->bind_size];
795 const uint8_t* p = start;
796 bool done = false;
797 while ( !done && (p < end) ) {
798 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
799 uint8_t opcode = *p & BIND_OPCODE_MASK;
800 ++p;
801 switch (opcode) {
802 case BIND_OPCODE_DONE:
803 done = true;
804 break;
805 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
806 libraryOrdinal = immediate;
807 break;
808 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
809 libraryOrdinal = read_uleb128(p, end);
810 break;
811 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
812 // the special ordinals are negative numbers
813 if ( immediate == 0 )
814 libraryOrdinal = 0;
815 else {
816 int8_t signExtended = BIND_OPCODE_MASK | immediate;
817 libraryOrdinal = signExtended;
818 }
819 break;
820 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
821 symbolName = (char*)p;
822 symboFlags = immediate;
823 while (*p != '\0')
824 ++p;
825 ++p;
826 break;
827 case BIND_OPCODE_SET_TYPE_IMM:
828 type = immediate;
829 break;
830 case BIND_OPCODE_SET_ADDEND_SLEB:
831 addend = read_sleb128(p, end);
832 break;
833 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
834 segmentIndex = immediate;
835 if ( segmentIndex > fSegmentsCount )
836 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n",
837 segmentIndex, fSegmentsCount);
838 address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
839 segmentEndAddress = segActualEndAddress(segmentIndex);
840 break;
841 case BIND_OPCODE_ADD_ADDR_ULEB:
842 address += read_uleb128(p, end);
843 break;
844 case BIND_OPCODE_DO_BIND:
845 if ( address >= segmentEndAddress )
846 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
847 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
848 address += sizeof(intptr_t);
849 break;
850 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
851 if ( address >= segmentEndAddress )
852 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
853 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
854 address += read_uleb128(p, end) + sizeof(intptr_t);
855 break;
856 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
857 if ( address >= segmentEndAddress )
858 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
859 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
860 address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
861 break;
862 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
863 count = read_uleb128(p, end);
864 skip = read_uleb128(p, end);
865 for (uint32_t i=0; i < count; ++i) {
866 if ( address >= segmentEndAddress )
867 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
868 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
869 address += skip + sizeof(intptr_t);
870 }
871 break;
872 default:
873 dyld::throwf("bad bind opcode %d in bind info", *p);
874 }
875 }
876 }
877 catch (const char* msg) {
878 const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
879 free((void*)msg);
880 throw newMsg;
881 }
882 }
883
884 void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_handler handler)
885 {
886 try {
887 uint8_t type = BIND_TYPE_POINTER;
888 int segmentIndex = 0;
889 uintptr_t address = segActualLoadAddress(0);
890 uintptr_t segmentEndAddress = segActualEndAddress(0);
891 const char* symbolName = NULL;
892 uint8_t symboFlags = 0;
893 int libraryOrdinal = 0;
894 intptr_t addend = 0;
895 const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
896 const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
897 const uint8_t* p = start;
898 bool done = false;
899 while ( !done && (p < end) ) {
900 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
901 uint8_t opcode = *p & BIND_OPCODE_MASK;
902 ++p;
903 switch (opcode) {
904 case BIND_OPCODE_DONE:
905 // there is BIND_OPCODE_DONE at end of each lazy bind, don't stop until end of whole sequence
906 break;
907 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
908 libraryOrdinal = immediate;
909 break;
910 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
911 libraryOrdinal = read_uleb128(p, end);
912 break;
913 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
914 // the special ordinals are negative numbers
915 if ( immediate == 0 )
916 libraryOrdinal = 0;
917 else {
918 int8_t signExtended = BIND_OPCODE_MASK | immediate;
919 libraryOrdinal = signExtended;
920 }
921 break;
922 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
923 symbolName = (char*)p;
924 symboFlags = immediate;
925 while (*p != '\0')
926 ++p;
927 ++p;
928 break;
929 case BIND_OPCODE_SET_TYPE_IMM:
930 type = immediate;
931 break;
932 case BIND_OPCODE_SET_ADDEND_SLEB:
933 addend = read_sleb128(p, end);
934 break;
935 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
936 segmentIndex = immediate;
937 if ( segmentIndex > fSegmentsCount )
938 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n",
939 segmentIndex, fSegmentsCount);
940 address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
941 segmentEndAddress = segActualEndAddress(segmentIndex);
942 break;
943 case BIND_OPCODE_ADD_ADDR_ULEB:
944 address += read_uleb128(p, end);
945 break;
946 case BIND_OPCODE_DO_BIND:
947 if ( address >= segmentEndAddress )
948 throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
949 (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "lazy forced", NULL);
950 address += sizeof(intptr_t);
951 break;
952 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
953 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
954 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
955 default:
956 dyld::throwf("bad lazy bind opcode %d", *p);
957 }
958 }
959 }
960
961 catch (const char* msg) {
962 const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
963 free((void*)msg);
964 throw newMsg;
965 }
966 }
967
968 // A program built targeting 10.5 will have hybrid stubs. When used with weak symbols
969 // the classic lazy loader is used even when running on 10.6
970 uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
971 {
972 // only works with compressed LINKEDIT if classic symbol table is also present
973 const macho_nlist* symbolTable = NULL;
974 const char* symbolTableStrings = NULL;
975 const dysymtab_command* dynSymbolTable = NULL;
976 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
977 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
978 const struct load_command* cmd = cmds;
979 for (uint32_t i = 0; i < cmd_count; ++i) {
980 switch (cmd->cmd) {
981 case LC_SYMTAB:
982 {
983 const struct symtab_command* symtab = (struct symtab_command*)cmd;
984 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
985 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
986 }
987 break;
988 case LC_DYSYMTAB:
989 dynSymbolTable = (struct dysymtab_command*)cmd;
990 break;
991 }
992 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
993 }
994 // no symbol table => no lookup by address
995 if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
996 dyld::throwf("classic lazy binding used with compressed LINKEDIT at %p in image %s", lazyPointer, this->getPath());
997
998 // scan for all lazy-pointer sections
999 const bool twoLevel = this->usesTwoLevelNameSpace();
1000 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
1001 cmd = cmds;
1002 for (uint32_t i = 0; i < cmd_count; ++i) {
1003 switch (cmd->cmd) {
1004 case LC_SEGMENT_COMMAND:
1005 {
1006 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
1007 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
1008 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
1009 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
1010 const uint8_t type = sect->flags & SECTION_TYPE;
1011 uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
1012 if ( type == S_LAZY_SYMBOL_POINTERS ) {
1013 const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
1014 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
1015 if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
1016 const uint32_t indirectTableOffset = sect->reserved1;
1017 const uint32_t lazyIndex = lazyPointer - symbolPointers;
1018 symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
1019 }
1020 }
1021 if ( (symbolIndex != INDIRECT_SYMBOL_ABS) && (symbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
1022 const macho_nlist* symbol = &symbolTable[symbolIndex];
1023 const char* symbolName = &symbolTableStrings[symbol->n_un.n_strx];
1024 int libraryOrdinal = GET_LIBRARY_ORDINAL(symbol->n_desc);
1025 if ( !twoLevel || context.bindFlat )
1026 libraryOrdinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
1027 uintptr_t ptrToBind = (uintptr_t)lazyPointer;
1028 uintptr_t symbolAddr = bindAt(context, ptrToBind, BIND_TYPE_POINTER, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL);
1029 ++fgTotalLazyBindFixups;
1030 return symbolAddr;
1031 }
1032 }
1033 }
1034 break;
1035 }
1036 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1037 }
1038 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
1039 }
1040
1041
1042 uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context)
1043 {
1044 const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
1045 const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
1046 if ( lazyBindingInfoOffset > fDyldInfo->lazy_bind_size )
1047 throw "fast lazy bind offset out of range";
1048
1049 uint8_t type = BIND_TYPE_POINTER;
1050 uintptr_t address = 0;
1051 const char* symbolName = NULL;
1052 uint8_t symboFlags = 0;
1053 int libraryOrdinal = 0;
1054 bool done = false;
1055 uintptr_t result = 0;
1056 const uint8_t* p = &start[lazyBindingInfoOffset];
1057 while ( !done && (p < end) ) {
1058 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1059 uint8_t opcode = *p & BIND_OPCODE_MASK;
1060 ++p;
1061 switch (opcode) {
1062 case BIND_OPCODE_DONE:
1063 done = true;
1064 break;
1065 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
1066 libraryOrdinal = immediate;
1067 break;
1068 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
1069 libraryOrdinal = read_uleb128(p, end);
1070 break;
1071 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
1072 // the special ordinals are negative numbers
1073 if ( immediate == 0 )
1074 libraryOrdinal = 0;
1075 else {
1076 int8_t signExtended = BIND_OPCODE_MASK | immediate;
1077 libraryOrdinal = signExtended;
1078 }
1079 break;
1080 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1081 symbolName = (char*)p;
1082 symboFlags = immediate;
1083 while (*p != '\0')
1084 ++p;
1085 ++p;
1086 break;
1087 case BIND_OPCODE_SET_TYPE_IMM:
1088 type = immediate;
1089 break;
1090 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1091 if ( immediate > fSegmentsCount )
1092 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n",
1093 immediate, fSegmentsCount);
1094 address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1095 break;
1096 case BIND_OPCODE_DO_BIND:
1097 result = this->bindAt(context, address, type, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL);
1098 break;
1099 case BIND_OPCODE_SET_ADDEND_SLEB:
1100 case BIND_OPCODE_ADD_ADDR_ULEB:
1101 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1102 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1103 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1104 default:
1105 dyld::throwf("bad lazy bind opcode %d", *p);
1106 }
1107 }
1108 return result;
1109 }
1110
1111 void ImageLoaderMachOCompressed::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder)
1112 {
1113 it.image = this;
1114 it.symbolName = " ";
1115 it.loadOrder = loadOrder;
1116 it.weakSymbol = false;
1117 it.symbolMatches = false;
1118 it.done = false;
1119 it.curIndex = 0;
1120 it.endIndex = this->fDyldInfo->weak_bind_size;
1121 it.address = 0;
1122 it.type = 0;
1123 it.addend = 0;
1124 }
1125
1126
1127 bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
1128 {
1129 if ( it.done )
1130 return false;
1131
1132 if ( this->fDyldInfo->weak_bind_size == 0 ) {
1133 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
1134 it.done = true;
1135 it.symbolName = "~~~";
1136 return true;
1137 }
1138 const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
1139 const uint8_t* p = start + it.curIndex;
1140 const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
1141 uint32_t count;
1142 uint32_t skip;
1143 while ( p < end ) {
1144 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1145 uint8_t opcode = *p & BIND_OPCODE_MASK;
1146 ++p;
1147 switch (opcode) {
1148 case BIND_OPCODE_DONE:
1149 it.done = true;
1150 it.curIndex = p - start;
1151 it.symbolName = "~~~"; // sorts to end
1152 return true;
1153 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1154 it.symbolName = (char*)p;
1155 it.weakSymbol = ((immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) == 0);
1156 it.symbolMatches = false;
1157 while (*p != '\0')
1158 ++p;
1159 ++p;
1160 it.curIndex = p - start;
1161 return false;
1162 case BIND_OPCODE_SET_TYPE_IMM:
1163 it.type = immediate;
1164 break;
1165 case BIND_OPCODE_SET_ADDEND_SLEB:
1166 it.addend = read_sleb128(p, end);
1167 break;
1168 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1169 if ( immediate > fSegmentsCount )
1170 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n",
1171 immediate, fSegmentsCount);
1172 it.address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1173 break;
1174 case BIND_OPCODE_ADD_ADDR_ULEB:
1175 it.address += read_uleb128(p, end);
1176 break;
1177 case BIND_OPCODE_DO_BIND:
1178 it.address += sizeof(intptr_t);
1179 break;
1180 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1181 it.address += read_uleb128(p, end) + sizeof(intptr_t);
1182 break;
1183 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1184 it.address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1185 break;
1186 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1187 count = read_uleb128(p, end);
1188 skip = read_uleb128(p, end);
1189 for (uint32_t i=0; i < count; ++i) {
1190 it.address += skip + sizeof(intptr_t);
1191 }
1192 break;
1193 default:
1194 dyld::throwf("bad weak bind opcode %d", *p);
1195 }
1196 }
1197 /// hmmm, BIND_OPCODE_DONE is missing...
1198 it.done = true;
1199 it.symbolName = "~~~";
1200 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
1201 return true;
1202 }
1203
1204 uintptr_t ImageLoaderMachOCompressed::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
1205 {
1206 //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
1207 const ImageLoader* foundIn = NULL;
1208 const ImageLoader::Symbol* sym = this->findExportedSymbol(it.symbolName, &foundIn);
1209 if ( sym != NULL ) {
1210 //dyld::log("sym=%p, foundIn=%p\n", sym, foundIn);
1211 return foundIn->getExportedSymbolAddress(sym, context, this);
1212 }
1213 return 0;
1214 }
1215
1216
1217 void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context)
1218 {
1219 // <rdar://problem/6570879> weak binding done too early with inserted libraries
1220 if ( this->getState() < dyld_image_state_bound )
1221 return;
1222
1223 const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
1224 const uint8_t* p = start + it.curIndex;
1225 const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
1226
1227 uint8_t type = it.type;
1228 uintptr_t address = it.address;
1229 const char* symbolName = it.symbolName;
1230 intptr_t addend = it.addend;
1231 uint32_t count;
1232 uint32_t skip;
1233 bool done = false;
1234 bool boundSomething = false;
1235 while ( !done && (p < end) ) {
1236 uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
1237 uint8_t opcode = *p & BIND_OPCODE_MASK;
1238 ++p;
1239 switch (opcode) {
1240 case BIND_OPCODE_DONE:
1241 done = true;
1242 break;
1243 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
1244 done = true;
1245 break;
1246 case BIND_OPCODE_SET_TYPE_IMM:
1247 type = immediate;
1248 break;
1249 case BIND_OPCODE_SET_ADDEND_SLEB:
1250 addend = read_sleb128(p, end);
1251 break;
1252 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
1253 if ( immediate > fSegmentsCount )
1254 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n",
1255 immediate, fSegmentsCount);
1256 address = segActualLoadAddress(immediate) + read_uleb128(p, end);
1257 break;
1258 case BIND_OPCODE_ADD_ADDR_ULEB:
1259 address += read_uleb128(p, end);
1260 break;
1261 case BIND_OPCODE_DO_BIND:
1262 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1263 boundSomething = true;
1264 address += sizeof(intptr_t);
1265 break;
1266 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
1267 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1268 boundSomething = true;
1269 address += read_uleb128(p, end) + sizeof(intptr_t);
1270 break;
1271 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
1272 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1273 boundSomething = true;
1274 address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
1275 break;
1276 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
1277 count = read_uleb128(p, end);
1278 skip = read_uleb128(p, end);
1279 for (uint32_t i=0; i < count; ++i) {
1280 bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
1281 boundSomething = true;
1282 address += skip + sizeof(intptr_t);
1283 }
1284 break;
1285 default:
1286 dyld::throwf("bad bind opcode %d in weak binding info", *p);
1287 }
1288 }
1289 if ( boundSomething && (targetImage != this) && !targetImage->neverUnload() )
1290 this->addDynamicReference(targetImage);
1291 }
1292
1293
1294
1295
1296
1297 const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr, const void** closestAddr) const
1298 {
1299 // called by dladdr()
1300 // only works with compressed LINKEDIT if classic symbol table is also present
1301 const macho_nlist* symbolTable = NULL;
1302 const char* symbolTableStrings = NULL;
1303 const dysymtab_command* dynSymbolTable = NULL;
1304 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
1305 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
1306 const struct load_command* cmd = cmds;
1307 for (uint32_t i = 0; i < cmd_count; ++i) {
1308 switch (cmd->cmd) {
1309 case LC_SYMTAB:
1310 {
1311 const struct symtab_command* symtab = (struct symtab_command*)cmd;
1312 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
1313 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
1314 }
1315 break;
1316 case LC_DYSYMTAB:
1317 dynSymbolTable = (struct dysymtab_command*)cmd;
1318 break;
1319 }
1320 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1321 }
1322 // no symbol table => no lookup by address
1323 if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
1324 return NULL;
1325
1326 uintptr_t targetAddress = (uintptr_t)addr - fSlide;
1327 const struct macho_nlist* bestSymbol = NULL;
1328 // first walk all global symbols
1329 const struct macho_nlist* const globalsStart = &symbolTable[dynSymbolTable->iextdefsym];
1330 const struct macho_nlist* const globalsEnd= &globalsStart[dynSymbolTable->nextdefsym];
1331 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
1332 if ( (s->n_type & N_TYPE) == N_SECT ) {
1333 if ( bestSymbol == NULL ) {
1334 if ( s->n_value <= targetAddress )
1335 bestSymbol = s;
1336 }
1337 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
1338 bestSymbol = s;
1339 }
1340 }
1341 }
1342 // next walk all local symbols
1343 const struct macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
1344 const struct macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
1345 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
1346 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
1347 if ( bestSymbol == NULL ) {
1348 if ( s->n_value <= targetAddress )
1349 bestSymbol = s;
1350 }
1351 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
1352 bestSymbol = s;
1353 }
1354 }
1355 }
1356 if ( bestSymbol != NULL ) {
1357 *closestAddr = (void*)(bestSymbol->n_value + fSlide);
1358 return &symbolTableStrings[bestSymbol->n_un.n_strx];
1359 }
1360 return NULL;
1361 }
1362
1363
1364 #if PREBOUND_IMAGE_SUPPORT
1365 void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& context)
1366 {
1367 // no way to back off a prebound compress image
1368 }
1369 #endif
1370