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@ 
  26 #if __arm__ || __arm64__ 
  27   #include <System/sys/mman.h> 
  34 #include <sys/types.h> 
  35 #include <sys/fcntl.h> 
  37 #include <sys/param.h> 
  38 #include <mach/mach.h> 
  39 #include <mach/thread_status.h> 
  40 #include <mach-o/loader.h>  
  41 #include <mach-o/dyld_images.h> 
  44 #include "ImageLoaderMachOCompressed.h" 
  48 #ifndef BIND_SUBOPCODE_THREADED_SET_JOP 
  49    #define BIND_SUBOPCODE_THREADED_SET_JOP                                                              0x0F 
  52 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables 
  55         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
  56         #define LC_ROUTINES_COMMAND             LC_ROUTINES_64 
  57         struct macho_segment_command    
: public segment_command_64  
{}; 
  58         struct macho_section                    
: public section_64  
{};         
  59         struct macho_routines_command   
: public routines_command_64  
{};        
  62         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
  63         #define LC_ROUTINES_COMMAND             LC_ROUTINES 
  64         struct macho_segment_command    
: public segment_command 
{}; 
  65         struct macho_section                    
: public section  
{};    
  66         struct macho_routines_command   
: public routines_command  
{};   
  71 // create image for main executable 
  72 ImageLoaderMachOCompressed
* ImageLoaderMachOCompressed::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
,  
  73                                                                                                                                                 unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
  75         ImageLoaderMachOCompressed
* image 
= ImageLoaderMachOCompressed::instantiateStart(mh
, path
, segCount
, libCount
); 
  77         // set slide for PIE programs 
  78         image
->setSlide(slide
); 
  80         // for PIE record end of program, to know where to start loading dylibs 
  82                 fgNextPIEDylibAddress 
= (uintptr_t)image
->getEnd(); 
  84         image
->disableCoverageCheck(); 
  85         image
->instantiateFinish(context
); 
  86         image
->setMapped(context
); 
  88         if ( context
.verboseMapping 
) { 
  89                 dyld::log("dyld: Main executable mapped %s\n", path
); 
  90                 for(unsigned int i
=0, e
=image
->segmentCount(); i 
< e
; ++i
) { 
  91                         const char* name 
= image
->segName(i
); 
  92                         if ( (strcmp(name
, "__PAGEZERO") == 0) || (strcmp(name
, "__UNIXSTACK") == 0)  ) 
  93                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segPreferredLoadAddress(i
), image
->segPreferredLoadAddress(i
)+image
->segSize(i
)); 
  95                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
)); 
 102 // create image by mapping in a mach-o file 
 103 ImageLoaderMachOCompressed
* ImageLoaderMachOCompressed::instantiateFromFile(const char* path
, int fd
, const uint8_t* fileData
, size_t lenFileData
, 
 104                                                                                                                         uint64_t offsetInFat
, uint64_t lenInFat
, const struct stat
& info
,  
 105                                                                                                                         unsigned int segCount
, unsigned int libCount
,  
 106                                                                                                                         const struct linkedit_data_command
* codeSigCmd
,  
 107                                                                                                                         const struct encryption_info_command
* encryptCmd
,  
 108                                                                                                                         const LinkContext
& context
) 
 110         ImageLoaderMachOCompressed
* image 
= ImageLoaderMachOCompressed::instantiateStart((macho_header
*)fileData
, path
, segCount
, libCount
); 
 113                 // record info about file   
 114                 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
); 
 116                 // if this image is code signed, let kernel validate signature before mapping any pages from image 
 117                 image
->loadCodeSignature(codeSigCmd
, fd
, offsetInFat
, context
); 
 119                 // Validate that first data we read with pread actually matches with code signature 
 120                 image
->validateFirstPages(codeSigCmd
, fd
, fileData
, lenFileData
, offsetInFat
, context
); 
 123                 image
->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
); 
 125                 // if framework is FairPlay encrypted, register with kernel 
 126                 image
->registerEncryption(encryptCmd
, context
); 
 128                 // probe to see if code signed correctly 
 129                 image
->crashIfInvalidCodeSignature(); 
 131                 // finish construction 
 132                 image
->instantiateFinish(context
); 
 134                 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path 
 135                 const char* installName 
= image
->getInstallPath(); 
 136                 if ( (installName 
!= NULL
) && (strcmp(installName
, path
) == 0) && (path
[0] == '/') ) 
 137                         image
->setPathUnowned(installName
); 
 139                 // <rdar://problem/6563887> app crashes when libSystem cannot be found 
 140                 else if ( (installName 
!= NULL
) && (strcmp(path
, "/usr/lib/libgcc_s.1.dylib") == 0) && (strcmp(installName
, "/usr/lib/libSystem.B.dylib") == 0) ) 
 141                         image
->setPathUnowned("/usr/lib/libSystem.B.dylib"); 
 143                 else if ( (path
[0] != '/') || (strstr(path
, "../") != NULL
) ) { 
 144                         // rdar://problem/10733082 Fix up @rpath based paths during introspection 
 145                         // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them 
 146                         char realPath
[MAXPATHLEN
]; 
 147                         if ( fcntl(fd
, F_GETPATH
, realPath
) == 0 )  
 148                                 image
->setPaths(path
, realPath
); 
 150                                 image
->setPath(path
); 
 153                         // <rdar://problem/46682306> always try to realpath dylibs since they may have been dlopen()ed using a symlink path 
 154                         if ( installName 
!= NULL 
) { 
 155                                 char realPath
[MAXPATHLEN
]; 
 156                                 if ( (fcntl(fd
, F_GETPATH
, realPath
) == 0) && (strcmp(path
, realPath
) != 0) ) 
 157                                         image
->setPaths(path
, realPath
); 
 159                                         image
->setPath(path
); 
 162                                 image
->setPath(path
); 
 166                 // make sure path is stable before recording in dyld_all_image_infos 
 167                 image
->setMapped(context
); 
 171                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 172                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 180 // create image by using cached mach-o file 
 181 ImageLoaderMachOCompressed
* ImageLoaderMachOCompressed::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, 
 182                                                                                                                                                 const struct stat
& info
, unsigned int segCount
, 
 183                                                                                                                                                 unsigned int libCount
, const LinkContext
& context
) 
 185         ImageLoaderMachOCompressed
* image 
= ImageLoaderMachOCompressed::instantiateStart(mh
, path
, segCount
, libCount
); 
 187                 // record info about file   
 188                 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
); 
 190                 // remember this is from shared cache and cannot be unloaded 
 191                 image
->fInSharedCache 
= true; 
 192                 image
->setNeverUnload(); 
 193                 image
->setSlide(slide
); 
 194                 image
->disableCoverageCheck(); 
 196                 // segments already mapped in cache 
 197                 if ( context
.verboseMapping 
) { 
 198                         dyld::log("dyld: Using shared cached for %s\n", path
); 
 199                         for(unsigned int i
=0; i 
< image
->fSegmentsCount
; ++i
) { 
 200                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", image
->segName(i
), image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
)); 
 204                 image
->instantiateFinish(context
); 
 206 #if TARGET_OS_SIMULATOR 
 207                 char realPath
[MAXPATHLEN
] = { 0 }; 
 208                 if ( dyld::gLinkContext
.rootPaths 
== NULL 
) 
 209                         throw "root path is not set"; 
 210                 strlcpy(realPath
, dyld::gLinkContext
.rootPaths
[0], MAXPATHLEN
); 
 211                 strlcat(realPath
, path
, MAXPATHLEN
); 
 212                 image
->setPaths(path
, realPath
); 
 214                 image
->setMapped(context
); 
 217                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 218                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 226 // create image by copying an in-memory mach-o file 
 227 ImageLoaderMachOCompressed
* ImageLoaderMachOCompressed::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
,  
 228                                                                                                                         unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
 230         ImageLoaderMachOCompressed
* image 
= ImageLoaderMachOCompressed::instantiateStart(mh
, moduleName
, segCount
, libCount
); 
 233                 if ( mh
->filetype 
== MH_EXECUTE 
)  
 234                         throw "can't load another MH_EXECUTE"; 
 237                 image
->mapSegments((const void*)mh
, len
, context
); 
 239                 // for compatibility, never unload dylibs loaded from memory 
 240                 image
->setNeverUnload(); 
 242                 image
->disableCoverageCheck(); 
 244                 // bundle loads need path copied 
 245                 if ( moduleName 
!= NULL 
)  
 246                         image
->setPath(moduleName
); 
 248                 image
->instantiateFinish(context
); 
 249                 image
->setMapped(context
); 
 252                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 253                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 262 ImageLoaderMachOCompressed::ImageLoaderMachOCompressed(const macho_header
* mh
, const char* path
, unsigned int segCount
,  
 263                                                                                                                                                 uint32_t segOffsets
[], unsigned int libCount
) 
 264  : ImageLoaderMachO(mh
, path
, segCount
, segOffsets
, libCount
), fDyldInfo(NULL
), fChainedFixups(NULL
), fExportsTrie(NULL
) 
 268 ImageLoaderMachOCompressed::~ImageLoaderMachOCompressed() 
 270         // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work 
 276 // construct ImageLoaderMachOCompressed using "placement new" with SegmentMachO objects array at end 
 277 ImageLoaderMachOCompressed
* ImageLoaderMachOCompressed::instantiateStart(const macho_header
* mh
, const char* path
,  
 278                                                                                                                                                         unsigned int segCount
, unsigned int libCount
) 
 280         size_t size 
= sizeof(ImageLoaderMachOCompressed
) + segCount 
* sizeof(uint32_t) + libCount 
* sizeof(ImageLoader
*); 
 281         ImageLoaderMachOCompressed
* allocatedSpace 
= static_cast<ImageLoaderMachOCompressed
*>(malloc(size
)); 
 282         if ( allocatedSpace 
== NULL 
) 
 283                 throw "malloc failed"; 
 284         uint32_t* segOffsets 
= ((uint32_t*)(((uint8_t*)allocatedSpace
) + sizeof(ImageLoaderMachOCompressed
))); 
 285         bzero(&segOffsets
[segCount
], libCount
*sizeof(void*));   // zero out lib array 
 286         return new (allocatedSpace
) ImageLoaderMachOCompressed(mh
, path
, segCount
, segOffsets
, libCount
); 
 290 // common code to finish initializing object 
 291 void ImageLoaderMachOCompressed::instantiateFinish(const LinkContext
& context
) 
 293         // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 
 294         this->parseLoadCmds(context
); 
 297 uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const 
 299         return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
))); 
 303 ImageLoader
* ImageLoaderMachOCompressed::libImage(unsigned int libIndex
) const 
 305         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
) + fSegmentsCount
*sizeof(uint32_t))); 
 307         return (ImageLoader
*)(images
[libIndex
] & (-4)); 
 310 bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex
) const 
 312         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
) + fSegmentsCount
*sizeof(uint32_t))); 
 313         // re-export flag is low bit 
 314         return ((images
[libIndex
] & 1) != 0); 
 317 bool ImageLoaderMachOCompressed::libIsUpward(unsigned int libIndex
) const 
 319         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
) + fSegmentsCount
*sizeof(uint32_t))); 
 320         // upward flag is second bit 
 321         return ((images
[libIndex
] & 2) != 0); 
 325 void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex
, ImageLoader
* image
, bool reExported
, bool upward
) 
 327         uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed
) + fSegmentsCount
*sizeof(uint32_t))); 
 328         uintptr_t value 
= (uintptr_t)image
; 
 333         images
[libIndex
] = value
; 
 337 void ImageLoaderMachOCompressed::rebaseAt(const LinkContext
& context
, uintptr_t addr
, uintptr_t slide
, uint8_t type
) 
 339         if ( context
.verboseRebase 
) { 
 340                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)addr
, slide
); 
 342         //dyld::log("0x%08lX type=%d\n", addr, type); 
 343         uintptr_t* locationToFix 
= (uintptr_t*)addr
; 
 345                 case REBASE_TYPE_POINTER
: 
 346                         *locationToFix 
+= slide
; 
 348                 case REBASE_TYPE_TEXT_ABSOLUTE32
: 
 349                         *locationToFix 
