1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
29 #include <sys/types.h>
30 #include <sys/fcntl.h>
33 #include <sys/param.h>
34 #include <mach/mach.h>
35 #include <mach/thread_status.h>
36 #include <mach-o/loader.h>
38 #include "ImageLoaderMachOCompressed.h"
39 #include "mach-o/dyld_images.h"
42 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
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
{};
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
{};
60 static uintptr_t read_uleb128(const uint8_t*& p
, const uint8_t* end
)
66 dyld::throwf("malformed uleb128");
68 uint64_t slice
= *p
& 0x7f;
70 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
71 dyld::throwf("uleb128 too big");
73 result
|= (slice
<< bit
);
82 static intptr_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
89 throw "malformed sleb128";
91 result
|= ((byte
& 0x7f) << bit
);
93 } while (byte
& 0x80);
94 // sign extend negative numbers
95 if ( (byte
& 0x40) != 0 )
96 result
|= (-1LL) << bit
;
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
)
105 ImageLoaderMachOCompressed
* image
= ImageLoaderMachOCompressed::instantiateStart(mh
, path
, segCount
, libCount
);
107 // set slide for PIE programs
108 image
->setSlide(slide
);
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();
114 image
->setNeverUnload();
115 image
->instantiateFinish(context
);
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
));
124 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
));
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
)
136 ImageLoaderMachOCompressed
* image
= ImageLoaderMachOCompressed::instantiateStart((macho_header
*)fileData
, path
, segCount
, libCount
);
139 // record info about file
140 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
);
143 image
->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
);
145 // finish construction
146 image
->instantiateFinish(context
);
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");
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
);
163 image
->setPath(path
);
166 image
->setPath(path
);
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
);
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
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
)
189 ImageLoaderMachOCompressed
* image
= ImageLoaderMachOCompressed::instantiateStart(mh
, path
, segCount
, libCount
);
191 // record info about file
192 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
);
194 // remember this is from shared cache and cannot be unloaded
195 image
->fInSharedCache
= true;
196 image
->setNeverUnload();
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
));
206 image
->instantiateFinish(context
);
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
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
)
222 ImageLoaderMachOCompressed
* image
= ImageLoaderMachOCompressed::instantiateStart(mh
, moduleName
, segCount
, libCount
);
225 if ( mh
->filetype
== MH_EXECUTE
)
226 throw "can't load another MH_EXECUTE";
229 image
->mapSegments((const void*)mh
, len
, context
);
231 // for compatibility, never unload dylibs loaded from memory
232 image
->setNeverUnload();
234 // bundle loads need path copied
235 if ( moduleName
!= NULL
)
236 image
->setPath(moduleName
);
238 image
->instantiateFinish(context
);
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
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
)
257 ImageLoaderMachOCompressed::~ImageLoaderMachOCompressed()
259 // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
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
)
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
);
279 // common code to finish initializing object
280 void ImageLoaderMachOCompressed::instantiateFinish(const LinkContext
& context
)
282 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
283 this->parseLoadCmds();
285 // notify state change
286 this->setMapped(context
);
289 uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
291 return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
)));
295 ImageLoader
* ImageLoaderMachOCompressed::libImage(unsigned int libIndex
) const
297 const uintptr_t* images
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
) + fSegmentsCount
*sizeof(uint32_t)));
299 return (ImageLoader
*)(images
[libIndex
] & (-2));
302 bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex
) const
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);
310 void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex
, ImageLoader
* image
, bool reExported
)
312 uintptr_t* images
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
) + fSegmentsCount
*sizeof(uint32_t)));
313 uintptr_t value
= (uintptr_t)image
;
316 images
[libIndex
] = value
;
320 void ImageLoaderMachOCompressed::markFreeLINKEDIT(const LinkContext
& context
)
322 // mark that we are done with rebase and bind info
323 markLINKEDIT(context
, MADV_FREE
);
326 void ImageLoaderMachOCompressed::markSequentialLINKEDIT(const LinkContext
& context
)
328 // mark the rebase and bind info and using sequential access
329 markLINKEDIT(context
, MADV_SEQUENTIAL
);
332 void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext
& context
, int advise
)
334 // if not loaded at preferred address, mark rebase info
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
;
341 return; // no binding info to prefetch
343 // end is at end of bind info
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
;
353 // round to whole pages
354 start
= start
& (-4096);
355 end
= (end
+ 4095) & (-4096);
357 // do nothing if only one page of rebase/bind info
358 if ( (end
-start
) <= 4096 )
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
)
367 dyld::log("%18s %s 0x%0lX -> 0x%0lX\n", "__LINKEDIT", adstr
, start
, end
-1);
373 void ImageLoaderMachOCompressed::rebaseAt(const LinkContext
& context
, uintptr_t addr
, uintptr_t slide
, uint8_t type
)
375 //dyld::log("0x%08lX type=%d\n", addr, type);
376 uintptr_t* locationToFix
= (uintptr_t*)addr
;
378 case REBASE_TYPE_POINTER
:
379 *locationToFix
+= slide
;
381 case REBASE_TYPE_TEXT_ABSOLUTE32
:
382 *locationToFix
+= slide
;
385 dyld::throwf("bad rebase type %d", type
);
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
)
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
);
397 void ImageLoaderMachOCompressed::rebase(const LinkContext
& context
)
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
;
406 int segmentIndex
= 0;
407 uintptr_t address
= segActualLoadAddress(0);
408 uintptr_t segmentEndAddress
= segActualEndAddress(0);
412 while ( !done
&& (p
< end
) ) {
413 uint8_t immediate
= *p
& REBASE_IMMEDIATE_MASK
;
414 uint8_t opcode
= *p
& REBASE_OPCODE_MASK
;
417 case REBASE_OPCODE_DONE
:
420 case REBASE_OPCODE_SET_TYPE_IMM
:
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
);
431 case REBASE_OPCODE_ADD_ADDR_ULEB
:
432 address
+= read_uleb128(p
, end
);
434 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
:
435 address
+= immediate
*sizeof(uintptr_t);
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);
444 fgTotalRebaseFixups
+= immediate
;
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);
454 fgTotalRebaseFixups
+= count
;
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
;
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);
472 fgTotalRebaseFixups
+= count
;
475 dyld::throwf("bad rebase opcode %d", *p
);
479 catch (const char* msg
) {
480 const char* newMsg
= dyld::mkstringf("%s in %s", msg
, this->getPath());
489 const ImageLoader::Symbol
* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol
, const ImageLoader
** foundIn
) const
491 //dyld::log("findExportedSymbolCompressed(%s) in %s\n", symbol, this->getShortName());
492 if ( fDyldInfo
->export_size
== 0 )
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
;
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;
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
) {
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' ) {
526 // advance to next child
528 read_uleb128(e
, end
);
531 // the symbol so far matches this edge (child)
532 // so advance to the child's node
534 uint32_t nodeOffset
= read_uleb128(e
, end
);
535 newNode
= &start
[nodeOffset
];
537 //dyld::log("findExportedSymbol() found matching edge advancing to node 0x%x\n", nodeOffset);
541 if ( newNode
!= NULL
)
544 //dyld::log("findExportedSymbol(%s) in %s failed\n", symbol, this->getShortName());
551 bool ImageLoaderMachOCompressed::containsSymbol(const void* addr
) const
553 const uint8_t* start
= &fLinkEditBase
[fDyldInfo
->export_off
];
554 const uint8_t* end
= &start
[fDyldInfo
->export_size
];
555 return ( (start
<= addr
) && (addr
< end
) );
559 uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const Symbol
* symbol
) const
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
;
570 throw "unsupported exported symbol kind";
573 bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol
* symbol
) const
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
);
585 const char* ImageLoaderMachOCompressed::exportedSymbolName(const Symbol
* symbol
) const
587 throw "NSNameOfSymbol() not supported with compressed LINKEDIT";
590 unsigned int ImageLoaderMachOCompressed::exportedSymbolCount() const
592 throw "NSSymbolDefinitionCountInObjectFileImage() not supported with compressed LINKEDIT";
595 const ImageLoader::Symbol
* ImageLoaderMachOCompressed::exportedSymbolIndexed(unsigned int index
) const
597 throw "NSSymbolDefinitionNameInObjectFileImage() not supported with compressed LINKEDIT";
600 unsigned int ImageLoaderMachOCompressed::importedSymbolCount() const
602 throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
605 const ImageLoader::Symbol
* ImageLoaderMachOCompressed::importedSymbolIndexed(unsigned int index
) const
607 throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
610 const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol
* symbol
) const
612 throw "NSSymbolReferenceNameInObjectFileImage() not supported with compressed LINKEDIT";
617 uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext
& context
, const char* symbolName
, bool weak_import
, const ImageLoader
** foundIn
)
620 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) {
621 if ( (*foundIn
!= this) && !(*foundIn
)->neverUnload() )
622 this->addDynamicReference(*foundIn
);
623 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
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
);
630 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
633 // definition can't be found anywhere, ok because it is weak, just return 0
636 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace");
640 uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext
& context
, const ImageLoader
* targetImage
, bool weak_import
,
641 const char* symbolName
, const ImageLoader
** foundIn
)
644 const Symbol
* sym
= targetImage
->findExportedSymbol(symbolName
, true, foundIn
);
646 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
650 // definition can't be found anywhere, ok because it is weak, just return 0
654 // nowhere to be found
655 throwSymbolNotFound(symbolName
, this->getPath(), targetImage
->getPath());
659 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext
& context
, const char* symbolName
,
660 uint8_t symboFlags
, int libraryOrdinal
, const ImageLoader
** targetImage
,
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
;
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
);
681 if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
) {
682 *targetImage
= context
.mainExecutable
;
684 else if ( libraryOrdinal
== BIND_SPECIAL_DYLIB_SELF
) {
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());
691 else if ( (unsigned)libraryOrdinal
<= libraryCount() ) {
692 *targetImage
= libImage(libraryOrdinal
-1);
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());
698 if ( *targetImage
== NULL
) {
700 // if target library not loaded and reference is weak or library is weak return 0
704 dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%d could not be loaded",
705 symbolName
, this->getPath(), libraryOrdinal
);
709 symbolAddress
= resolveTwolevel(context
, *targetImage
, weak_import
, symbolName
, targetImage
);
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
;
722 return symbolAddress
;
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
)
728 const ImageLoader
* targetImage
;
729 uintptr_t symbolAddress
;
732 symbolAddress
= this->resolve(context
, symbolName
, symboFlags
, libraryOrdinal
, &targetImage
, last
);
735 return this->bindLocation(context
, addr
, symbolAddress
, targetImage
, type
, symbolName
, addend
, msg
);
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
)
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
);
747 void ImageLoaderMachOCompressed::doBind(const LinkContext
& context
, bool forceLazysBound
)
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
755 // run through all binding opcodes
756 eachBind(context
, &ImageLoaderMachOCompressed::bindAt
);
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
);
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
);
768 // tell kernel we are done with chunks of LINKEDIT
769 if ( !context
.preFetchDisabled
)
770 this->markFreeLINKEDIT(context
);
774 void ImageLoaderMachOCompressed::doBindJustLazies(const LinkContext
& context
)
776 eachLazyBind(context
, &ImageLoaderMachOCompressed::bindAt
);
779 void ImageLoaderMachOCompressed::eachBind(const LinkContext
& context
, bind_handler handler
)
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;
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
;
797 while ( !done
&& (p
< end
) ) {
798 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
799 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
802 case BIND_OPCODE_DONE
:
805 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
806 libraryOrdinal
= immediate
;
808 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
809 libraryOrdinal
= read_uleb128(p
, end
);
811 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
812 // the special ordinals are negative numbers
813 if ( immediate
== 0 )
816 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
817 libraryOrdinal
= signExtended
;
820 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
821 symbolName
= (char*)p
;
822 symboFlags
= immediate
;
827 case BIND_OPCODE_SET_TYPE_IMM
:
830 case BIND_OPCODE_SET_ADDEND_SLEB
:
831 addend
= read_sleb128(p
, end
);
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
);
841 case BIND_OPCODE_ADD_ADDR_ULEB
:
842 address
+= read_uleb128(p
, end
);
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);
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);
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);
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);
873 dyld::throwf("bad bind opcode %d in bind info", *p
);
877 catch (const char* msg
) {
878 const char* newMsg
= dyld::mkstringf("%s in %s", msg
, this->getPath());
884 void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext
& context
, bind_handler handler
)
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;
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
;
899 while ( !done
&& (p
< end
) ) {
900 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
901 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
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
907 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
908 libraryOrdinal
= immediate
;
910 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
911 libraryOrdinal
= read_uleb128(p
, end
);
913 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
914 // the special ordinals are negative numbers
915 if ( immediate
== 0 )
918 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
919 libraryOrdinal
= signExtended
;
922 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
923 symbolName
= (char*)p
;
924 symboFlags
= immediate
;
929 case BIND_OPCODE_SET_TYPE_IMM
:
932 case BIND_OPCODE_SET_ADDEND_SLEB
:
933 addend
= read_sleb128(p
, end
);
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
);
943 case BIND_OPCODE_ADD_ADDR_ULEB
:
944 address
+= read_uleb128(p
, end
);
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);
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
:
956 dyld::throwf("bad lazy bind opcode %d", *p
);
961 catch (const char* msg
) {
962 const char* newMsg
= dyld::mkstringf("%s in %s", msg
, this->getPath());
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
)
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
) {
983 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
984 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
985 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
989 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
992 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
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());
998 // scan for all lazy-pointer sections
999 const bool twoLevel
= this->usesTwoLevelNameSpace();
1000 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[dynSymbolTable
->indirectsymoff
];
1002 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1004 case LC_SEGMENT_COMMAND
:
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
= §ionsStart
[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
];
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
;
1036 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1038 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer
, this->getPath());
1042 uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset
, const LinkContext
& context
)
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";
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;
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
;
1062 case BIND_OPCODE_DONE
:
1065 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
1066 libraryOrdinal
= immediate
;
1068 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
1069 libraryOrdinal
= read_uleb128(p
, end
);
1071 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
1072 // the special ordinals are negative numbers
1073 if ( immediate
== 0 )
1076 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
1077 libraryOrdinal
= signExtended
;
1080 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1081 symbolName
= (char*)p
;
1082 symboFlags
= immediate
;
1087 case BIND_OPCODE_SET_TYPE_IMM
:
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
);
1096 case BIND_OPCODE_DO_BIND
:
1097 result
= this->bindAt(context
, address
, type
, symbolName
, 0, 0, libraryOrdinal
, "lazy ", NULL
);
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
:
1105 dyld::throwf("bad lazy bind opcode %d", *p
);
1111 void ImageLoaderMachOCompressed::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
)
1114 it
.symbolName
= " ";
1115 it
.loadOrder
= loadOrder
;
1116 it
.weakSymbol
= false;
1117 it
.symbolMatches
= false;
1120 it
.endIndex
= this->fDyldInfo
->weak_bind_size
;
1127 bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator
& it
)
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
1135 it
.symbolName
= "~~~";
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
;
1144 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
1145 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
1148 case BIND_OPCODE_DONE
:
1150 it
.curIndex
= p
- start
;
1151 it
.symbolName
= "~~~"; // sorts to end
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;
1160 it
.curIndex
= p
- start
;
1162 case BIND_OPCODE_SET_TYPE_IMM
:
1163 it
.type
= immediate
;
1165 case BIND_OPCODE_SET_ADDEND_SLEB
:
1166 it
.addend
= read_sleb128(p
, end
);
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
);
1174 case BIND_OPCODE_ADD_ADDR_ULEB
:
1175 it
.address
+= read_uleb128(p
, end
);
1177 case BIND_OPCODE_DO_BIND
:
1178 it
.address
+= sizeof(intptr_t);
1180 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
1181 it
.address
+= read_uleb128(p
, end
) + sizeof(intptr_t);
1183 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
1184 it
.address
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t);
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);
1194 dyld::throwf("bad weak bind opcode %d", *p
);
1197 /// hmmm, BIND_OPCODE_DONE is missing...
1199 it
.symbolName
= "~~~";
1200 //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
1204 uintptr_t ImageLoaderMachOCompressed::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
)
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);
1217 void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, const LinkContext
& context
)
1219 // <rdar://problem/6570879> weak binding done too early with inserted libraries
1220 if ( this->getState() < dyld_image_state_bound
)
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
;
1227 uint8_t type
= it
.type
;
1228 uintptr_t address
= it
.address
;
1229 const char* symbolName
= it
.symbolName
;
1230 intptr_t addend
= it
.addend
;
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
;
1240 case BIND_OPCODE_DONE
:
1243 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
1246 case BIND_OPCODE_SET_TYPE_IMM
:
1249 case BIND_OPCODE_SET_ADDEND_SLEB
:
1250 addend
= read_sleb128(p
, end
);
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
);
1258 case BIND_OPCODE_ADD_ADDR_ULEB
:
1259 address
+= read_uleb128(p
, end
);
1261 case BIND_OPCODE_DO_BIND
:
1262 bindLocation(context
, address
, value
, targetImage
, type
, symbolName
, addend
, "weak ");
1263 boundSomething
= true;
1264 address
+= sizeof(intptr_t);
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);
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);
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);
1286 dyld::throwf("bad bind opcode %d in weak binding info", *p
);
1289 if ( boundSomething
&& (targetImage
!= this) && !targetImage
->neverUnload() )
1290 this->addDynamicReference(targetImage
);
1297 const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr
, const void** closestAddr
) const
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
) {
1311 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
1312 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
1313 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
1317 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
1320 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1322 // no symbol table => no lookup by address
1323 if ( (symbolTable
== NULL
) || (dynSymbolTable
== NULL
) )
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
)
1337 else if ( (s
->n_value
<= targetAddress
) && (bestSymbol
->n_value
< s
->n_value
) ) {
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
)
1351 else if ( (s
->n_value
<= targetAddress
) && (bestSymbol
->n_value
< s
->n_value
) ) {
1356 if ( bestSymbol
!= NULL
) {
1357 *closestAddr
= (void*)(bestSymbol
->n_value
+ fSlide
);
1358 return &symbolTableStrings
[bestSymbol
->n_un
.n_strx
];
1364 #if PREBOUND_IMAGE_SUPPORT
1365 void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext
& context
)
1367 // no way to back off a prebound compress image