+= slide
; 
 352                         dyld::throwf("bad rebase type %d", type
); 
 356 void ImageLoaderMachOCompressed::throwBadRebaseAddress(uintptr_t address
, uintptr_t segmentEndAddress
, int segmentIndex
,  
 357                                                                                 const uint8_t* startOpcodes
, const uint8_t* endOpcodes
, const uint8_t* pos
) 
 359         dyld::throwf("malformed rebase opcodes (%ld/%ld): address 0x%08lX is outside of segment %s (0x%08lX -> 0x%08lX)", 
 360                 (intptr_t)(pos
-startOpcodes
), (intptr_t)(endOpcodes
-startOpcodes
), address
, segName(segmentIndex
),  
 361                 segActualLoadAddress(segmentIndex
), segmentEndAddress
);  
 364 void ImageLoaderMachOCompressed::rebase(const LinkContext
& context
, uintptr_t slide
) 
 366         // binary uses chained fixups where are applied during binding 
 367         if ( fDyldInfo 
== NULL 
) 
 370         CRSetCrashLogMessage2(this->getPath()); 
 371         const uint8_t* const start 
= fLinkEditBase 
+ fDyldInfo
->rebase_off
; 
 372         const uint8_t* const end 
= &start
[fDyldInfo
->rebase_size
]; 
 373         const uint8_t* p 
= start
; 
 379         bool bindingBecauseOfRoot 
= this->overridesCachedDylib(ignore
); 
 380         vmAccountingSetSuspended(context
, bindingBecauseOfRoot
); 
 384                 int segmentIndex 
= 0; 
 385                 uintptr_t address 
= segActualLoadAddress(0); 
 386                 uintptr_t segmentStartAddress 
= segActualLoadAddress(0); 
 387                 uintptr_t segmentEndAddress 
= segActualEndAddress(0); 
 391                 while ( !done 
&& (p 
< end
) ) { 
 392                         uint8_t immediate 
= *p 
& REBASE_IMMEDIATE_MASK
; 
 393                         uint8_t opcode 
= *p 
& REBASE_OPCODE_MASK
; 
 396                                 case REBASE_OPCODE_DONE
: 
 399                                 case REBASE_OPCODE_SET_TYPE_IMM
: 
 402                                 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
: 
 403                                         segmentIndex 
= immediate
; 
 404                                         if ( segmentIndex 
>= fSegmentsCount 
) 
 405                                                 dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)", 
 406                                                                 segmentIndex
, fSegmentsCount
-1); 
 407                         #if TEXT_RELOC_SUPPORT 
 408                                         if ( !segWriteable(segmentIndex
) && !segHasRebaseFixUps(segmentIndex
) && !segHasBindFixUps(segmentIndex
) ) 
 410                                         if ( !segWriteable(segmentIndex
) ) 
 412                                                 dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is not a writable segment (%s)", 
 413                                                                 segmentIndex
, segName(segmentIndex
)); 
 414                                         segmentStartAddress 
= segActualLoadAddress(segmentIndex
); 
 415                                         segmentEndAddress 
= segActualEndAddress(segmentIndex
); 
 416                                         address 
= segmentStartAddress 
+ read_uleb128(p
, end
); 
 418                                 case REBASE_OPCODE_ADD_ADDR_ULEB
: 
 419                                         address 
+= read_uleb128(p
, end
); 
 421                                 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED
: 
 422                                         address 
+= immediate
*sizeof(uintptr_t); 
 424                                 case REBASE_OPCODE_DO_REBASE_IMM_TIMES
: 
 425                                         for (int i
=0; i 
< immediate
; ++i
) { 
 426                                                 if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
 427                                                         throwBadRebaseAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
 428                                                 rebaseAt(context
, address
, slide
, type
); 
 429                                                 address 
+= sizeof(uintptr_t); 
 431                                         fgTotalRebaseFixups 
+= immediate
; 
 433                                 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES
: 
 434                                         count 
= read_uleb128(p
, end
); 
 435                                         for (uint32_t i
=0; i 
< count
; ++i
) { 
 436                                                 if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
 437                                                         throwBadRebaseAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
 438                                                 rebaseAt(context
, address
, slide
, type
); 
 439                                                 address 
+= sizeof(uintptr_t); 
 441                                         fgTotalRebaseFixups 
+= count
; 
 443                                 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
: 
 444                                         if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
 445                                                 throwBadRebaseAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
 446                                         rebaseAt(context
, address
, slide
, type
); 
 447                                         address 
+= read_uleb128(p
, end
) + sizeof(uintptr_t); 
 448                                         ++fgTotalRebaseFixups
; 
 450                                 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
: 
 451                                         count 
= read_uleb128(p
, end
); 
 452                                         skip 
= read_uleb128(p
, end
); 
 453                                         for (uint32_t i
=0; i 
< count
; ++i
) { 
 454                                                 if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
 455                                                         throwBadRebaseAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
 456                                                 rebaseAt(context
, address
, slide
, type
); 
 457                                                 address 
+= skip 
+ sizeof(uintptr_t); 
 459                                         fgTotalRebaseFixups 
+= count
; 
 462                                         dyld::throwf("bad rebase opcode %d", *(p
-1)); 
 466         catch (const char* msg
) { 
 467                 const char* newMsg 
= dyld::mkstringf("%s in %s", msg
, this->getPath()); 
 471         CRSetCrashLogMessage2(NULL
); 
 474 const ImageLoader::Symbol
* ImageLoaderMachOCompressed::findShallowExportedSymbol(const char* symbol
, const ImageLoader
** foundIn
) const 
 476         //dyld::log("Compressed::findExportedSymbol(%s) in %s\n", symbol, this->getShortName()); 
 477         uint32_t trieFileOffset 
= fDyldInfo 
? fDyldInfo
->export_off  
: fExportsTrie
->dataoff
; 
 478         uint32_t trieFileSize   
= fDyldInfo 
? fDyldInfo
->export_size 
: fExportsTrie
->datasize
; 
 479         if ( trieFileSize 
== 0 ) 
 482         dyld::logBindings("%s: %s\n", this->getShortName(), symbol
); 
 484         ++ImageLoaderMachO::fgSymbolTrieSearchs
; 
 485         const uint8_t* start 
= &fLinkEditBase
[trieFileOffset
]; 
 486         const uint8_t* end 
= &start
[trieFileSize
]; 
 487         const uint8_t* foundNodeStart 
= this->trieWalk(start
, end
, symbol
);  
 488         if ( foundNodeStart 
!= NULL 
) { 
 489                 const uint8_t* p 
= foundNodeStart
; 
 490                 const uintptr_t flags 
= read_uleb128(p
, end
); 
 491                 // found match, return pointer to terminal part of node 
 492                 if ( flags 
& EXPORT_SYMBOL_FLAGS_REEXPORT 
) { 
 493                         // re-export from another dylib, lookup there 
 494                         const uintptr_t ordinal 
= read_uleb128(p
, end
); 
 495                         const char* importedName 
= (char*)p
; 
 496                         if ( importedName
[0] == '\0' ) 
 497                                 importedName 
= symbol
; 
 498                         if ( (ordinal 
> 0) && (ordinal 
<= libraryCount()) ) { 
 499                                 const ImageLoader
* reexportedFrom 
= libImage((unsigned int)ordinal
-1); 
 500                                 // Missing weak-dylib 
 501                                 if ( reexportedFrom 
== NULL 
) 
 503                                 //dyld::log("Compressed::findExportedSymbol(), %s -> %s/%s\n", symbol, reexportedFrom->getShortName(), importedName); 
 504                                 const char* reExportLibPath 
= libPath((unsigned int)ordinal
-1); 
 505                                 return reexportedFrom
->findExportedSymbol(importedName
, true, reExportLibPath
, foundIn
); 
 508                                 //dyld::throwf("bad mach-o binary, library ordinal (%u) invalid (max %u) for re-exported symbol %s in %s", 
 509                                 //      ordinal, libraryCount(), symbol, this->getPath()); 
 513                         //dyld::log("findExportedSymbol(%s) in %s found match, returning %p\n", symbol, this->getShortName(), p); 
 514                         if ( foundIn 
!= NULL 
) 
 515                                 *foundIn 
= (ImageLoader
*)this;           
 516                         // return pointer to terminal part of node 
 517                         return (Symbol
*)foundNodeStart
; 
 524 bool ImageLoaderMachOCompressed::containsSymbol(const void* addr
) const 
 526         uint32_t trieFileOffset 
= fDyldInfo 
? fDyldInfo
->export_off  
: fExportsTrie
->dataoff
; 
 527         uint32_t trieFileSize   
= fDyldInfo 
? fDyldInfo
->export_size 
: fExportsTrie
->datasize
; 
 528         const uint8_t* start 
= &fLinkEditBase
[trieFileOffset
]; 
 529         const uint8_t* end 
= &start
[trieFileSize
]; 
 530         return ( (start 
<= addr
) && (addr 
< end
) ); 
 534 uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext
& context
, const Symbol
* symbol
, const ImageLoader
* requestor
, bool runResolver
) const 
 536         uint32_t trieFileOffset 
= fDyldInfo 
? fDyldInfo
->export_off  
: fExportsTrie
->dataoff
; 
 537         uint32_t trieFileSize   
= fDyldInfo 
? fDyldInfo
->export_size 
: fExportsTrie
->datasize
; 
 538         const uint8_t* exportNode 
= (uint8_t*)symbol
; 
 539         const uint8_t* exportTrieStart 
= fLinkEditBase 
+ trieFileOffset
; 
 540         const uint8_t* exportTrieEnd 
= exportTrieStart 
+ trieFileSize
; 
 541         if ( (exportNode 
< exportTrieStart
) || (exportNode 
> exportTrieEnd
) ) 
 542                 throw "symbol is not in trie"; 
 543         //dyld::log("exportedSymbolAddress(): node=%p, nodeOffset=0x%04X in %s\n", symbol, (int)((uint8_t*)symbol - exportTrieStart), this->getShortName()); 
 544         uintptr_t flags 
= read_uleb128(exportNode
, exportTrieEnd
); 
 545         switch ( flags 
& EXPORT_SYMBOL_FLAGS_KIND_MASK 
) { 
 546                 case EXPORT_SYMBOL_FLAGS_KIND_REGULAR
: 
 547                         if ( runResolver 
&& (flags 
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) ) { 
 548                                 // this node has a stub and resolver, run the resolver to get target address 
 549                                 uintptr_t stub 
= read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)fMachOData
; // skip over stub 
 550                                 // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee 
 551                                 uintptr_t interposedStub 
= interposedAddress(context
, stub
, requestor
); 
 552                                 if ( interposedStub 
!= stub 
) 
 553                                         return interposedStub
; 
 554                                 // stub was not interposed, so run resolver 
 555                                 typedef uintptr_t (*ResolverProc
)(void); 
 556                                 ResolverProc resolver 
= (ResolverProc
)(read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)fMachOData
); 
 557 #if __has_feature(ptrauth_calls) 
 558                                 resolver 
= (ResolverProc
)__builtin_ptrauth_sign_unauthenticated(resolver
, ptrauth_key_asia
, 0); 
 560                                 uintptr_t result 
= (*resolver
)(); 
 561                                 if ( context
.verboseBind 
) 
 562                                         dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver
, result
); 
 563 #if __has_feature(ptrauth_calls) 
 564                         result 
= (uintptr_t)__builtin_ptrauth_strip((void*)result
, ptrauth_key_asia
); 
 568                         return read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)fMachOData
; 
 569                 case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
: 
 570                         if ( flags 
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 
) 
 571                                 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, symbol
); 
 572                         return read_uleb128(exportNode
, exportTrieEnd
) + (uintptr_t)fMachOData
; 
 573                 case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
: 
 574                         if ( flags 
& EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 
) 
 575                                 dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, symbol
); 
 576                         return read_uleb128(exportNode
, exportTrieEnd
); 
 578                         dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags
, symbol
); 
 582 bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol
* symbol
) const 
 584         uint32_t trieFileOffset 
= fDyldInfo 
? fDyldInfo
->export_off  
: fExportsTrie
->dataoff
; 
 585         uint32_t trieFileSize   
= fDyldInfo 
? fDyldInfo
->export_size 
: fExportsTrie
->datasize
; 
 586         const uint8_t* exportNode 
= (uint8_t*)symbol
; 
 587         const uint8_t* exportTrieStart 
= fLinkEditBase 
+ trieFileOffset
; 
 588         const uint8_t* exportTrieEnd 
= exportTrieStart 
+ trieFileSize
; 
 589         if ( (exportNode 
< exportTrieStart
) || (exportNode 
> exportTrieEnd
) ) 
 590                 throw "symbol is not in trie"; 
 591         uintptr_t flags 
= read_uleb128(exportNode
, exportTrieEnd
); 
 592         return ( flags 
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 
); 
 596 const char* ImageLoaderMachOCompressed::exportedSymbolName(const Symbol
* symbol
) const 
 598         throw "NSNameOfSymbol() not supported with compressed LINKEDIT"; 
 601 unsigned int ImageLoaderMachOCompressed::exportedSymbolCount() const 
 603         throw "NSSymbolDefinitionCountInObjectFileImage() not supported with compressed LINKEDIT"; 
 606 const ImageLoader::Symbol
* ImageLoaderMachOCompressed::exportedSymbolIndexed(unsigned int index
) const 
 608         throw "NSSymbolDefinitionNameInObjectFileImage() not supported with compressed LINKEDIT"; 
 611 unsigned int ImageLoaderMachOCompressed::importedSymbolCount() const 
 613         throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT"; 
 616 const ImageLoader::Symbol
* ImageLoaderMachOCompressed::importedSymbolIndexed(unsigned int index
) const 
 618         throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT"; 
 621 const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol
* symbol
) const 
 623         throw "NSSymbolReferenceNameInObjectFileImage() not supported with compressed LINKEDIT"; 
 628 uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext
& context
, const char* symbolName
, bool weak_import
,  
 629                                                                                                         bool runResolver
, const ImageLoader
** foundIn
) 
 632         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) { 
 633                 if ( *foundIn 
!= this ) 
 634                         context
.addDynamicReference(this, const_cast<ImageLoader
*>(*foundIn
)); 
 635                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this, runResolver
); 
 637         // if a bundle is loaded privately the above will not find its exports 
 638         if ( this->isBundle() && this->hasHiddenExports() ) { 
 639                 // look in self for needed symbol 
 640                 sym 
= this->findShallowExportedSymbol(symbolName
, foundIn
); 
 642                         return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this, runResolver
); 
 645                 // definition can't be found anywhere, ok because it is weak, just return 0 
 648         throwSymbolNotFound(context
, symbolName
, this->getPath(), "", "flat namespace"); 
 652 static void patchCacheUsesOf(const ImageLoader::LinkContext
& context
, const dyld3::closure::Image
* overriddenImage
, 
 653                                                          uint32_t cacheOffsetOfImpl
, const char* symbolName
, uintptr_t newImpl
) 
 655         uintptr_t cacheStart 
= (uintptr_t)context
.dyldCache
; 
 656         uint32_t imageIndex 
= overriddenImage
->imageNum() - (uint32_t)context
.dyldCache
->cachedDylibsImageArray()->startImageNum(); 
 657         context
.dyldCache
->forEachPatchableUseOfExport(imageIndex
, cacheOffsetOfImpl
, ^(dyld_cache_patchable_location patchLocation
) { 
 658                 uintptr_t* loc 
= (uintptr_t*)(cacheStart
+patchLocation
.cacheOffset
); 
 659 #if __has_feature(ptrauth_calls) 
 660                 if ( patchLocation
.authenticated 
) { 
 661                          dyld3::MachOLoaded::ChainedFixupPointerOnDisk fixupInfo
; 
 662                         fixupInfo
.arm64e
.authRebase
.auth      
= true; 
 663                         fixupInfo
.arm64e
.authRebase
.addrDiv   
= patchLocation
.usesAddressDiversity
; 
 664                         fixupInfo
.arm64e
.authRebase
.diversity 
= patchLocation
.discriminator
; 
 665                         fixupInfo
.arm64e
.authRebase
.key       
= patchLocation
.key
; 
 666                         uintptr_t newValue 
= fixupInfo
.arm64e
.signPointer(loc
, newImpl 
+ DyldSharedCache::getAddend(patchLocation
)); 
 667                         if ( *loc 
!= newValue 
) { 
 669                                 if ( context
.verboseBind 
) 
 670                                         dyld::log("dyld: cache fixup: *%p = %p (JOP: diversity 0x%04X, addr-div=%d, key=%s) to %s\n", 
 671                                                         loc
, (void*)newValue
, patchLocation
.discriminator
, patchLocation
.usesAddressDiversity
, DyldSharedCache::keyName(patchLocation
), symbolName
); 
 676                 uintptr_t newValue 
= newImpl 
+ (uintptr_t)DyldSharedCache::getAddend(patchLocation
); 
 677                 if ( *loc 
!= newValue 
) { 
 679                         if ( context
.verboseBind 
) 
 680                                 dyld::log("dyld: cache fixup: *%p = %p to %s\n", loc
, (void*)newValue
, symbolName
); 
 687 uintptr_t ImageLoaderMachOCompressed::resolveWeak(const LinkContext
& context
, const char* symbolName
, bool weak_import
, 
 688                                                                                                   bool runResolver
, const ImageLoader
** foundIn
) 
 691         CoalesceNotifier notifier 
= nullptr; 
 692         __block 
uintptr_t   foundOutsideCache     
= 0; 
 693         __block 
const char* foundOutsideCachePath 
= nullptr; 
 694         __block 
uintptr_t   lastFoundInCache      
= 0; 
 695         if ( this->usesChainedFixups() ) { 
 696                 notifier 
= ^(const Symbol
* implSym
, const ImageLoader
* implIn
, const mach_header
* implMh
) { 
 697                         // This block is only called in dyld2 mode when a non-cached image is search for which weak-def implementation to use 
 698                         // As a side effect of that search we notice any implementations outside and inside the cache, 
 699                         // and use that to trigger patching the cache to use the implementation outside the cache. 
 700                         uintptr_t implAddr 
= implIn
->getExportedSymbolAddress(implSym
, context
, nullptr, false, symbolName
); 
 701                         if ( ((dyld3::MachOLoaded
*)implMh
)->inDyldCache() ) { 
 702                                 if ( foundOutsideCache 
!= 0 ) { 
 703                                         // have an implementation in cache and and earlier one not in the cache, patch cache to use earlier one 
 704                                         lastFoundInCache 
= implAddr
; 
 706                                         if ( context
.dyldCache
->findMachHeaderImageIndex(implMh
, imageIndex
) ) { 
 707                                                 const dyld3::closure::Image
* overriddenImage 
= context
.dyldCache
->cachedDylibsImageArray()->imageForNum(imageIndex
+1); 
 708                                                 uint32_t cacheOffsetOfImpl 
= (uint32_t)((uintptr_t)implAddr 
- (uintptr_t)context
.dyldCache
); 
 709                                                 if ( context
.verboseWeakBind 
) 
 710                                                         dyld::log("dyld: weak bind, patching dyld cache uses of %s to use 0x%lX in %s\n", symbolName
, foundOutsideCache
, foundOutsideCachePath
); 
 711                                                 patchCacheUsesOf(context
, overriddenImage
, cacheOffsetOfImpl
, symbolName
, foundOutsideCache
); 
 716                                 // record first non-cache implementation 
 717                                 if ( foundOutsideCache 
== 0 ) { 
 718                                         foundOutsideCache     
= implAddr
; 
 719                                         foundOutsideCachePath 
= implIn
->getPath(); 
 725         if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
, notifier
) ) { 
 726                 if ( *foundIn 
!= this ) 
 727                         context
.addDynamicReference(this, const_cast<ImageLoader
*>(*foundIn
)); 
 728                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this, runResolver
); 
 730         // if a bundle is loaded privately the above will not find its exports 
 731         if ( this->isBundle() && this->hasHiddenExports() ) { 
 732                 // look in self for needed symbol 
 733                 sym 
= this->findShallowExportedSymbol(symbolName
, foundIn
); 
 735                         return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this, runResolver
); 
 738                 // definition can't be found anywhere, ok because it is weak, just return 0 
 741         throwSymbolNotFound(context
, symbolName
, this->getPath(), "", "weak"); 
 745 uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext
& context
, const char* symbolName
, const ImageLoader
* definedInImage
, 
 746                                                                                                           const ImageLoader
* requestorImage
, unsigned requestorOrdinalOfDef
, bool weak_import
, bool runResolver
, 
 747                                                                                                           const ImageLoader
** foundIn
) 
 751         if ( definedInImage
->findExportedSymbolAddress(context
, symbolName
, requestorImage
, requestorOrdinalOfDef
, runResolver
, foundIn
, &address
) ) 
 755                 // definition can't be found anywhere, ok because it is weak, just return 0 
 759         // nowhere to be found, check if maybe this image is too new for this OS 
 760         char versMismatch
[256]; 
 761         versMismatch
[0] = '\0'; 
 762         uint32_t imageMinOS 
= this->minOSVersion(); 
 763         // dyld is always built for the current OS, so we can get the current OS version 
 764         // from the load command in dyld itself. 
 765         extern const mach_header __dso_handle
; 
 766         uint32_t dyldMinOS 
= ImageLoaderMachO::minOSVersion(&__dso_handle
); 
 767         if ( imageMinOS 
> dyldMinOS 
) { 
 769                 const char* msg 
= dyld::mkstringf(" (which was built for Mac OS X %d.%d)", imageMinOS 
>> 16, (imageMinOS 
>> 8) & 0xFF); 
 771                 const char* msg 
= dyld::mkstringf(" (which was built for iOS %d.%d)", imageMinOS 
>> 16, (imageMinOS 
>> 8) & 0xFF); 
 773                 strcpy(versMismatch
, msg
); 
 776         throwSymbolNotFound(context
, symbolName
, this->getPath(), versMismatch
, definedInImage
->getPath()); 
 780 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext
& context
, const char* symbolName
,  
 781                                                                                                         uint8_t symboFlags
, long libraryOrdinal
, const ImageLoader
** targetImage
, 
 782                                                                                                         LastLookup
* last
, bool runResolver
) 
 786         // only clients that benefit from caching last lookup pass in a LastLookup struct 
 787         if ( last 
!= NULL 
) { 
 788                 if ( (last
->ordinal 
== libraryOrdinal
) 
 789                         && (last
->flags 
== symboFlags
) 
 790                         && (last
->name 
== symbolName
) ) { 
 791                                 *targetImage 
= last
->foundIn
; 
 796         bool weak_import 
= (symboFlags 
& BIND_SYMBOL_FLAGS_WEAK_IMPORT
); 
 797         uintptr_t symbolAddress
; 
 798         if ( context
.bindFlat 
|| (libraryOrdinal 
== BIND_SPECIAL_DYLIB_FLAT_LOOKUP
) ) { 
 799                 symbolAddress 
= this->resolveFlat(context
, symbolName
, weak_import
, runResolver
, targetImage
); 
 801         else if ( libraryOrdinal 
== BIND_SPECIAL_DYLIB_WEAK_LOOKUP 
) { 
 802                 symbolAddress 
= this->resolveWeak(context
, symbolName
, weak_import
, runResolver
, targetImage
); 
 805                 if ( libraryOrdinal 
== BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE 
) { 
 806                         *targetImage 
= context
.mainExecutable
; 
 808                 else if ( libraryOrdinal 
== BIND_SPECIAL_DYLIB_SELF 
) { 
 811                 else if ( libraryOrdinal 
<= 0 ) { 
 812                         dyld::throwf("bad mach-o binary, unknown special library ordinal (%ld) too big for symbol %s in %s", 
 813                                 libraryOrdinal
, symbolName
, this->getPath()); 
 815                 else if ( (unsigned)libraryOrdinal 
<= libraryCount() ) { 
 816                         *targetImage 
= libImage((unsigned int)libraryOrdinal
-1); 
 819                         dyld::throwf("bad mach-o binary, library ordinal (%ld) too big (max %u) for symbol %s in %s", 
 820                                 libraryOrdinal
, libraryCount(), symbolName
, this->getPath()); 
 822                 if ( *targetImage 
== NULL 
) { 
 824                                 // if target library not loaded and reference is weak or library is weak return 0 
 828                                 // Try get the path from the load commands 
 829                                 if ( const char* depPath 
= libPath((unsigned int)libraryOrdinal
-1) ) { 
 830                                         dyld::throwf("can't resolve symbol %s in %s because dependent dylib %s could not be loaded", 
 831                                                                  symbolName
, this->getPath(), depPath
); 
 833                                         dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%ld could not be loaded", 
 834                                                                  symbolName
, this->getPath(), libraryOrdinal
); 
 839                         symbolAddress 
= resolveTwolevel(context
, symbolName
, *targetImage
, this, (unsigned)libraryOrdinal
, weak_import
, runResolver
, targetImage
); 
 843         // save off lookup results if client wants  
 844         if ( last 
!= NULL 
) { 
 845                 last
->ordinal   
= libraryOrdinal
; 
 846                 last
->flags             
= symboFlags
; 
 847                 last
->name              
= symbolName
; 
 848                 last
->foundIn   
= *targetImage
; 
 849                 last
->result    
= symbolAddress
; 
 852         return symbolAddress
; 
 855 uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext
& context
, ImageLoaderMachOCompressed
* image
, 
 856                                                                                          uintptr_t addr
, uint8_t type
, const char* symbolName
, 
 857                                                                                          uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
 858                                                                                          ExtraBindData 
*extraBindData
, 
 859                                                                                          const char* msg
, LastLookup
* last
, bool runResolver
) 
 861         const ImageLoader
*      targetImage
; 
 862         uintptr_t                       symbolAddress
; 
 865     if (type 
== BIND_TYPE_THREADED_REBASE
) { 
 867         targetImage 
= nullptr; 
 869         symbolAddress 
= image
->resolve(context
, symbolName
, symbolFlags
, libraryOrdinal
, &targetImage
, last
, runResolver
); 
 872         return image
->bindLocation(context
, image
->imageBaseAddress(), addr
, symbolAddress
, type
, symbolName
, addend
, image
->getPath(), targetImage 
? targetImage
->getPath() : NULL
, msg
, extraBindData
, image
->fSlide
); 
 876 void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address
, uintptr_t segmentEndAddress
, int segmentIndex
,  
 877                                                                                 const uint8_t* startOpcodes
, const uint8_t* endOpcodes
, const uint8_t* pos
) 
 879         dyld::throwf("malformed binding opcodes (%ld/%ld): address 0x%08lX is outside segment %s (0x%08lX -> 0x%08lX)", 
 880                 (intptr_t)(pos
-startOpcodes
), (intptr_t)(endOpcodes
-startOpcodes
), address
, segName(segmentIndex
),  
 881                 segActualLoadAddress(segmentIndex
), segmentEndAddress
);  
 885 void ImageLoaderMachOCompressed::doBind(const LinkContext
& context
, bool forceLazysBound
, const ImageLoader
* reExportParent
) 
 887         CRSetCrashLogMessage2(this->getPath()); 
 889         // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 
 890         // note: flat-namespace binaries need to have imports rebound (even if correctly prebound) 
 891         if ( this->usablePrebinding(context
) ) { 
 892                 // don't need to bind 
 893                 // except weak which may now be inline with the regular binds 
 894                 if ( this->participatesInCoalescing() && (fDyldInfo 
!= nullptr) ) { 
 895                         // run through all binding opcodes 
 896                         eachBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
 897                                                                 uintptr_t addr
, uint8_t type
, const char* symbolName
, 
 898                                                                 uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
 899                                                                 ExtraBindData 
*extraBindData
, 
 900                                                                 const char* msg
, LastLookup
* last
, bool runResolver
) { 
 901                                 if ( libraryOrdinal 
!= BIND_SPECIAL_DYLIB_WEAK_LOOKUP 
) 
 903                                 return ImageLoaderMachOCompressed::bindAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
 904                                                                                                                   addend
, libraryOrdinal
, extraBindData
, 
 905                                                                                                                   msg
, last
, runResolver
); 
 910                 uint64_t t0 
= mach_absolute_time(); 
 913                 bool bindingBecauseOfRoot 
= ( this->overridesCachedDylib(ignore
) || this->inSharedCache() ); 
 914                 vmAccountingSetSuspended(context
, bindingBecauseOfRoot
); 
 916                 if ( fChainedFixups 
!= NULL 
) { 
 917                         const dyld_chained_fixups_header
* fixupsHeader 
= (dyld_chained_fixups_header
*)(fLinkEditBase 
+ fChainedFixups
->dataoff
); 
 918                         doApplyFixups(context
, fixupsHeader
); 
 920                 else if ( fDyldInfo 
!= nullptr ) { 
 921                 #if TEXT_RELOC_SUPPORT 
 922                         // if there are __TEXT fixups, temporarily make __TEXT writable 
 923                         if ( fTextSegmentBinds 
) 
 924                                 this->makeTextSegmentWritable(context
, true); 
 927                         // run through all binding opcodes 
 928                         eachBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
 929                                                                 uintptr_t addr
, uint8_t type
, const char* symbolName
, 
 930                                                                 uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
 931                                                                 ExtraBindData 
*extraBindData
, 
 932                                                                 const char* msg
, LastLookup
* last
, bool runResolver
) { 
 933                                 return ImageLoaderMachOCompressed::bindAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
 934                                                                                                                   addend
, libraryOrdinal
, extraBindData
, 
 935                                                                                                                   msg
, last
, runResolver
); 
 938                 #if TEXT_RELOC_SUPPORT 
 939                         // if there were __TEXT fixups, restore write protection 
 940                         if ( fTextSegmentBinds 
) 
 941                                 this->makeTextSegmentWritable(context
, false); 
 944                         // if this image is in the shared cache, but depends on something no longer in the shared cache, 
 945                         // there is no way to reset the lazy pointers, so force bind them now 
 946                         if ( forceLazysBound 
|| fInSharedCache 
) 
 947                                 this->doBindJustLazies(context
); 
 949                         // this image is in cache, but something below it is not.  If 
 950                         // this image has lazy pointer to a resolver function, then 
 951                         // the stub may have been altered to point to a shared lazy pointer. 
 952                         if ( fInSharedCache 
) 
 953                                 this->updateOptimizedLazyPointers(context
); 
 956                 uint64_t t1 
= mach_absolute_time(); 
 957                 ImageLoader::fgTotalRebindCacheTime 
+= (t1
-t0
); 
 960         // See if this dylib overrides something in the dyld cache 
 961         uint32_t dyldCacheOverrideImageNum
; 
 962         if ( context
.dyldCache 
&& context
.dyldCache
->header
.builtFromChainedFixups 
&& overridesCachedDylib(dyldCacheOverrideImageNum
) ) { 
 963                 // need to patch all other places in cache that point to the overridden dylib, to point to this dylib instead 
 964                 const dyld3::closure::Image
* overriddenImage 
= context
.dyldCache
->cachedDylibsImageArray()->imageForNum(dyldCacheOverrideImageNum
); 
 965                 uint32_t imageIndex 
= dyldCacheOverrideImageNum 
- (uint32_t)context
.dyldCache
->cachedDylibsImageArray()->startImageNum(); 
 966                 //dyld::log("doBind() found override of %s\n", this->getPath()); 
 967                 context
.dyldCache
->forEachPatchableExport(imageIndex
, ^(uint32_t cacheOffsetOfImpl
, const char* exportName
) { 
 968                         uintptr_t newImpl 
= 0; 
 969                         const ImageLoader
* foundIn 
= nullptr; 
 970                         if ( this->findExportedSymbolAddress(context
, exportName
, NULL
, 0, false, &foundIn
, &newImpl
) ) { 
 971                                 //dyld::log("   patchCacheUsesOf(%s) found in %s\n", exportName, foundIn->getPath()); 
 972                                 patchCacheUsesOf(context
, overriddenImage
, cacheOffsetOfImpl
, exportName
, newImpl
); 
 975                                 // <rdar://problem/59196856> allow patched impls to move between re-export sibling dylibs 
 976                                 if ( reExportParent 
!= nullptr ) { 
 977                                         reExportParent
->forEachReExportDependent(^(const ImageLoader
* reExportedDep
, bool& stop
) { 
 978                                                 uintptr_t siblingImpl 
= 0; 
 979                                                 const ImageLoader
* foundInSibling 
= nullptr; 
 980                                                 if ( reExportedDep
->findExportedSymbolAddress(context
, exportName
, NULL
, 0, false, &foundInSibling
, &siblingImpl
) ) { 
 982                                                         //dyld::log("   patchCacheUsesOf(%s) found in sibling %s\n", exportName, foundInSibling->getPath()); 
 983                                                         patchCacheUsesOf(context
, overriddenImage
, cacheOffsetOfImpl
, exportName
, siblingImpl
); 
 991         // set up dyld entry points in image 
 992         // do last so flat main executables will have __dyld or __program_vars set up 
 993         this->setupLazyPointerHandler(context
); 
 994         CRSetCrashLogMessage2(NULL
); 
 998 void ImageLoaderMachOCompressed::doBindJustLazies(const LinkContext
& context
) 
1000         eachLazyBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
1001                                                         uintptr_t addr
, uint8_t type
, const char* symbolName
, 
1002                                                         uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
1003                                                         ExtraBindData 
*extraBindData
, 
1004                                                         const char* msg
, LastLookup
* last
, bool runResolver
) { 
1005                 return ImageLoaderMachOCompressed::bindAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
1006                                                                                                   addend
, libraryOrdinal
, extraBindData
, 
1007                                                                                                   msg
, last
, runResolver
); 
1011 void ImageLoaderMachOCompressed::doApplyFixups(const LinkContext
& context
, const dyld_chained_fixups_header
* fixupsHeader
) 
1013         const dyld3::MachOLoaded
* ml 
= (dyld3::MachOLoaded
*)machHeader(); 
1014         const dyld_chained_starts_in_image
* starts 
= (dyld_chained_starts_in_image
*)((uint8_t*)fixupsHeader 
+ fixupsHeader
->starts_offset
); 
1016         // build table of resolved targets for each symbol ordinal 
1017         STACK_ALLOC_OVERFLOW_SAFE_ARRAY(const void*, targetAddrs
, 128); 
1018         targetAddrs
.reserve(fixupsHeader
->imports_count
); 
1019         __block Diagnostics diag
; 
1020         const dyld3::MachOAnalyzer
* ma 
= (dyld3::MachOAnalyzer
*)ml
; 
1021         ma
->forEachChainedFixupTarget(diag
, ^(int libOrdinal
, const char* symbolName
, uint64_t addend
, bool weakImport
, bool& stop
) { 
1022                 const ImageLoader
*      targetImage
; 
1023                 uint8_t symbolFlags 
= weakImport 
? BIND_SYMBOL_FLAGS_WEAK_IMPORT 
: 0; 
1025                         uintptr_t symbolAddress 
= this->resolve(context
, symbolName
, symbolFlags
, libOrdinal
, &targetImage
, NULL
, true); 
1026                         targetAddrs
.push_back((void*)(symbolAddress 
+ addend
)); 
1028                 catch (const char* msg
) { 
1030                         diag
.error("%s", msg
); 
1033         if ( diag
.hasError() ) 
1034                 throw strdup(diag
.errorMessage()); 
1036         auto logFixups 
= ^(void* loc
, void* newValue
) { 
1037                 dyld::log("dyld: fixup: %s:%p = %p\n", this->getShortName(), loc
, newValue
); 
1039         if ( !context
.verboseBind 
) 
1040                 logFixups 
= nullptr; 
1042         ml
->fixupAllChainedFixups(diag
, starts
, fSlide
, targetAddrs
, logFixups
); 
1043         if ( diag
.hasError() ) 
1044                 throw strdup(diag
.errorMessage()); 
1047 void ImageLoaderMachOCompressed::registerInterposing(const LinkContext
& context
) 
1049         // mach-o files advertise interposing by having a __DATA __interpose section 
1050         struct InterposeData 
{ uintptr_t replacement
; uintptr_t replacee
; }; 
1052         __block Diagnostics diag
; 
1053         const dyld3::MachOAnalyzer
* ma 
= (dyld3::MachOAnalyzer
*)fMachOData
; 
1054         ma
->forEachInterposingSection(diag
, ^(uint64_t vmOffset
, uint64_t vmSize
, bool& stopSections
) { 
1055                 if ( ma
->hasChainedFixups() ) { 
1056             const uint16_t pointerFormat 
= ma
->chainedPointerFormat(); 
1057                         const uint8_t* sectionStart 
= fMachOData
+vmOffset
; 
1058                         const uint8_t* sectionEnd   
= fMachOData
+vmOffset
+vmSize
; 
1059                 ma
->withChainStarts(diag
, ma
->chainStartsOffset(), ^(const dyld_chained_starts_in_image
* startsInfo
) { 
1060                         __block 
uintptr_t lastRebaseTarget 
= 0; 
1061                                 ma
->forEachFixupInAllChains(diag
, startsInfo
, false, ^(dyld3::MachOLoaded::ChainedFixupPointerOnDisk
* fixupLoc
, const dyld_chained_starts_in_segment
* segInfo
, bool& stopFixups
) { 
1062                                         if ( ((uint8_t*)fixupLoc 
< sectionStart
) || ((uint8_t*)fixupLoc 
>= sectionEnd
) ) 
1064                                         uint64_t rebaseTargetRuntimeOffset
; 
1065                                         uint32_t bindOrdinal
; 
1067                                 if ( fixupLoc
->isRebase(pointerFormat
, 0, rebaseTargetRuntimeOffset
) ) { 
1068                                                 //dyld::log("interpose rebase at fixup at %p to 0x%0llX\n", fixupLoc, rebaseTargetRuntimeOffset); 
1069                                                 lastRebaseTarget 
= (uintptr_t)(fMachOData
+rebaseTargetRuntimeOffset
); 
1071                                 else if ( fixupLoc
->isBind(pointerFormat
, bindOrdinal
, ptrAddend
) ) { 
1072                                                 //dyld::log("interpose bind fixup at %p to bind ordinal %d\n", fixupLoc, bindOrdinal); 
1073                                                 __block 
uint32_t targetBindIndex 
= 0; 
1074                                                 ma
->forEachChainedFixupTarget(diag
, ^(int libraryOrdinal
, const char* symbolName
, uint64_t addend
, bool weakImport
, bool& stop
) { 
1075                                                         if ( targetBindIndex 
== bindOrdinal 
) { 
1076                                                                 //dyld::log("interpose bind fixup at %p is to %s libOrdinal=%d\n", fixupLoc, symbolName, libraryOrdinal); 
1077                                                                 LastLookup
* last 
= NULL
; 
1078                                                                 const ImageLoader
* targetImage
; 
1079                                                                 uintptr_t targetBindAddress 
= 0; 
1081                                                                         targetBindAddress 
= this->resolve(context
, symbolName
, 0, libraryOrdinal
, &targetImage
, last
, false); 
1083                                                                 catch (const char* msg
) { 
1086                                                                         targetBindAddress 
= 0; 
1088                                                                 //dyld::log("interpose bind fixup at %p is bound to 0x%lX\n", fixupLoc, targetBindAddress); 
1089                                                                 // <rdar://problem/25686570> ignore interposing on a weak function that does not exist 
1090                                                                 if ( targetBindAddress 
== 0 ) 
1092                                                                 ImageLoader::InterposeTuple tuple
; 
1093                                                                 tuple
.replacement   
= lastRebaseTarget
; 
1094                                                                 tuple
.neverImage        
= this; 
1095                                                                 tuple
.onlyImage         
= NULL
; 
1096                                                                 tuple
.replacee      
= targetBindAddress
; 
1097                                                                 // <rdar://problem/7937695> verify that replacement is in this image 
1098                                                                 if ( this->containsAddress((void*)tuple
.replacement
) ) { 
1099                                                                         if ( context
.verboseInterposing 
) 
1100                                                                                 dyld::log("dyld: interposing 0x%lx with 0x%lx\n", tuple
.replacee
, tuple
.replacement
); 
1101                                                                         // chain to any existing interpositions 
1102                                                                         for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
1103                                                                                 if ( it
->replacee 
== tuple
.replacee 
) { 
1104                                                                                         tuple
.replacee 
= it
->replacement
; 
1107                                                                         ImageLoader::fgInterposingTuples
.push_back(tuple
); 
1117                         // traditional (non-chained) fixups 
1118                         const size_t         count          
= (size_t)(vmSize 
/ sizeof(InterposeData
)); 
1119                         const InterposeData
* interposeArray 
= (InterposeData
*)(fMachOData
+vmOffset
); 
1120                         if ( context
.verboseInterposing 
) 
1121                                 dyld::log("dyld: found %lu interposing tuples in %s\n", count
, getPath()); 
1122                         for (size_t j
=0; j 
< count
; ++j
) { 
1123                                 uint64_t bindOffset 
= ((uint8_t*)&(interposeArray
[j
].replacee
)) - fMachOData
; 
1124                                 ma
->forEachBind(diag
, ^(uint64_t runtimeOffset
, int libOrdinal
, const char* symbolName
, bool weakImport
, bool lazyBind
, uint64_t addend
, bool& stopBinds
) { 
1125                                         if ( bindOffset 
!= runtimeOffset 
) 
1128                                         LastLookup
* last 
= NULL
; 
1129                                         const ImageLoader
* targetImage
; 
1130                                         uintptr_t targetBindAddress 
= 0; 
1132                                                 targetBindAddress 
= this->resolve(context
, symbolName
, 0, libOrdinal
, &targetImage
, last
, false); 
1134                                         catch (const char* msg
) { 
1137                                                 targetBindAddress 
= 0; 
1139                                         ImageLoader::InterposeTuple tuple
; 
1140                                         tuple
.replacement     
= interposeArray
[j
].replacement
; 
1141                                         tuple
.neverImage      
= this; 
1142                                         tuple
.onlyImage       
= NULL
; 
1143                                         tuple
.replacee        
= targetBindAddress
; 
1144                                         // <rdar://problem/25686570> ignore interposing on a weak function that does not exist 
1145                                         if ( tuple
.replacee 
== 0 ) 
1147                                         // <rdar://problem/7937695> verify that replacement is in this image 
1148                                         if ( this->containsAddress((void*)tuple
.replacement
) ) { 
1149                                                 if ( context
.verboseInterposing 
) 
1150                                                         dyld::log("dyld:   interposing 0x%lx with 0x%lx\n", tuple
.replacee
, tuple
.replacement
); 
1151                                                 // chain to any existing interpositions 
1152                                                 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
1153                                                         if ( it
->replacee 
== tuple
.replacee 
) { 
1154                                                                 tuple
.replacee 
= it
->replacement
; 
1157                                                 ImageLoader::fgInterposingTuples
.push_back(tuple
); 
1159                                 }, ^(const char* symbolName
){ 
1166 bool ImageLoaderMachOCompressed::usesChainedFixups() const 
1168         return ((dyld3::MachOLoaded
*)machHeader())->hasChainedFixups(); 
1171 struct ThreadedBindData 
{ 
1172     ThreadedBindData(const char* symbolName
, int64_t addend
, long libraryOrdinal
, uint8_t symbolFlags
, uint8_t type
) 
1173     : symbolName(symbolName
), addend(addend
), libraryOrdinal(libraryOrdinal
), symbolFlags(symbolFlags
), type(type
) { } 
1175     std::tuple
<const char*, int64_t, long, bool, uint8_t> pack() const { 
1176         return std::make_tuple(symbolName
, addend
, libraryOrdinal
, symbolFlags
, type
); 
1179     const char* symbolName     
= nullptr; 
1181     long libraryOrdinal        
= 0; 
1182     uint8_t symbolFlags        
= 0; 
1186 void ImageLoaderMachOCompressed::makeDataReadOnly() const 
1188 #if !TEXT_RELOC_SUPPORT 
1189         if ( fReadOnlyDataSegment 
&& !this->ImageLoader::inSharedCache() ) { 
1190                 for (unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
1191                         if ( segIsReadOnlyData(i
) ) { 
1192                                 uintptr_t start 
= segActualLoadAddress(i
); 
1193                                 uintptr_t size 
= segSize(i
); 
1194         #if defined(__x86_64__) && !TARGET_OS_SIMULATOR 
1195                                 if ( dyld::isTranslated() ) { 
1196                                         // <rdar://problem/48325338> can't mprotect non-16KB segments 
1197                                         if ( ((size 
& 0x3FFF) != 0) || ((start 
& 0x3FFF) != 0) ) 
1201                                 ::mprotect((void*)start
, size
, PROT_READ
); 
1202                                 //dyld::log("make read-only 0x%09lX -> 0x%09lX\n", (long)start, (long)(start+size)); 
1210 void ImageLoaderMachOCompressed::eachBind(const LinkContext
& context
, bind_handler handler
) 
1214                 int segmentIndex 
= -1; 
1215                 uintptr_t address 
= segActualLoadAddress(0); 
1216                 uintptr_t segmentStartAddress 
= segActualLoadAddress(0); 
1217                 uintptr_t segmentEndAddress 
= segActualEndAddress(0); 
1218                 const char* symbolName 
= NULL
; 
1219                 uint8_t symboFlags 
= 0; 
1220                 bool libraryOrdinalSet 
= false; 
1221                 long libraryOrdinal 
= 0; 
1222                 intptr_t addend 
= 0; 
1225         uintptr_t segOffset 
= 0; 
1227                 dyld3::OverflowSafeArray
<ThreadedBindData
> ordinalTable
; 
1228         bool useThreadedRebaseBind 
= false; 
1229         ExtraBindData extraBindData
; 
1230                 LastLookup last 
= { 0, 0, NULL
, 0, NULL 
}; 
1231                 const uint8_t* const start 
= fLinkEditBase 
+ fDyldInfo
->bind_off
; 
1232                 const uint8_t* const end 
= &start
[fDyldInfo
->bind_size
]; 
1233                 const uint8_t* p 
= start
; 
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_DYLIB_ORDINAL_IMM
: 
1244                                         libraryOrdinal 
= immediate
; 
1245                                         libraryOrdinalSet 
= true; 
1247                                 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
: 
1248                                         libraryOrdinal 
= read_uleb128(p
, end
); 
1249                                         libraryOrdinalSet 
= true; 
1251                                 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
: 
1252                                         // the special ordinals are negative numbers 
1253                                         if ( immediate 
== 0 ) 
1256                                                 int8_t signExtended 
= BIND_OPCODE_MASK 
| immediate
; 
1257                                                 libraryOrdinal 
= signExtended
; 
1259                                         libraryOrdinalSet 
= true; 
1261                                 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
: 
1262                                         symbolName 
= (char*)p
; 
1263                                         symboFlags 
= immediate
; 
1268                                 case BIND_OPCODE_SET_TYPE_IMM
: 
1271                                 case BIND_OPCODE_SET_ADDEND_SLEB
: 
1272                                         addend 
= read_sleb128(p
, end
); 
1274                                 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
: 
1275                                         segmentIndex 
= immediate
; 
1276                                         if ( (segmentIndex 
>= fSegmentsCount
) || (segmentIndex 
< 0) ) 
1277                                                 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is out of range (0..%d)", 
1278                                                                 segmentIndex
, fSegmentsCount
-1); 
1279                         #if TEXT_RELOC_SUPPORT 
1280                                         if ( !segWriteable(segmentIndex
) && !segHasRebaseFixUps(segmentIndex
) && !segHasBindFixUps(segmentIndex
) ) 
1282                                         if ( !segWriteable(segmentIndex
) ) 
1284                                                 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is not writable", segmentIndex
); 
1285                                         segOffset 
= read_uleb128(p
, end
); 
1286                                         if ( segOffset 
> segSize(segmentIndex
) ) 
1287                                                 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has offset 0x%08lX beyond segment size (0x%08lX)", segOffset
, segSize(segmentIndex
)); 
1288                                         segmentStartAddress 
= segActualLoadAddress(segmentIndex
); 
1289                                         address 
= segmentStartAddress 
+ segOffset
; 
1290                                         segmentEndAddress 
= segActualEndAddress(segmentIndex
); 
1292                                 case BIND_OPCODE_ADD_ADDR_ULEB
: 
1293                                         address 
+= read_uleb128(p
, end
); 
1295                                 case BIND_OPCODE_DO_BIND
: 
1296                     if (!useThreadedRebaseBind
) { 
1297                         if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
1298                             throwBadBindingAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
1299                         if ( symbolName  
== NULL 
) 
1300                             dyld::throwf("BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM"); 
1301                         if ( segmentIndex 
== -1 ) 
1302                             dyld::throwf("BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"); 
1303                         if ( !libraryOrdinalSet 
) 
1304                             dyld::throwf("BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL*"); 
1305                         handler(context
, this, address
, type
, symbolName
, symboFlags
, addend
, libraryOrdinal
, 
1306                                                                 &extraBindData
, "", &last
, false); 
1307                         address 
+= sizeof(intptr_t); 
1309                         ordinalTable
.push_back(ThreadedBindData(symbolName
, addend
, libraryOrdinal
, symboFlags
, type
)); 
1312                                 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
: 
1313                                         if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
1314                                                 throwBadBindingAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
1315                                         if ( symbolName  
== NULL 
) 
1316                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM"); 
1317                                         if ( segmentIndex 
== -1 ) 
1318                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"); 
1319                                         if ( !libraryOrdinalSet 
) 
1320                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL*"); 
1321                     handler(context
, this, address
, type
, symbolName
, symboFlags
, addend
, libraryOrdinal
, 
1322                                      &extraBindData
, "", &last
, false); 
1323                                         address 
+= read_uleb128(p
, end
) + sizeof(intptr_t); 
1325                                 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
: 
1326                                         if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
1327                                                 throwBadBindingAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
1328                                         if ( symbolName  
== NULL 
) 
1329                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM"); 
1330                                         if ( segmentIndex 
== -1 ) 
1331                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"); 
1332                                         if ( !libraryOrdinalSet 
) 
1333                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL*"); 
1334                     handler(context
, this, address
, type
, symbolName
, symboFlags
, addend
, libraryOrdinal
, 
1335                                      &extraBindData
, "", &last
, false); 
1336                                         address 
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t); 
1338                                 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
: 
1339                                         if ( symbolName  
== NULL 
) 
1340                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM"); 
1341                                         if ( segmentIndex 
== -1 ) 
1342                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"); 
1343                                         count 
= read_uleb128(p
, end
); 
1344                                         if ( !libraryOrdinalSet 
) 
1345                                                 dyld::throwf("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL*"); 
1346                                         skip 
= read_uleb128(p
, end
); 
1347                                         for (uint32_t i
=0; i 
< count
; ++i
) { 
1348                                                 if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
1349                                                         throwBadBindingAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
1350                         handler(context
, this, address
, type
, symbolName
, symboFlags
, addend
, libraryOrdinal
, 
1351                                          &extraBindData
, "", &last
, false); 
1352                                                 address 
+= skip 
+ sizeof(intptr_t); 
1355                 case BIND_OPCODE_THREADED
: 
1356                     if (sizeof(intptr_t) != 8) { 
1357                         dyld::throwf("BIND_OPCODE_THREADED require 64-bit"); 
1360                     // Note the immediate is a sub opcode 
1361                     switch (immediate
) { 
1362                         case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
: 
1363                             count 
= read_uleb128(p
, end
); 
1364                             ordinalTable
.clear(); 
1365                             // FIXME: ld64 wrote the wrong value here and we need to offset by 1 for now. 
1366                             ordinalTable
.reserve(count 
+ 1); 
1367                             useThreadedRebaseBind 
= true; 
1369                         case BIND_SUBOPCODE_THREADED_APPLY
: { 
1372                                 address 
= segmentStartAddress 
+ segOffset
; 
1373                                 uint64_t value 
= *(uint64_t*)address
; 
1376                                 bool isRebase 
= (value 
& (1ULL << 62)) == 0; 
1379                                         // Call the bind handler which knows about our bind type being set to rebase 
1380                                         handler(context
, this, address
, BIND_TYPE_THREADED_REBASE
, nullptr, 0, 0, 0, 
1381                                                          nullptr, "", &last
, false); 
1384                                     // the ordinal is bits [0..15] 
1385                                     uint16_t ordinal 
= value 
& 0xFFFF; 
1386                                     if (ordinal 
>= ordinalTable
.count()) { 
1387                                         dyld::throwf("bind ordinal (%d) is out of range (max=%lu) for disk pointer 0x%16llX at segIndex=%d, segOffset=0x%0lX in %s", 
1388                                                     ordinal
, ordinalTable
.count(),value
, segmentIndex
, segOffset
, this->getPath()); 
1391                                     std::tie(symbolName
, addend
, libraryOrdinal
, symboFlags
, type
) = ordinalTable
[ordinal
].pack(); 
1392                                     if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
1393                                         throwBadBindingAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
1395                                         handler(context
, this, address
, BIND_TYPE_THREADED_BIND
, 
1396                                                          symbolName
, symboFlags
, addend
, libraryOrdinal
, 
1397                                                          nullptr, "", &last
, false); 
1401                                 // The delta is bits [51..61] 
1402                                 // And bit 62 is to tell us if we are a rebase (0) or bind (1) 
1403                                 value 
&= ~(1ULL << 62); 
1404                                 delta 
= ( value 
& 0x3FF8000000000000 ) >> 51; 
1405                                 segOffset 
+= delta 
* sizeof(intptr_t); 
1406                             } while ( delta 
!= 0 ); 
1411                             dyld::throwf("bad threaded bind subopcode 0x%02X", *p
); 
1415                                         dyld::throwf("bad bind opcode %d in bind info", *p
); 
1419         catch (const char* msg
) { 
1420                 const char* newMsg 
= dyld::mkstringf("%s in %s", msg
, this->getPath()); 
1426 void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext
& context
, bind_handler handler
) 
1429                 uint8_t type 
= BIND_TYPE_POINTER
; 
1430                 int segmentIndex 
= -1; 
1431                 uintptr_t address 
= segActualLoadAddress(0); 
1432                 uintptr_t segmentStartAddress 
= segActualLoadAddress(0); 
1433                 uintptr_t segmentEndAddress 
= segActualEndAddress(0); 
1434                 uintptr_t segOffset
; 
1435                 const char* symbolName 
= NULL
; 
1436                 uint8_t symboFlags 
= 0; 
1437                 long libraryOrdinal 
= 0; 
1438                 intptr_t addend 
= 0; 
1439                 const uint8_t* const start 
= fLinkEditBase 
+ fDyldInfo
->lazy_bind_off
; 
1440                 const uint8_t* const end 
= &start
[fDyldInfo
->lazy_bind_size
]; 
1441                 const uint8_t* p 
= start
; 
1443                 while ( !done 
&& (p 
< end
) ) { 
1444                         uint8_t immediate 
= *p 
& BIND_IMMEDIATE_MASK
; 
1445                         uint8_t opcode 
= *p 
& BIND_OPCODE_MASK
; 
1448                                 case BIND_OPCODE_DONE
: 
1449                                         // there is BIND_OPCODE_DONE at end of each lazy bind, don't stop until end of whole sequence 
1451                                 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
: 
1452                                         libraryOrdinal 
= immediate
; 
1454                                 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
: 
1455                                         libraryOrdinal 
= read_uleb128(p
, end
); 
1457                                 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
: 
1458                                         // the special ordinals are negative numbers 
1459                                         if ( immediate 
== 0 ) 
1462                                                 int8_t signExtended 
= BIND_OPCODE_MASK 
| immediate
; 
1463                                                 libraryOrdinal 
= signExtended
; 
1466                                 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
: 
1467                                         symbolName 
= (char*)p
; 
1468                                         symboFlags 
= immediate
; 
1473                                 case BIND_OPCODE_SET_TYPE_IMM
: 
1476                                 case BIND_OPCODE_SET_ADDEND_SLEB
: 
1477                                         addend 
= read_sleb128(p
, end
); 
1479                                 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
: 
1480                                         segmentIndex 
= immediate
; 
1481                                         if ( (segmentIndex 
>= fSegmentsCount
) || (segmentIndex 
< 0) ) 
1482                                                 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is out of range (0..%d)", 
1483                                                                 segmentIndex
, fSegmentsCount
-1); 
1484                                         if ( !segWriteable(segmentIndex
) ) 
1485                                                 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is not writable", segmentIndex
); 
1486                                         segOffset 
= read_uleb128(p
, end
); 
1487                                         if ( segOffset 
> segSize(segmentIndex
) ) 
1488                                                 dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has offset 0x%08lX beyond segment size (0x%08lX)", segOffset
, segSize(segmentIndex
)); 
1489                                         segmentStartAddress 
= segActualLoadAddress(segmentIndex
); 
1490                                         segmentEndAddress 
= segActualEndAddress(segmentIndex
); 
1491                                         address 
= segmentStartAddress 
+ segOffset
; 
1493                                 case BIND_OPCODE_ADD_ADDR_ULEB
: 
1494                                         address 
+= read_uleb128(p
, end
); 
1496                                 case BIND_OPCODE_DO_BIND
: 
1497                                         if ( segmentIndex 
== -1 ) 
1498                                                 dyld::throwf("BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"); 
1499                                         if ( (address 
< segmentStartAddress
) || (address 
>= segmentEndAddress
) ) 
1500                                                 throwBadBindingAddress(address
, segmentEndAddress
, segmentIndex
, start
, end
, p
); 
1501                                         if ( symbolName  
== NULL 
) 
1502                                                 dyld::throwf("BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM"); 
1503                     handler(context
, this, address
, type
, symbolName
, symboFlags
, addend
, libraryOrdinal
, 
1504                                      NULL
, "forced lazy ", NULL
, false); 
1505                                         address 
+= sizeof(intptr_t); 
1507                                 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
: 
1508                                 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
: 
1509                                 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
: 
1511                                         dyld::throwf("bad lazy bind opcode %d", *p
); 
1516         catch (const char* msg
) { 
1517                 const char* newMsg 
= dyld::mkstringf("%s in %s", msg
, this->getPath()); 
1523 // A program built targeting 10.5 will have hybrid stubs.  When used with weak symbols 
1524 // the classic lazy loader is used even when running on 10.6 
1525 uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
) 
1527         // only works with compressed LINKEDIT if classic symbol table is also present 
1528         const macho_nlist
* symbolTable 
= NULL
; 
1529         const char* symbolTableStrings 
= NULL
; 
1530         const dysymtab_command
* dynSymbolTable 
= NULL
; 
1531         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1532         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1533         const struct load_command
* cmd 
= cmds
; 
1534         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1538                                         const struct symtab_command
* symtab 
= (struct symtab_command
*)cmd
; 
1539                                         symbolTableStrings 
= (const char*)&fLinkEditBase
[symtab
->stroff
]; 
1540                                         symbolTable 
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]); 
1544                                 dynSymbolTable 
= (struct dysymtab_command
*)cmd
; 
1547                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1549         // no symbol table => no lookup by address 
1550         if ( (symbolTable 
== NULL
) || (dynSymbolTable 
== NULL
) ) 
1551                 dyld::throwf("classic lazy binding used with compressed LINKEDIT at %p in image %s", lazyPointer
, this->getPath()); 
1553         // scan for all lazy-pointer sections 
1554         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1555         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[dynSymbolTable
->indirectsymoff
]; 
1557         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1559                         case LC_SEGMENT_COMMAND
: 
1561                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1562                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1563                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1564                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1565                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1566                                                 uint32_t symbolIndex 
= INDIRECT_SYMBOL_LOCAL
; 
1567                                                 if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
1568                                                         const size_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
1569                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1570                                                         if ( (lazyPointer 
>= symbolPointers
) && (lazyPointer 
< &symbolPointers
[pointerCount
]) ) { 
1571                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1572                                                                 const size_t lazyIndex 
= lazyPointer 
- symbolPointers
; 
1573                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ lazyIndex
]; 
1576                                                 if ( (symbolIndex 
!= INDIRECT_SYMBOL_ABS
) && (symbolIndex 
!= INDIRECT_SYMBOL_LOCAL
) ) { 
1577                                                         const macho_nlist
* symbol 
= &symbolTable
[symbolIndex
]; 
1578                                                         const char* symbolName 
= &symbolTableStrings
[symbol
->n_un
.n_strx
]; 
1579                                                         int libraryOrdinal 
= GET_LIBRARY_ORDINAL(symbol
->n_desc
); 
1580                                                         if ( !twoLevel 
|| context
.bindFlat 
)  
1581                                                                 libraryOrdinal 
= BIND_SPECIAL_DYLIB_FLAT_LOOKUP
; 
1582                                                         uintptr_t ptrToBind 
= (uintptr_t)lazyPointer
; 
1583                             uintptr_t symbolAddr 
= bindAt(context
, this, ptrToBind
, BIND_TYPE_POINTER
, symbolName
, 0, 0, libraryOrdinal
, 
1584                                                           NULL
, "lazy ", NULL
); 
1585                                                         ++fgTotalLazyBindFixups
; 
1592                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1594         dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer
, this->getPath()); 
1599 uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset
, const LinkContext
& context
, 
1600                                                                                                                         void (*lock
)(), void (*unlock
)()) 
1602         // <rdar://problem/8663923> race condition with flat-namespace lazy binding 
1603         if ( this->usesTwoLevelNameSpace() ) { 
1604                 // two-level namespace lookup does not require lock because dependents can't be unloaded before this image 
1607                 // acquire dyld global lock 
1612         const uint8_t* const start 
= fLinkEditBase 
+ fDyldInfo
->lazy_bind_off
; 
1613         const uint8_t* const end 
= &start
[fDyldInfo
->lazy_bind_size
]; 
1615         uintptr_t segOffset
; 
1617         const char* symbolName
; 
1621                 if ( ! getLazyBindingInfo(lazyBindingInfoOffset
, start
, end
, &segIndex
, &segOffset
, &libraryOrdinal
, &symbolName
, &doneAfterBind
) ) 
1622                         dyld::throwf("bad lazy bind info"); 
1624                 if ( segIndex 
>= fSegmentsCount 
) 
1625                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",  
1626                                                         segIndex
, fSegmentsCount
-1); 
1627                 if ( segOffset 
> segSize(segIndex
) ) 
1628                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has offset 0x%08lX beyond segment size (0x%08lX)", segOffset
, segSize(segIndex
)); 
1629                 uintptr_t address 
= segActualLoadAddress(segIndex
) + segOffset
; 
1630         result 
= bindAt(context
, this, address
, BIND_TYPE_POINTER
, symbolName
, 0, 0, libraryOrdinal
, 
1631                               NULL
, "lazy ", NULL
, true); 
1632                 // <rdar://problem/24140465> Some old apps had multiple lazy symbols bound at once 
1633         } while (!doneAfterBind 
&& !context
.strictMachORequired
); 
1635         if ( !this->usesTwoLevelNameSpace() ) { 
1636                 // release dyld global lock 
1637                 if ( unlock 
!= NULL 
) 
1643 void ImageLoaderMachOCompressed::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
, unsigned) 
1646         it
.symbolName 
= " "; 
1647         it
.loadOrder 
= loadOrder
; 
1648         it
.weakSymbol 
= false; 
1649         it
.symbolMatches 
= false; 
1652         it
.endIndex 
= (this->fDyldInfo 
? this->fDyldInfo
->weak_bind_size 
: 0); 
1659 bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator
& it
) 
1664         if ( (this->fDyldInfo 
== nullptr) || (this->fDyldInfo
->weak_bind_size 
== 0) ) { 
1665                 /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info 
1667                 it
.symbolName 
= "~~~"; 
1670         const uint8_t* start 
= fLinkEditBase 
+ fDyldInfo
->weak_bind_off
; 
1671         const uint8_t* p 
= start 
+ it
.curIndex
; 
1672         const uint8_t* end 
= fLinkEditBase 
+ fDyldInfo
->weak_bind_off 
+ this->fDyldInfo
->weak_bind_size
; 
1675         uintptr_t segOffset
; 
1677                 uint8_t immediate 
= *p 
& BIND_IMMEDIATE_MASK
; 
1678                 uint8_t opcode 
= *p 
& BIND_OPCODE_MASK
; 
1681                         case BIND_OPCODE_DONE
: 
1683                                 it
.curIndex 
= p 
- start
; 
1684                                 it
.symbolName 
= "~~~"; // sorts to end 
1686                         case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
: 
1687                                 it
.symbolName 
= (char*)p
; 
1688                                 it
.weakSymbol 
= ((immediate 
& BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION
) == 0); 
1689                                 it
.symbolMatches 
= false; 
1693                                 it
.curIndex 
= p 
- start
; 
1695                         case BIND_OPCODE_SET_TYPE_IMM
: 
1696                                 it
.type 
= immediate
; 
1698                         case BIND_OPCODE_SET_ADDEND_SLEB
: 
1699                                 it
.addend 
= read_sleb128(p
, end
); 
1701                         case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
: 
1702                                 if ( immediate 
>= fSegmentsCount 
) 
1703                                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)", 
1704                                                         immediate
, fSegmentsCount
-1); 
1706                                 // <rdar://problem/23138428> iOS app compatibility 
1707                                 if ( !segWriteable(immediate
) && it
.image
->isPositionIndependentExecutable() ) 
1708                 #elif TEXT_RELOC_SUPPORT 
1709                                 // <rdar://problem/23479396&23590867> i386 OS X app compatibility 
1710                                 if ( !segWriteable(immediate
) && !segHasRebaseFixUps(immediate
) && !segHasBindFixUps(immediate
) 
1711                                         && (!it
.image
->isExecutable() || it
.image
->isPositionIndependentExecutable()) ) 
1713                                 if ( !segWriteable(immediate
) ) 
1715                                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB targets segment %s which is not writable", segName(immediate
)); 
1716                                 segOffset 
= read_uleb128(p
, end
); 
1717                                 if ( segOffset 
> segSize(immediate
) ) 
1718                                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has offset 0x%08lX beyond segment size (0x%08lX)", segOffset
, segSize(immediate
)); 
1719                                 it
.address 
= segActualLoadAddress(immediate
) + segOffset
; 
1721                         case BIND_OPCODE_ADD_ADDR_ULEB
: 
1722                                 it
.address 
+= read_uleb128(p
, end
); 
1724                         case BIND_OPCODE_DO_BIND
: 
1725                                 it
.address 
+= sizeof(intptr_t); 
1727                         case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
: 
1728                                 it
.address 
+= read_uleb128(p
, end
) + sizeof(intptr_t); 
1730                         case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
: 
1731                                 it
.address 
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t); 
1733                         case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
: 
1734                                 count 
= read_uleb128(p
, end
); 
1735                                 skip 
= read_uleb128(p
, end
); 
1736                                 for (uint32_t i
=0; i 
< count
; ++i
) { 
1737                                         it
.address 
+= skip 
+ sizeof(intptr_t); 
1741                                 dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p
, (int)(p
-start
), this->getPath()); 
1744         /// hmmm, BIND_OPCODE_DONE is missing... 
1746         it
.symbolName 
= "~~~"; 
1747         //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath()); 
1751 uintptr_t ImageLoaderMachOCompressed::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
) 
1753         //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath()); 
1754         const ImageLoader
* foundIn 
= NULL
; 
1755         const ImageLoader::Symbol
* sym 
= this->findShallowExportedSymbol(it
.symbolName
, &foundIn
); 
1756         if ( sym 
!= NULL 
) { 
1757                 //dyld::log("sym=%p, foundIn=%p\n", sym, foundIn); 
1758                 return foundIn
->getExportedSymbolAddress(sym
, context
, this); 
1764 void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, unsigned targetIndex
, const LinkContext
& context
) 
1766         // <rdar://problem/6570879> weak binding done too early with inserted libraries 
1767         if ( this->getState() < dyld_image_state_bound  
) 
1770         if ( fDyldInfo 
== nullptr ) 
1773         const uint8_t* start 
= fLinkEditBase 
+ fDyldInfo
->weak_bind_off
; 
1774         const uint8_t* p 
= start 
+ it
.curIndex
; 
1775         const uint8_t* end 
= fLinkEditBase 
+ fDyldInfo
->weak_bind_off 
+ this->fDyldInfo
->weak_bind_size
; 
1777         uint8_t type 
= it
.type
; 
1778         uintptr_t address 
= it
.address
; 
1779         const char* symbolName 
= it
.symbolName
; 
1780         intptr_t addend 
= it
.addend
; 
1783         uintptr_t segOffset
; 
1785         bool boundSomething 
= false; 
1786         while ( !done 
&& (p 
< end
) ) { 
1787                 uint8_t immediate 
= *p 
& BIND_IMMEDIATE_MASK
; 
1788                 uint8_t opcode 
= *p 
& BIND_OPCODE_MASK
; 
1791                         case BIND_OPCODE_DONE
: 
1794                         case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
: 
1797                         case BIND_OPCODE_SET_TYPE_IMM
: 
1800                         case BIND_OPCODE_SET_ADDEND_SLEB
: 
1801                                 addend 
= read_sleb128(p
, end
); 
1803                         case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
: 
1804                                 if ( immediate 
>= fSegmentsCount 
) 
1805                                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)", 
1806                                                         immediate
, fSegmentsCount
-1); 
1808                                 // <rdar://problem/23138428> iOS app compatibility 
1809                                 if ( !segWriteable(immediate
) && it
.image
->isPositionIndependentExecutable() ) 
1810                 #elif TEXT_RELOC_SUPPORT 
1811                                 // <rdar://problem/23479396&23590867> i386 OS X app compatibility 
1812                                 if ( !segWriteable(immediate
) && !segHasRebaseFixUps(immediate
) && !segHasBindFixUps(immediate
) 
1813                                         && (!it
.image
->isExecutable() || it
.image
->isPositionIndependentExecutable()) ) 
1815                                 if ( !segWriteable(immediate
) ) 
1817                                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB targets segment %s which is not writable", segName(immediate
)); 
1818                                 segOffset 
= read_uleb128(p
, end
); 
1819                                 if ( segOffset 
> segSize(immediate
) ) 
1820                                         dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has offset 0x%08lX beyond segment size (0x%08lX)", segOffset
, segSize(immediate
)); 
1821                                 address 
= segActualLoadAddress(immediate
) + segOffset
; 
1823                         case BIND_OPCODE_ADD_ADDR_ULEB
: 
1824                                 address 
+= read_uleb128(p
, end
); 
1826                         case BIND_OPCODE_DO_BIND
: 
1827                                 bindLocation(context
, this->imageBaseAddress(), address
, value
, type
, symbolName
, addend
, this->getPath(), targetImage 
? targetImage
->getPath() : NULL
, "weak ", NULL
, fSlide
); 
1828                                 boundSomething 
= true; 
1829                                 address 
+= sizeof(intptr_t); 
1831                         case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
: 
1832                                 bindLocation(context
, this->imageBaseAddress(), address
, value
, type
, symbolName
, addend
, this->getPath(), targetImage 
? targetImage
->getPath() : NULL
, "weak ", NULL
, fSlide
); 
1833                                 boundSomething 
= true; 
1834                                 address 
+= read_uleb128(p
, end
) + sizeof(intptr_t); 
1836                         case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
: 
1837                                 bindLocation(context
, this->imageBaseAddress(), address
, value
, type
, symbolName
, addend
, this->getPath(), targetImage 
? targetImage
->getPath() : NULL
, "weak ", NULL
, fSlide
); 
1838                                 boundSomething 
= true; 
1839                                 address 
+= immediate
*sizeof(intptr_t) + sizeof(intptr_t); 
1841                         case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
: 
1842                                 count 
= read_uleb128(p
, end
); 
1843                                 skip 
= read_uleb128(p
, end
); 
1844                                 for (uint32_t i
=0; i 
< count
; ++i
) { 
1845                                         bindLocation(context
, this->imageBaseAddress(), address
, value
, type
, symbolName
, addend
, this->getPath(), targetImage 
? targetImage
->getPath() : NULL
, "weak ", NULL
, fSlide
); 
1846                                         boundSomething 
= true; 
1847                                         address 
+= skip 
+ sizeof(intptr_t); 
1851                                 dyld::throwf("bad bind opcode %d in weak binding info", *p
); 
1854         // C++ weak coalescing cannot be tracked by reference counting.  Error on side of never unloading. 
1855         if ( boundSomething 
&& (targetImage 
!= this) ) 
1856                 context
.addDynamicReference(this, targetImage
); 
1859 uintptr_t ImageLoaderMachOCompressed::interposeAt(const LinkContext
& context
, ImageLoaderMachOCompressed
* image
, 
1860                                                                                                   uintptr_t addr
, uint8_t type
, const char*, 
1861                                                   uint8_t, intptr_t, long, 
1862                                                   ExtraBindData 
*extraBindData
, 
1863                                                   const char*, LastLookup
*, bool runResolver
) 
1865         if ( type 
== BIND_TYPE_POINTER 
) { 
1866                 uintptr_t* fixupLocation 
= (uintptr_t*)addr
; 
1867                 uintptr_t curValue 
= *fixupLocation
; 
1868                 uintptr_t newValue 
= interposedAddress(context
, curValue
, image
); 
1869                 if ( newValue 
!= curValue
) { 
1870                         *fixupLocation 
= newValue
; 
1876 void ImageLoaderMachOCompressed::doInterpose(const LinkContext
& context
) 
1878         if ( context
.verboseInterposing 
) 
1879                 dyld::log("dyld: interposing %lu tuples onto image: %s\n", fgInterposingTuples
.size(), this->getPath()); 
1881         const dyld3::MachOAnalyzer
* ma 
= (dyld3::MachOAnalyzer
*)fMachOData
; 
1882         if ( !ma
->hasChainedFixups() && (fDyldInfo 
!= nullptr) ) { 
1883                 // Note: all binds that happen as part of normal loading and fixups will have interposing applied. 
1884                 // There is only two cases where we need to parse bind opcodes and apply interposing: 
1886                 // 1) Lazy pointers are either not bound yet, or in dyld cache they are prebound (to uninterposed target)  
1887                 eachLazyBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
1888                                                                 uintptr_t addr
, uint8_t type
, const char* symbolName
, 
1889                                                                 uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
1890                                                                 ExtraBindData 
*extraBindData
, 
1891                                                                 const char* msg
, LastLookup
* last
, bool runResolver
) { 
1892                         return ImageLoaderMachOCompressed::interposeAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
1893                                                                                                                    addend
, libraryOrdinal
, extraBindData
, 
1894                                                                                                                    msg
, last
, runResolver
); 
1897                 // 2) non-lazy pointers in the dyld cache need to be interposed 
1898                 if ( ma
->inDyldCache() ) { 
1899                         eachBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
1900                                                                 uintptr_t addr
, uint8_t type
, const char* symbolName
, 
1901                                                                 uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
1902                                                                 ExtraBindData 
*extraBindData
, 
1903                                                                 const char* msg
, LastLookup
* last
, bool runResolver
) { 
1904                                 return ImageLoaderMachOCompressed::interposeAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
1905                                                                                                                            addend
, libraryOrdinal
, extraBindData
, 
1906                                                                                                                            msg
, last
, runResolver
); 
1914 uintptr_t ImageLoaderMachOCompressed::dynamicInterposeAt(const LinkContext
& context
, ImageLoaderMachOCompressed
* image
, 
1915                                                                                                                  uintptr_t addr
, uint8_t type
, const char* symbolName
, 
1916                                                          uint8_t, intptr_t, long, 
1917                                                          ExtraBindData 
*extraBindData
, 
1918                                                          const char*, LastLookup
*, bool runResolver
) 
1920         if ( type 
== BIND_TYPE_POINTER 
) { 
1921                 uintptr_t* fixupLocation 
= (uintptr_t*)addr
; 
1922                 uintptr_t value 
= *fixupLocation
; 
1923                 // don't apply interposing to table entries. 
1924                 if ( (context
.dynamicInterposeArray 
<= (void*)addr
) && ((void*)addr 
< &context
.dynamicInterposeArray
[context
.dynamicInterposeCount
]) ) 
1926                 for(size_t i
=0; i 
< context
.dynamicInterposeCount
; ++i
) { 
1927                         if ( value 
== (uintptr_t)context
.dynamicInterposeArray
[i
].replacee 
) { 
1928                                 if ( context
.verboseInterposing 
) { 
1929                                         dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",  
1930                                                 fixupLocation
, context
.dynamicInterposeArray
[i
].replacee
, context
.dynamicInterposeArray
[i
].replacement
, image
->getPath()); 
1932                                 *fixupLocation 
= (uintptr_t)context
.dynamicInterposeArray
[i
].replacement
; 
1939 void ImageLoaderMachOCompressed::dynamicInterpose(const LinkContext
& context
) 
1941         if ( context
.verboseInterposing 
) 
1942                 dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context
.dynamicInterposeCount
, this->getPath()); 
1944         // update already bound references to symbols 
1945         eachBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
1946                                                 uintptr_t addr
, uint8_t type
, const char* symbolName
, 
1947                                                 uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
1948                                                 ExtraBindData 
*extraBindData
, 
1949                                                 const char* msg
, LastLookup
* last
, bool runResolver
) { 
1950                 return ImageLoaderMachOCompressed::dynamicInterposeAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
1951                                                                                                                           addend
, libraryOrdinal
, extraBindData
, 
1952                                                                                                                           msg
, last
, runResolver
); 
1954         eachLazyBind(context
, ^(const LinkContext
& ctx
, ImageLoaderMachOCompressed
* image
, 
1955                                                         uintptr_t addr
, uint8_t type
, const char* symbolName
, 
1956                                                         uint8_t symbolFlags
, intptr_t addend
, long libraryOrdinal
, 
1957                                                         ExtraBindData 
*extraBindData
, 
1958                                                         const char* msg
, LastLookup
* last
, bool runResolver
) { 
1959                 return ImageLoaderMachOCompressed::dynamicInterposeAt(ctx
, image
, addr
, type
, symbolName
, symbolFlags
, 
1960                                                                                                                           addend
, libraryOrdinal
, extraBindData
, 
1961                                                                                                                           msg
, last
, runResolver
); 
1965 const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr
, const void** closestAddr
) const 
1967         return ImageLoaderMachO::findClosestSymbol((mach_header
*)fMachOData
, addr
, closestAddr
); 
1971 #if PREBOUND_IMAGE_SUPPORT 
1972 void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext
& context
) 
1974         // no way to back off a prebound compress image 
1979 #if __arm__ || __x86_64__ 
1980 void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub
, void** originalLazyPointerAddr
, const LinkContext
& context
) 
1983         uint32_t* instructions 
= (uint32_t*)stub
; 
1984     // sanity check this is a stub we understand 
1985         if ( (instructions
[0] != 0xe59fc004) || (instructions
[1] != 0xe08fc00c) || (instructions
[2] != 0xe59cf000) ) 
1988         void** lazyPointerAddr 
= (void**)(instructions
[3] + (stub 
+ 12)); 
1991     // sanity check this is a stub we understand 
1992         if ( (stub
[0] != 0xFF) || (stub
[1] != 0x25) ) 
1994     int32_t ripOffset 
= *((int32_t*)(&stub
[2])); 
1995         void** lazyPointerAddr 
= (void**)(ripOffset 
+ stub 
+ 6); 
1998    // if stub does not use original lazy pointer (meaning it was optimized by update_dyld_shared_cache) 
1999     if ( lazyPointerAddr 
!= originalLazyPointerAddr 
) { 
2000                 // <rdar://problem/12928448> only de-optimization lazy pointers if they are part of shared cache not loaded (because overridden) 
2001                 const ImageLoader
* lazyPointerImage 
= context
.findImageContainingAddress(lazyPointerAddr
); 
2002                 if ( lazyPointerImage 
!= NULL 
) 
2005         // copy newly re-bound lazy pointer value to shared lazy pointer 
2006         *lazyPointerAddr 
= *originalLazyPointerAddr
; 
2008                 if ( context
.verboseBind 
) 
2009                         dyld::log("dyld: alter bind: %s: *0x%08lX = 0x%08lX \n", 
2010                                           this->getShortName(), (long)lazyPointerAddr
, (long)*originalLazyPointerAddr
); 
2016 // <rdar://problem/8890875> overriding shared cache dylibs with resolvers fails 
2017 void ImageLoaderMachOCompressed::updateOptimizedLazyPointers(const LinkContext
& context
) 
2019 #if __arm__ || __x86_64__ 
2020         // find stubs and indirect symbol table 
2021         const struct macho_section
* stubsSection 
= NULL
; 
2022         const dysymtab_command
* dynSymbolTable 
= NULL
; 
2023         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
2024         const uint32_t cmd_count 
= mh
->ncmds
; 
2025         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2026         const struct load_command
* cmd 
= cmds
; 
2027         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2028                 if (cmd
->cmd 
== LC_SEGMENT_COMMAND
) { 
2029                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2030                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2031                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2032                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2033                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2034                                 if ( type 
== S_SYMBOL_STUBS 
)  
2035                                         stubsSection 
= sect
; 
2038                 else if ( cmd
->cmd 
== LC_DYSYMTAB 
) { 
2039                         dynSymbolTable 
= (struct dysymtab_command
*)cmd
; 
2041                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2043         if ( dynSymbolTable 
== NULL 
) 
2045         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[dynSymbolTable
->indirectsymoff
]; 
2046         if ( stubsSection 
== NULL 
) 
2048         const uint32_t stubsSize 
= stubsSection
->reserved2
; 
2049         const uint32_t stubsCount 
= (uint32_t)(stubsSection
->size 
/ stubsSize
); 
2050         const uint32_t stubsIndirectTableOffset 
= stubsSection
->reserved1
; 
2051         if ( (stubsIndirectTableOffset
+stubsCount
) > dynSymbolTable
->nindirectsyms 
) 
2053         uint8_t* const stubsAddr 
= (uint8_t*)(stubsSection
->addr 
+ this->fSlide
); 
2055         // for each lazy pointer section 
2057         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2058                 if (cmd
->cmd 
== LC_SEGMENT_COMMAND
) { 
2059                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2060                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2061                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2062                         for (const struct macho_section
* lazyPointerSection
=sectionsStart
; lazyPointerSection 
< sectionsEnd
; ++lazyPointerSection
) { 
2063                                 const uint8_t type 
= lazyPointerSection
->flags 
& SECTION_TYPE
; 
2064                                 if ( type 
!= S_LAZY_SYMBOL_POINTERS 
) 
2066                                 const uint32_t lazyPointersCount 
= (uint32_t)(lazyPointerSection
->size 
/ sizeof(void*)); 
2067                                 const uint32_t lazyPointersIndirectTableOffset 
= lazyPointerSection
->reserved1
; 
2068                                 if ( (lazyPointersIndirectTableOffset
+lazyPointersCount
) > dynSymbolTable
->nindirectsyms 
) 
2070                                 void** const lazyPointersAddr 
= (void**)(lazyPointerSection
->addr 
+ this->fSlide
); 
2071                                 // for each lazy pointer 
2072                                 for(uint32_t lpIndex
=0; lpIndex 
< lazyPointersCount
; ++lpIndex
) { 
2073                                         const uint32_t lpSymbolIndex 
= indirectTable
[lazyPointersIndirectTableOffset
+lpIndex
]; 
2074                                         // find matching stub and validate it uses this lazy pointer 
2075                                         for(uint32_t stubIndex
=0; stubIndex 
< stubsCount
; ++stubIndex
) { 
2076                                                 if ( indirectTable
[stubsIndirectTableOffset
+stubIndex
] == lpSymbolIndex 
) { 
2077                                                         this->updateAlternateLazyPointer(stubsAddr
+stubIndex
*stubsSize
, &lazyPointersAddr
[lpIndex
], context
); 
2085                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2092 void ImageLoaderMachOCompressed::registerEncryption(const encryption_info_command
* encryptCmd
, const LinkContext
& context
) 
2094 #if (__arm__ || __arm64__) && !TARGET_OS_SIMULATOR 
2095         if ( encryptCmd 
== NULL 
) 
2097         // fMachOData not set up yet, need to manually find mach_header 
2098         const mach_header
* mh 
= NULL
; 
2099         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
2100                 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) { 
2101                         mh 
= (mach_header
*)segActualLoadAddress(i
); 
2102                         void* start 
= ((uint8_t*)mh
) + encryptCmd
->cryptoff
; 
2103                         size_t len 
= encryptCmd
->cryptsize
; 
2104                         uint32_t cputype 
= mh
->cputype
; 
2105                         uint32_t cpusubtype 
= mh
->cpusubtype
; 
2106                         uint32_t cryptid 
= encryptCmd
->cryptid
; 
2107                         if (context
.verboseMapping
) { 
2108                                  dyld::log("                      0x%08lX->0x%08lX configured for FairPlay decryption\n", (long)start
, (long)start
+len
); 
2110                         int result 
= mremap_encrypted(start
, len
, cryptid
, cputype
, cpusubtype
); 
2111                         if ( result 
!= 0 ) { 
2112                                 dyld::throwf("mremap_encrypted() => %d, errno=%d for %s\n", result
, errno
, this->getPath());