1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2010 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@ 
  25 // work around until conformance work is complete rdar://problem/4508801 
  34 #include <sys/types.h> 
  35 #include <sys/fcntl.h> 
  38 #include <mach/mach.h> 
  39 #include <mach/thread_status.h> 
  40 #include <mach-o/loader.h>  
  41 #include <mach-o/reloc.h>  
  42 #include <mach-o/nlist.h>  
  43 #include <sys/sysctl.h> 
  44 #include <libkern/OSAtomic.h> 
  45 #include <libkern/OSCacheControl.h> 
  48         #include <mach-o/x86_64/reloc.h> 
  51         #include <mach-o/arm/reloc.h> 
  54 #include "ImageLoaderMachOClassic.h" 
  55 #include "mach-o/dyld_images.h" 
  58 extern "C" void fast_stub_binding_helper_interface(); 
  62         #define POINTER_RELOC X86_64_RELOC_UNSIGNED 
  64         #define POINTER_RELOC GENERIC_RELOC_VANILLA 
  68 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables 
  71         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
  72         #define LC_ROUTINES_COMMAND             LC_ROUTINES_64 
  73         struct macho_segment_command    
: public segment_command_64  
{}; 
  74         struct macho_section                    
: public section_64  
{};         
  75         struct macho_routines_command   
: public routines_command_64  
{};        
  78         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
  79         #define LC_ROUTINES_COMMAND             LC_ROUTINES 
  80         struct macho_segment_command    
: public segment_command 
{}; 
  81         struct macho_section                    
: public section  
{};    
  82         struct macho_routines_command   
: public routines_command  
{};   
  88 // create image for main executable 
  89 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
,  
  90                                                                                                                                                 unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
  92         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart(mh
, path
, segCount
, libCount
); 
  94         // set slide for PIE programs 
  95         image
->setSlide(slide
); 
  97         // for PIE record end of program, to know where to start loading dylibs 
  99                 fgNextPIEDylibAddress 
= (uintptr_t)image
->getEnd(); 
 101         image
->instantiateFinish(context
); 
 102         image
->setMapped(context
); 
 105         // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding 
 106         if ( image
->fReadOnlyImportSegment 
) { 
 107                 for(unsigned int i
=0; i 
< image
->fSegmentsCount
; ++i
) { 
 108                         if ( image
->segIsReadOnlyImport(i
) ) 
 109                                 image
->segMakeWritable(i
, context
); 
 114         if ( context
.verboseMapping 
) { 
 115                 dyld::log("dyld: Main executable mapped %s\n", path
); 
 116                 for(unsigned int i
=0, e
=image
->segmentCount(); i 
< e
; ++i
) { 
 117                         const char* name 
= image
->segName(i
); 
 118                         if ( (strcmp(name
, "__PAGEZERO") == 0) || (strcmp(name
, "__UNIXSTACK") == 0)  ) 
 119                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segPreferredLoadAddress(i
), image
->segPreferredLoadAddress(i
)+image
->segSize(i
)); 
 121                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
)); 
 128 // create image by mapping in a mach-o file 
 129 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateFromFile(const char* path
, int fd
, const uint8_t* fileData
,  
 130                                                                                                                         uint64_t offsetInFat
, uint64_t lenInFat
, const struct stat
& info
,  
 131                                                                                                                         unsigned int segCount
, unsigned int libCount
,  
 132                                                                                                                         const struct linkedit_data_command
* codeSigCmd
, const LinkContext
& context
) 
 134         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart((macho_header
*)fileData
, path
, segCount
, libCount
); 
 136                 // record info about file   
 137                 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
); 
 139                 // if this image is code signed, let kernel validate signature before mapping any pages from image 
 140                 image
->loadCodeSignature(codeSigCmd
, fd
, offsetInFat
, context
); 
 143                 image
->mapSegmentsClassic(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
); 
 146                 image
->instantiateFinish(context
); 
 148                 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path 
 149                 const char* installName 
= image
->getInstallPath(); 
 150                 if ( (installName 
!= NULL
) && (strcmp(installName
, path
) == 0) && (path
[0] == '/') ) 
 151                         image
->setPathUnowned(installName
); 
 152                 else if ( (path
[0] != '/') || (strstr(path
, "../") != NULL
) ) { 
 153                         // rdar://problem/10733082 Fix up @path based paths during introspection 
 154                         // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them 
 155                         char realPath
[MAXPATHLEN
]; 
 156                         if ( fcntl(fd
, F_GETPATH
, realPath
) == 0 )  
 157                                 image
->setPaths(path
, realPath
); 
 159                                 image
->setPath(path
); 
 162                         image
->setPath(path
); 
 164                 // make sure path is stable before recording in dyld_all_image_infos 
 165                 image
->setMapped(context
); 
 167                 // pre-fetch content of __DATA segment for faster launches 
 168                 // don't do this on prebound images or if prefetching is disabled 
 169         if ( !context
.preFetchDisabled 
&& !image
->isPrebindable()) 
 170                         image
->preFetchDATA(fd
, offsetInFat
, context
); 
 174                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 175                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 183 // create image by using cached mach-o file 
 184 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, 
 185                                                                                                                                 unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
 187         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart(mh
, path
, segCount
, libCount
); 
 189                 // record info about file   
 190                 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
); 
 192                 // remember this is from shared cache and cannot be unloaded 
 193                 image
->fInSharedCache 
= true; 
 194                 image
->setNeverUnload(); 
 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, e
=image
->segmentCount(); i 
< e
; ++i
) { 
 200                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", image
->segName(i
), image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
)); 
 204                 image
->instantiateFinish(context
); 
 205                 image
->setMapped(context
); 
 208                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 209                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 217 // create image by copying an in-memory mach-o file 
 218 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
,  
 219                                                                                                                         unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
 221         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart(mh
, moduleName
, segCount
, libCount
); 
 224                 if ( mh
->filetype 
== MH_EXECUTE 
)  
 225                         throw "can't load another MH_EXECUTE"; 
 228                 image
->ImageLoaderMachO::mapSegments((const void*)mh
, len
, context
); 
 230                 // for compatibility, never unload dylibs loaded from memory 
 231                 image
->setNeverUnload(); 
 233                 // bundle loads need path copied 
 234                 if ( moduleName 
!= NULL 
)  
 235                         image
->setPath(moduleName
); 
 237                 image
->instantiateFinish(context
); 
 238                 image
->setMapped(context
); 
 241                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 242                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 251 ImageLoaderMachOClassic::ImageLoaderMachOClassic(const macho_header
* mh
, const char* path
,  
 252                                                                                                         unsigned int segCount
, uint32_t segOffsets
[], unsigned int libCount
) 
 253  : ImageLoaderMachO(mh
, path
, segCount
, segOffsets
, libCount
), fStrings(NULL
), fSymbolTable(NULL
), fDynamicInfo(NULL
) 
 257 // construct ImageLoaderMachOClassic using "placement new" with SegmentMachO objects array at end 
 258 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateStart(const macho_header
* mh
, const char* path
, 
 259                                                                                                                                                 unsigned int segCount
, unsigned int libCount
) 
 261         size_t size 
= sizeof(ImageLoaderMachOClassic
) + segCount 
* sizeof(uint32_t) + libCount 
* sizeof(ImageLoader
*); 
 262         ImageLoaderMachOClassic
* allocatedSpace 
= static_cast<ImageLoaderMachOClassic
*>(malloc(size
)); 
 263         if ( allocatedSpace 
== NULL 
) 
 264                 throw "malloc failed"; 
 265         uint32_t* segOffsets 
= ((uint32_t*)(((uint8_t*)allocatedSpace
) + sizeof(ImageLoaderMachOClassic
))); 
 266         bzero(&segOffsets
[segCount
], libCount
*sizeof(void*));   // zero out lib array 
 267         return new (allocatedSpace
) ImageLoaderMachOClassic(mh
, path
, segCount
, segOffsets
, libCount
); 
 272 // common code to finish initializing object 
 273 void ImageLoaderMachOClassic::instantiateFinish(const LinkContext
& context
) 
 275         // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 
 276         this->parseLoadCmds(); 
 279 ImageLoaderMachOClassic::~ImageLoaderMachOClassic() 
 281         // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work 
 285 uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const 
 287         return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
))); 
 291 ImageLoader
* ImageLoaderMachOClassic::libImage(unsigned int libIndex
) const 
 293         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 295         return (ImageLoader
*)(images
[libIndex
] & (-4)); 
 298 bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex
) const 
 300         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 301         // re-export flag is low bit 
 302         return ((images
[libIndex
] & 1) != 0); 
 305 bool ImageLoaderMachOClassic::libIsUpward(unsigned int libIndex
) const 
 307         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 308         // upward flag is second bit 
 309         return ((images
[libIndex
] & 2) != 0); 
 313 void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex
, ImageLoader
* image
, bool reExported
, bool upward
) 
 315         uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 316         uintptr_t value 
= (uintptr_t)image
; 
 321         images
[libIndex
] = value
; 
 325 void ImageLoaderMachOClassic::setSymbolTableInfo(const macho_nlist
* symbols
, const char* strings
, const dysymtab_command
* dynSym
) 
 327         fSymbolTable 
= symbols
; 
 329         fDynamicInfo 
= dynSym
; 
 332 void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext
& context
) 
 334         // always prefetch a subrange of __LINKEDIT pages 
 335         uintptr_t symbolTableStart 
= (uintptr_t)fSymbolTable
; 
 336         uintptr_t stringTableStart 
= (uintptr_t)fStrings
; 
 338         // if image did not load at preferred address 
 339         if ( segPreferredLoadAddress(0) != (uintptr_t)fMachOData 
) { 
 340                 // local relocations will be processed, so start pre-fetch at local symbols 
 341                 start 
= (uintptr_t)fMachOData 
+ fDynamicInfo
->locreloff
; 
 344                 // otherwise start pre-fetch at global symbols section of symbol table 
 345                 start 
= symbolTableStart 
+ fDynamicInfo
->iextdefsym 
* sizeof(macho_nlist
); 
 347         // prefetch ends at end of last undefined string in string pool 
 348         uintptr_t end 
= stringTableStart
; 
 349         if ( fDynamicInfo
->nundefsym 
!= 0 ) 
 350                 end 
+= fSymbolTable
[fDynamicInfo
->iundefsym
+fDynamicInfo
->nundefsym
-1].n_un
.n_strx
; 
 351         else if ( fDynamicInfo
->nextdefsym 
!= 0 ) 
 352                 end 
+= fSymbolTable
[fDynamicInfo
->iextdefsym
+fDynamicInfo
->nextdefsym
-1].n_un
.n_strx
; 
 354         // round to whole pages 
 355         start 
= start 
& (-4096); 
 356         end 
= (end 
+ 4095) & (-4096); 
 358         // skip if there is only one page 
 359         if ( (end
-start
) > 4096 ) { 
 360                 madvise((void*)start
, end
-start
, MADV_WILLNEED
); 
 361                 fgTotalBytesPreFetched 
+= (end
-start
); 
 362                 if ( context
.verboseMapping 
) { 
 363                         dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", "__LINKEDIT", start
, end
-1); 
 369 #if SPLIT_SEG_DYLIB_SUPPORT      
 371 ImageLoaderMachOClassic::getExtraZeroFillEntriesCount() 
 373         // calculate mapping entries 
 374         unsigned int extraZeroFillEntries 
= 0; 
 375         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 376                 if ( segHasTrailingZeroFill(i
) ) 
 377                         ++extraZeroFillEntries
; 
 380         return extraZeroFillEntries
; 
 384 ImageLoaderMachOClassic::initMappingTable(uint64_t offsetInFat
, 
 385                                                                    shared_file_mapping_np 
*mappingTable
) 
 387         for(unsigned int i
=0,entryIndex
=0; i 
< fSegmentsCount
; ++i
, ++entryIndex
) { 
 388                 shared_file_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 389                 entry
->sfm_address                      
= segActualLoadAddress(i
); 
 390                 entry
->sfm_size                         
= segFileSize(i
); 
 391                 entry
->sfm_file_offset          
= segFileOffset(i
) + offsetInFat
; 
 392                 entry
->sfm_init_prot            
= VM_PROT_NONE
; 
 393                 if ( !segUnaccessible(i
) ) { 
 394                         if ( segExecutable(i
) ) 
 395                                 entry
->sfm_init_prot   
|= VM_PROT_EXECUTE
; 
 396                         if ( segReadable(i
) ) 
 397                                 entry
->sfm_init_prot   
|= VM_PROT_READ
; 
 398                         if ( segWriteable(i
) ) 
 399                                 entry
->sfm_init_prot   
|= VM_PROT_WRITE 
| VM_PROT_COW
; 
 401                 entry
->sfm_max_prot                     
= entry
->sfm_init_prot
; 
 402                 if ( segHasTrailingZeroFill(i
) ) { 
 403                         shared_file_mapping_np
* zfentry 
= &mappingTable
[++entryIndex
]; 
 404                         zfentry
->sfm_address            
= entry
->sfm_address 
+ segFileSize(i
); 
 405                         zfentry
->sfm_size                       
= segSize(i
) - segFileSize(i
); 
 406                         zfentry
->sfm_file_offset        
= 0; 
 407                         zfentry
->sfm_init_prot          
= entry
->sfm_init_prot 
| VM_PROT_COW 
| VM_PROT_ZF
; 
 408                         zfentry
->sfm_max_prot           
= zfentry
->sfm_init_prot
; 
 414 ImageLoaderMachOClassic::mapSplitSegDylibOutsideSharedRegion(int fd
, 
 415                                                                                                         uint64_t offsetInFat
, 
 418                                                                                                         const LinkContext
& context
) 
 420         uintptr_t nextAltLoadAddress 
= 0; 
 421         const unsigned int segmentCount 
= fSegmentsCount
; 
 422         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 423         const unsigned int regionCount 
= segmentCount
+extraZeroFillEntries
; 
 424         shared_file_mapping_np regions
[regionCount
]; 
 425         initMappingTable(offsetInFat
, regions
); 
 427         // find space somewhere to allocate split seg 
 428         bool foundRoom 
= false; 
 429         while ( ! foundRoom 
) { 
 431                 for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 432                         vm_address_t addr 
= nextAltLoadAddress 
+ regions
[i
].sfm_address 
- regions
[0].sfm_address
; 
 433                         vm_size_t size 
= regions
[i
].sfm_size 
; 
 434                         r 
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/); 
 436                                 // no room here, deallocate what has succeeded so far 
 437                                 for(unsigned int j
=0; j 
< i
; ++j
) { 
 438                                         vm_address_t addr 
= nextAltLoadAddress 
+ regions
[j
].sfm_address 
- regions
[0].sfm_address
; 
 439                                         vm_size_t size 
= regions
[j
].sfm_size 
; 
 440                                         (void)vm_deallocate(mach_task_self(), addr
, size
); 
 442                                 nextAltLoadAddress 
+= 0x00100000;  // skip ahead 1MB and try again 
 443                                 // skip over shared region 
 444                                 if ( (SHARED_REGION_BASE 
<= nextAltLoadAddress
) && (nextAltLoadAddress 
< (SHARED_REGION_BASE 
+ SHARED_REGION_SIZE
)) ) 
 445                                         nextAltLoadAddress 
= (SHARED_REGION_BASE 
+ SHARED_REGION_SIZE
); 
 446                                 if ( nextAltLoadAddress 
> 0xFF000000 ) 
 447                                         throw "can't map split seg anywhere"; 
 454         // map in each region 
 455         uintptr_t slide 
= nextAltLoadAddress 
- regions
[0].sfm_address
; 
 456         this->setSlide(slide
); 
 457         for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 458                 if ( ((regions
[i
].sfm_init_prot 
& VM_PROT_ZF
) != 0) || (regions
[i
].sfm_size 
== 0) ) { 
 459                         // nothing to mmap for zero-fills areas, they are just vm_allocated  
 462                         void* mmapAddress 
= (void*)(uintptr_t)(regions
[i
].sfm_address 
+ slide
); 
 463                         size_t size 
= regions
[i
].sfm_size
; 
 465                         if ( regions
[i
].sfm_init_prot 
& VM_PROT_EXECUTE 
) 
 466                                 protection   
|= PROT_EXEC
; 
 467                         if ( regions
[i
].sfm_init_prot 
& VM_PROT_READ 
) 
 468                                 protection   
|= PROT_READ
; 
 469                         if ( regions
[i
].sfm_init_prot 
& VM_PROT_WRITE 
) 
 470                                 protection   
|= PROT_WRITE
; 
 471                         off_t offset 
= regions
[i
].sfm_file_offset
; 
 472                         //dyld::log("mmap(%p, 0x%08lX, %s\n", mmapAddress, size, fPath); 
 473                         mmapAddress 
= mmap(mmapAddress
, size
, protection
, MAP_FIXED 
| MAP_PRIVATE
, fd
, offset
); 
 474                         if ( mmapAddress 
== ((void*)(-1)) ) 
 480         if ( context
.verboseMapping 
) { 
 481                 dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath()); 
 482                 for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 483                         const shared_file_mapping_np
* entry 
= ®ions
[entryIndex
]; 
 484                         if ( (entry
->sfm_init_prot 
& VM_PROT_ZF
) == 0 )  
 485                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", 
 486                                                 segName(segIndex
), segActualLoadAddress(segIndex
), segActualEndAddress(segIndex
)-1); 
 487                         if ( entryIndex 
< (regionCount
-1) ) { 
 488                                 const shared_file_mapping_np
* nextEntry 
= ®ions
[entryIndex
+1]; 
 489                                 if ( (nextEntry
->sfm_init_prot 
& VM_PROT_ZF
) != 0 ) { 
 490                                         uint64_t segOffset 
= nextEntry
->sfm_address 
- entry
->sfm_address
; 
 491                                         dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n", 
 492                                                         segName(segIndex
), (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset
), (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset 
+ nextEntry
->sfm_size 
- 1)); 
 501 #endif // SPLIT_SEG_DYLIB_SUPPORT 
 504 void ImageLoaderMachOClassic::mapSegmentsClassic(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
) 
 506         // non-split segment libraries handled by super class 
 508                 return ImageLoaderMachO::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
); 
 510 #if SPLIT_SEG_SHARED_REGION_SUPPORT      
 511         // don't map split-seg dylibs into shared region if shared cache is in use 
 512         if ( ! context
.dyldLoadedAtSameAddressNeededBySharedCache 
) { 
 513                 // try to map into shared region at preferred address 
 514                 if ( mapSplitSegDylibInfoSharedRegion(fd
, offsetInFat
, lenInFat
, fileLen
, context
) == 0)  
 517         // if there is a problem, fall into case where we map file somewhere outside the shared region 
 520 #if SPLIT_SEG_DYLIB_SUPPORT 
 521         // support old split-seg dylibs by mapping them where ever we find space 
 522         if ( mapSplitSegDylibOutsideSharedRegion(fd
, offsetInFat
, lenInFat
, fileLen
, context
) != 0 )  
 524                 throw "mapping error"; 
 528 #if SPLIT_SEG_SHARED_REGION_SUPPORT      
 529 static int _shared_region_map_np(int fd
, uint32_t count
, const shared_file_mapping_np mappings
[]) 
 531         return syscall(295, fd
, count
, mappings
); 
 535 ImageLoaderMachOClassic::mapSplitSegDylibInfoSharedRegion(int fd
, 
 536                                          uint64_t offsetInFat
, 
 539                                          const LinkContext
& context
) 
 541         // build table of segments to map 
 542         const unsigned int segmentCount 
= fSegmentsCount
; 
 543         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 544         const unsigned int mappingTableCount 
= segmentCount
+extraZeroFillEntries
; 
 545         shared_file_mapping_np mappingTable
[mappingTableCount
]; 
 546         initMappingTable(offsetInFat
, mappingTable
); 
 548         // try to map it in shared 
 549         int r 
= _shared_region_map_np(fd
, mappingTableCount
, mappingTable
); 
 551                 this->setNeverUnload(); 
 552                 if ( context
.verboseMapping 
) { 
 553                         dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath()); 
 554                         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 555                                 const shared_file_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 556                                 if ( (entry
->sfm_init_prot 
& VM_PROT_ZF
) == 0 )  
 557                                         dyld::log("%18s at 0x%08lX->0x%08lX\n", 
 558                                                           segName(segIndex
), segActualLoadAddress(segIndex
), segActualEndAddress(segIndex
)-1); 
 559                                 if ( entryIndex 
< (mappingTableCount
-1) ) { 
 560                                         const shared_file_mapping_np
* nextEntry 
= &mappingTable
[entryIndex
+1]; 
 561                                         if ( (nextEntry
->sfm_init_prot 
& VM_PROT_ZF
) != 0 ) { 
 562                                                 uint64_t segOffset 
= nextEntry
->sfm_address 
- entry
->sfm_address
; 
 563                                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", 
 564                                                                   segName(segIndex
), (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset
),  
 565                                                                   (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset 
+ nextEntry
->sfm_size 
- 1)); 
 575 #endif // SPLIT_SEG_SHARED_REGION_SUPPORT        
 577 // test if this image is re-exported through parent (the image that loaded this one) 
 578 bool ImageLoaderMachOClassic::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const 
 581                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 582                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 583                 const struct load_command
* cmd 
= cmds
; 
 584                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 585                         if (cmd
->cmd 
== LC_SUB_FRAMEWORK
) { 
 586                                 const struct sub_framework_command
* subf 
= (struct sub_framework_command
*)cmd
; 
 587                                 const char* exportThruName 
= (char*)cmd 
+ subf
->umbrella
.offset
; 
 588                                 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent... 
 589                                 const char* parentInstallPath 
= parent
->getInstallPath(); 
 590                                 if ( parentInstallPath 
!= NULL 
) { 
 591                                         const char* lastSlash 
= strrchr(parentInstallPath
, '/'); 
 592                                         if ( lastSlash 
!= NULL 
) { 
 593                                                 if ( strcmp(&lastSlash
[1], exportThruName
) == 0 ) 
 595                                                 if ( context
.imageSuffix 
!= NULL 
) { 
 596                                                         // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 
 597                                                         char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(exportThruName
)+1]; 
 598                                                         strcpy(reexportAndSuffix
, exportThruName
); 
 599                                                         strcat(reexportAndSuffix
, context
.imageSuffix
); 
 600                                                         if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 ) 
 606                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 612 // test if child is re-exported  
 613 bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const 
 615         if ( fHasSubLibraries 
) { 
 616                 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child... 
 617                 const char* childInstallPath 
= child
->getInstallPath(); 
 618                 if ( childInstallPath 
!= NULL 
) { 
 619                         const char* lastSlash 
= strrchr(childInstallPath
, '/'); 
 620                         if ( lastSlash 
!= NULL 
) { 
 621                                 const char* firstDot 
= strchr(lastSlash
, '.'); 
 623                                 if ( firstDot 
== NULL 
) 
 624                                         len 
= strlen(lastSlash
); 
 626                                         len 
= firstDot
-lastSlash
-1; 
 627                                 char childLeafName
[len
+1]; 
 628                                 strncpy(childLeafName
, &lastSlash
[1], len
); 
 629                                 childLeafName
[len
] = '\0'; 
 630                                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 631                                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 632                                 const struct load_command
* cmd 
= cmds
; 
 633                                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 637                                                                 const struct sub_library_command
* lib 
= (struct sub_library_command
*)cmd
; 
 638                                                                 const char* aSubLibName 
= (char*)cmd 
+ lib
->sub_library
.offset
; 
 639                                                                 if ( strcmp(aSubLibName
, childLeafName
) == 0 ) 
 641                                                                 if ( context
.imageSuffix 
!= NULL 
) { 
 642                                                                         // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end 
 643                                                                         char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1]; 
 644                                                                         strcpy(aSubLibNameAndSuffix
, aSubLibName
); 
 645                                                                         strcat(aSubLibNameAndSuffix
, context
.imageSuffix
); 
 646                                                                         if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 ) 
 652                                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 657         if ( fHasSubUmbrella 
) { 
 658                 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child... 
 659                 const char* childInstallPath 
= child
->getInstallPath(); 
 660                 if ( childInstallPath 
!= NULL 
) { 
 661                         const char* lastSlash 
= strrchr(childInstallPath
, '/'); 
 662                         if ( lastSlash 
!= NULL 
) { 
 663                                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 664                                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 665                                 const struct load_command
* cmd 
= cmds
; 
 666                                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 668                                                 case LC_SUB_UMBRELLA
: 
 670                                                                 const struct sub_umbrella_command
* um 
= (struct sub_umbrella_command
*)cmd
; 
 671                                                                 const char* aSubUmbrellaName 
= (char*)cmd 
+ um
->sub_umbrella
.offset
; 
 672                                                                 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 ) 
 674                                                                 if ( context
.imageSuffix 
!= NULL 
) { 
 675                                                                         // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 
 676                                                                         char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1]; 
 677                                                                         strcpy(umbrellaAndSuffix
, aSubUmbrellaName
); 
 678                                                                         strcat(umbrellaAndSuffix
, context
.imageSuffix
); 
 679                                                                         if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 ) 
 685                                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 694 uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress() 
 696         // in split segment libraries r_address is offset from first writable segment 
 697         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 698                 if ( segWriteable(i
) )  
 699                         return segActualLoadAddress(i
); 
 701         throw "no writable segment"; 
 704 uintptr_t ImageLoaderMachOClassic::getRelocBase() 
 706         // r_address is either an offset from the first segment address 
 707         // or from the first writable segment address 
 709         return getFirstWritableSegmentAddress(); 
 712                 return getFirstWritableSegmentAddress(); 
 714                 return segActualLoadAddress(0); 
 719 #if PREBOUND_IMAGE_SUPPORT 
 720 void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext
& context
) 
 722         // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values 
 723         const uintptr_t relocBase 
= this->getRelocBase(); 
 724         register const uintptr_t slide 
= this->fSlide
; 
 725         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]); 
 726         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nlocrel
]; 
 727         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
 728                 if ( (reloc
->r_address 
& R_SCATTERED
) != 0 ) { 
 729                         const struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
 730                         if (sreloc
->r_length 
== RELOC_SIZE
) { 
 731                                 uintptr_t* locationToFix 
= (uintptr_t*)(sreloc
->r_address 
+ relocBase
); 
 732                                 switch(sreloc
->r_type
) { 
 734                                         case GENERIC_RELOC_PB_LA_PTR
: 
 735                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
 739                                         case ARM_RELOC_PB_LA_PTR
: 
 740                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
 753 void ImageLoaderMachOClassic::rebase(const LinkContext
& context
) 
 755         CRSetCrashLogMessage2(this->getPath()); 
 756         register const uintptr_t slide 
= this->fSlide
; 
 757         const uintptr_t relocBase 
= this->getRelocBase(); 
 759         // prefetch any LINKEDIT pages needed 
 760         if ( !context
.preFetchDisabled 
&& !this->isPrebindable()) 
 761                 this->prefetchLINKEDIT(context
); 
 763         // loop through all local (internal) relocation records 
 764         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]); 
 765         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nlocrel
]; 
 766         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
 767                 uintptr_t rebaseAddr
; 
 769         #if LINKEDIT_USAGE_DEBUG 
 770                         noteAccessedLinkEditAddress(reloc
); 
 773                         // only one kind of local relocation supported for x86_64 
 774                         if ( reloc
->r_length 
!= 3 )  
 775                                 throw "bad local relocation length"; 
 776                         if ( reloc
->r_type 
!= X86_64_RELOC_UNSIGNED 
)  
 777                                 throw "unknown local relocation type"; 
 778                         if ( reloc
->r_pcrel 
!= 0 )  
 779                                 throw "bad local relocation pc_rel"; 
 780                         if ( reloc
->r_extern 
!= 0 )  
 781                                 throw "extern relocation found with local relocations"; 
 782                         rebaseAddr 
= reloc
->r_address 
+ relocBase
; 
 783                         if ( ! this->containsAddress((void*)rebaseAddr
) ) 
 784                                 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr
); 
 785                         *((uintptr_t*)rebaseAddr
) += slide
; 
 786                         if ( context
.verboseRebase 
) 
 787                                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr
, slide
); 
 789                         if ( (reloc
->r_address 
& R_SCATTERED
) == 0 ) { 
 790                                 if ( reloc
->r_symbolnum 
== R_ABS 
) { 
 791                                         // ignore absolute relocations 
 793                                 else if (reloc
->r_length 
== RELOC_SIZE
) { 
 794                                         switch(reloc
->r_type
) { 
 795                                                 case GENERIC_RELOC_VANILLA
: 
 796                                                         rebaseAddr 
= reloc
->r_address 
+ relocBase
; 
 797                                                         if ( ! this->containsAddress((void*)rebaseAddr
) ) 
 798                                                                 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr
); 
 799                                                         *((uintptr_t*)rebaseAddr
) += slide
; 
 800                                                         if ( context
.verboseRebase 
) 
 801                                                                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr
, slide
); 
 804                                                         throw "unknown local relocation type"; 
 808                                         throw "bad local relocation length"; 
 812                                 const struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
 813                                 if (sreloc
->r_length 
== RELOC_SIZE
) { 
 814                                         uintptr_t* locationToFix 
= (uintptr_t*)(sreloc
->r_address 
+ relocBase
); 
 815                                         switch(sreloc
->r_type
) { 
 816                                                 case GENERIC_RELOC_VANILLA
: 
 817                                                         if ( ! this->containsAddress((void*)locationToFix
) )  
 818                                                                 dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix
); 
 819                                                         *locationToFix 
+= slide
; 
 820                                                         if ( context
.verboseRebase 
) 
 821                                                                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix
, slide
); 
 824                                                 case GENERIC_RELOC_PB_LA_PTR
: 
 828                                                 case ARM_RELOC_PB_LA_PTR
: 
 833                                                         throw "unknown local scattered relocation type"; 
 837                                         throw "bad local scattered relocation length"; 
 842                 catch (const char* msg
) { 
 843                         const uint8_t* r 
= (uint8_t*)reloc
; 
 844                         dyld::throwf("%s in %s. reloc record at %p: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 
 845                                 msg
, this->getPath(), reloc
, r
[0], r
[1], r
[2], r
[3], r
[4], r
[5], r
[6], r
[7]); 
 850         fgTotalRebaseFixups 
+= fDynamicInfo
->nlocrel
; 
 851         CRSetCrashLogMessage2(NULL
); 
 856 const struct macho_nlist
* ImageLoaderMachOClassic::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],  
 857                                                                                                 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
) const 
 859         int32_t high 
= symbolCount
-1; 
 860         int32_t mid 
= hintIndex
; 
 862         // handle out of range hint 
 863         if ( mid 
>= (int32_t)symbolCount 
) 
 865         ++ImageLoaderMachO::fgSymbolTableBinarySearchs
; 
 866         ++fgTotalBindImageSearches
;      
 868         //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName()); 
 870         for (int32_t low 
= 0; low 
<= high
; mid 
= (low
+high
)/2) { 
 871                 const uint32_t index 
= toc
[mid
].symbol_index
; 
 872                 const struct macho_nlist
* pivot 
= &symbols
[index
]; 
 873                 const char* pivotStr 
= &stringPool
[pivot
->n_un
.n_strx
]; 
 874 #if LINKEDIT_USAGE_DEBUG 
 875                 noteAccessedLinkEditAddress(&toc
[mid
]); 
 876                 noteAccessedLinkEditAddress(pivot
); 
 877                 noteAccessedLinkEditAddress(pivotStr
); 
 879                 int cmp 
= strcmp(key
, pivotStr
); 
 894 const struct macho_nlist
* ImageLoaderMachOClassic::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
) const 
 897         ++fgTotalBindImageSearches
;      
 898         ++ImageLoaderMachO::fgSymbolTableBinarySearchs
; 
 900         //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n",  
 901         //                              key, this->getShortName(), stringPool, symbols, symbolCount); 
 903         const struct macho_nlist
* base 
= symbols
; 
 904         for (uint32_t n 
= symbolCount
; n 
> 0; n 
/= 2) { 
 905                 const struct macho_nlist
* pivot 
= &base
[n
/2]; 
 906                 const char* pivotStr 
= &stringPool
[pivot
->n_un
.n_strx
]; 
 907 #if LINKEDIT_USAGE_DEBUG 
 908                 noteAccessedLinkEditAddress(pivot
); 
 909                 noteAccessedLinkEditAddress(pivotStr
); 
 911                 int cmp 
= strcmp(key
, pivotStr
); 
 916                         // move base to symbol after pivot 
 929 const ImageLoader::Symbol
* ImageLoaderMachOClassic::findExportedSymbol(const char* name
, const ImageLoader
** foundIn
) const 
 931         const struct macho_nlist
* sym 
= NULL
; 
 932         if ( fDynamicInfo
->tocoff 
== 0 ) 
 933                 sym 
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
); 
 935                 sym 
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],  
 936                                                                                 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
); 
 938                 if ( foundIn 
!= NULL 
) 
 939                         *foundIn 
= (ImageLoader
*)this;           
 940                 return (const Symbol
*)sym
; 
 947 bool ImageLoaderMachOClassic::containsSymbol(const void* addr
) const 
 949         return ( (fSymbolTable 
<= addr
) && (addr 
< fStrings
) ); 
 953 uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext
& context
, const Symbol
* symbol
, const ImageLoader
* requestor
, bool runResolver
) const 
 955         const struct macho_nlist
* sym 
= (macho_nlist
*)symbol
; 
 956         uintptr_t result 
= sym
->n_value 
+ fSlide
; 
 958                 // processor assumes code address with low bit set is thumb 
 959                 if (sym
->n_desc 
& N_ARM_THUMB_DEF
) 
 965 bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol
* symbol
) const 
 967         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)symbol
; 
 968         return ( (nlistSym
->n_desc 
& N_WEAK_DEF
) != 0 ); 
 971 const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol
* symbol
) const 
 973         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)symbol
; 
 974         return &fStrings
[nlistSym
->n_un
.n_strx
]; 
 977 unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const 
 979         return fDynamicInfo
->nextdefsym
; 
 982 const ImageLoader::Symbol
* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index
) const 
 984         if ( index 
< fDynamicInfo
->nextdefsym 
) { 
 985                 const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iextdefsym 
+ index
]; 
 986                 return (const ImageLoader::Symbol
*)sym
; 
 991 unsigned int ImageLoaderMachOClassic::importedSymbolCount() const 
 993         return fDynamicInfo
->nundefsym
; 
 996 const ImageLoader::Symbol
* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index
) const 
 998         if ( index 
< fDynamicInfo
->nundefsym 
) { 
 999                 const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iundefsym 
+ index
]; 
1000                 return (const ImageLoader::Symbol
*)sym
; 
1005 const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol
* symbol
) const 
1007         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)symbol
; 
1008         return &fStrings
[nlistSym
->n_un
.n_strx
]; 
1013 bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist
* symbol
) 
1015         // if a define and weak ==> coalesced  
1016         if ( ((symbol
->n_type 
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc 
& N_WEAK_DEF
) != 0) )  
1023 bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist
* symbol
) 
1025         // if an undefine and not referencing a weak symbol ==> coalesced 
1026         if ( ((symbol
->n_type 
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc 
& N_REF_TO_WEAK
) != 0) ) 
1033 uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist
* sym
, const LinkContext
& context
, bool runResolver
) const 
1035         return ImageLoaderMachO::getSymbolAddress((Symbol
*)sym
, this, context
, runResolver
); 
1038 uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
,  
1039                                                                                 bool twoLevel
, bool dontCoalesce
, const ImageLoader
** foundIn
) 
1041         ++fgTotalBindSymbolsResolved
; 
1042         const char* symbolName 
= &fStrings
[undefinedSymbol
->n_un
.n_strx
]; 
1044 #if LINKEDIT_USAGE_DEBUG 
1045         noteAccessedLinkEditAddress(undefinedSymbol
); 
1046         noteAccessedLinkEditAddress(symbolName
); 
1048         if ( context
.bindFlat 
|| !twoLevel 
) { 
1050                 if ( ((undefinedSymbol
->n_type 
& N_PEXT
) != 0) && ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) ) { 
1051                         // is a multi-module private_extern internal reference that the linker did not optimize away 
1052                         uintptr_t addr 
= this->getSymbolAddress(undefinedSymbol
, context
, false); 
1057                 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) { 
1058                         if ( *foundIn 
!= this ) 
1059                                 context
.addDynamicReference(this, const_cast<ImageLoader
*>(*foundIn
)); 
1060                         return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1062                 // if a bundle is loaded privately the above will not find its exports 
1063                 if ( this->isBundle() && this->hasHiddenExports() ) { 
1064                         // look in self for needed symbol 
1065                         sym 
= this->findExportedSymbol(symbolName
, foundIn
); 
1067                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1069                 if ( (undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0 ) { 
1070                         // definition can't be found anywhere 
1071                         // if reference is weak_import, then it is ok, just return 0 
1074                 throwSymbolNotFound(context
, symbolName
, this->getPath(), "flat namespace"); 
1077                 // symbol requires searching images with coalesced symbols (not done during prebinding) 
1078                 if ( !context
.prebinding 
&& !dontCoalesce 
&& (symbolIsWeakReference(undefinedSymbol
) || symbolIsWeakDefinition(undefinedSymbol
)) ) { 
1080                         if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) ) { 
1081                                 if ( *foundIn 
!= this ) 
1082                                         context
.addDynamicReference(this, const_cast<ImageLoader
*>(*foundIn
)); 
1083                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1085                         //throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace"); 
1086                         //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName); 
1089                 // if this is a real definition (not an undefined symbol) there is no ordinal 
1090                 if ( (undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT 
) { 
1091                         // static linker should never generate this case, but if it does, do something sane 
1092                         uintptr_t addr 
= this->getSymbolAddress(undefinedSymbol
, context
, false); 
1098                 ImageLoader
* target 
= NULL
; 
1099                 uint8_t ord 
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
); 
1100                 if ( ord 
== EXECUTABLE_ORDINAL 
) { 
1101                         target 
= context
.mainExecutable
; 
1103                 else if ( ord 
== SELF_LIBRARY_ORDINAL 
) { 
1106                 else if ( ord 
== DYNAMIC_LOOKUP_ORDINAL 
) { 
1107                         // rnielsen: HACKHACK 
1110                         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1111                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1112                         // no image has exports this symbol 
1114                         context
.undefinedHandler(symbolName
); 
1115                         // try looking again 
1116                         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1117                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1119                         throwSymbolNotFound(context
, symbolName
, this->getPath(), "dynamic lookup"); 
1121                 else if ( ord 
<= libraryCount() ) { 
1122                         target 
= libImage(ord
-1); 
1123                         if ( target 
== NULL 
) { 
1124                                 // if target library not loaded and reference is weak or library is weak return 0 
1129                         dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s", 
1130                                 ord
, libraryCount(), symbolName
, this->getPath()); 
1133                 if ( target 
== NULL 
) { 
1134                         //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath()); 
1135                         throw "symbol not found"; 
1138                 const Symbol
* sym 
= target
->findExportedSymbol(symbolName
, true, foundIn
); 
1140                         return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1142                 else if ( (undefinedSymbol
->n_type 
& N_PEXT
) != 0 ) { 
1143                         // don't know why the static linker did not eliminate the internal reference to a private extern definition 
1145                         return this->getSymbolAddress(undefinedSymbol
, context
, false); 
1147                 else if ( (undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0 ) { 
1148                         // if definition not found and reference is weak return 0 
1152                 // nowhere to be found 
1153                 throwSymbolNotFound(context
, symbolName
, this->getPath(), target
->getPath()); 
1159 // returns if 'addr' is within the address range of section 'sectionIndex' 
1160 // fSlide is not used.  'addr' is assumed to be a prebound address in this image  
1161 bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
) 
1163         uint8_t currentSectionIndex 
= 1; 
1164         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1165         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1166         const struct load_command
* cmd 
= cmds
; 
1167         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1168                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1169                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1170                         if ( (currentSectionIndex 
<= sectionIndex
) && (sectionIndex 
< currentSectionIndex
+seg
->nsects
) ) { 
1171                                 // 'sectionIndex' is in this segment, get section info 
1172                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1173                                 const struct macho_section
* const section 
= §ionsStart
[sectionIndex
-currentSectionIndex
]; 
1174                                 return ( (section
->addr 
<= addr
) && (addr 
< section
->addr
+section
->size
) ); 
1177                                 // 'sectionIndex' not in this segment, skip to next segment 
1178                                 currentSectionIndex 
+= seg
->nsects
; 
1181                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1187 void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext
& context
) 
1189         const uintptr_t relocBase 
= this->getRelocBase(); 
1190         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1191         const bool prebound 
= this->isPrebindable(); 
1193 #if TEXT_RELOC_SUPPORT 
1194         // if there are __TEXT fixups, temporarily make __TEXT writable 
1195         if ( fTextSegmentBinds 
)  
1196                 this->makeTextSegmentWritable(context
, true); 
1198         // cache last lookup 
1199         const struct macho_nlist
*       lastUndefinedSymbol 
= NULL
; 
1200         uintptr_t                                       symbolAddr 
= 0; 
1201         const ImageLoader
*                      image 
= NULL
; 
1203         // loop through all external relocation records and bind each 
1204         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
1205         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
1206         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1207                 if (reloc
->r_length 
== RELOC_SIZE
) { 
1208                         switch(reloc
->r_type
) { 
1211                                                 const struct macho_nlist
* undefinedSymbol 
= &fSymbolTable
[reloc
->r_symbolnum
]; 
1212                                                 uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
1213                                                 if ( ! this->containsAddress((void*)location
) ) 
1214                                                         dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location
, this->getPath()); 
1215                                                 uintptr_t value 
= *location
; 
1216                                                 bool symbolAddrCached 
= true; 
1218                                                 if ( reloc
->r_pcrel 
) { 
1219                                                         value 
+= (uintptr_t)location 
+ 4 - fSlide
; 
1223                                                         // we are doing relocations, so prebinding was not usable 
1224                                                         // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 
1225                                                         // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 
1226                                                         // if mach-o relocation structs had an "addend" field this complication would not be necessary. 
1227                                                         if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1228                                                                 // weak symbols need special casing, since *location may have been prebound to a definition in another image. 
1229                                                                 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume  
1230                                                                 // that we can subtract off the weak symbol address to get the addend. 
1231                                                                 // If prebound elsewhere, we've lost the addend and have to assume it is zero. 
1232                                                                 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 
1233                                                                 if ( (value 
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) ) { 
1234                                                                         value 
-= undefinedSymbol
->n_value
; 
1236                                     // if weak and thumb subtract off extra thumb bit 
1237                                     if ( (undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0 ) 
1245                                                         else if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0) ) { 
1246                                                                 // it was prebound to a defined symbol for thumb code in the same linkage unit 
1247                                                                 // we need to subtract off one to get real addend 
1248                                                                 value 
-= (undefinedSymbol
->n_value
+1); 
1252                                                                 // is undefined or non-weak symbol, so do subtraction to get addend 
1253                                                                 value 
-= undefinedSymbol
->n_value
; 
1256                                                 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too 
1257                                                 if ( undefinedSymbol 
!= lastUndefinedSymbol 
) { 
1258                                                         bool dontCoalesce 
= true; 
1259                                                         if ( symbolIsWeakReference(undefinedSymbol
) ) {  
1260                                                                 // when weakbind() is run on a classic mach-o encoding, it won't try 
1261                                                                 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted 
1262                                                                 // range of global symbols.  To handle that case we do the coalesing now. 
1263                                                                 dontCoalesce 
= false; 
1265                                                         symbolAddr 
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, dontCoalesce
, &image
); 
1266                                                         lastUndefinedSymbol 
= undefinedSymbol
; 
1267                                                         symbolAddrCached 
= false; 
1269                                                 if ( context
.verboseBind 
) { 
1270                                                         const char *path 
= NULL
; 
1271                                                         if ( image 
!= NULL 
) { 
1272                                                                 path 
= image
->getShortName(); 
1274                                                         const char* cachedString 
= "(cached)"; 
1275                                                         if ( !symbolAddrCached 
)  
1278                                                                 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n", 
1279                                                                                 this->getShortName(), (uintptr_t)location
, 
1280                                                                                 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, cachedString
); 
1283                                                                 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n", 
1284                                                                                 this->getShortName(), (uintptr_t)location
, 
1285                                                                                 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, cachedString
, value
); 
1288                                                 value 
+= symbolAddr
; 
1290                                                 if ( reloc
->r_pcrel 
) { 
1291                                                         *location 
= value 
- ((uintptr_t)location 
+ 4); 
1294                                                         // don't dirty page if prebound value was correct 
1295                                                         if ( !prebound 
|| (*location 
!= value
) ) 
1299                                                 // don't dirty page if prebound value was correct 
1300                                                 if ( !prebound 
|| (*location 
!= value
) ) 
1304                                                 ++fgTotalBindFixups
; 
1308                                         throw "unknown external relocation type"; 
1312                         throw "bad external relocation length"; 
1316 #if TEXT_RELOC_SUPPORT 
1317         // if there were __TEXT fixups, restore write protection 
1318         if ( fTextSegmentBinds 
) { 
1319                 this->makeTextSegmentWritable(context
, true); 
1326 uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, const ImageLoader
* targetImage
, const LinkContext
& context
) 
1328         if ( context
.verboseBind 
) { 
1329                 const char* path 
= NULL
; 
1330                 if ( targetImage 
!= NULL 
) 
1331                         path 
= targetImage
->getShortName(); 
1332                 dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n", 
1333                                 this->getShortName(), symbolName
, (((sect
->flags 
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"), 
1334                                 ((path 
!= NULL
) ? path 
: "<weak_import-not-found>"), symbolName
, (uintptr_t)ptrToBind
, targetAddr
); 
1336         if ( context
.bindingHandler 
!= NULL 
) { 
1337                 const char* path 
= NULL
; 
1338                 if ( targetImage 
!= NULL 
) 
1339                         path 
= targetImage
->getShortName(); 
1340                 targetAddr 
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
); 
1343         // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32" 
1344         if ( ((sect
->flags 
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2 
== 5) ) { 
1345                 uint32_t rel32 
= targetAddr 
- (((uint32_t)ptrToBind
)+5); 
1346                 // re-write instruction in a thread-safe manner 
1347                 // use 8-byte compare-and-swap to alter 5-byte jump table entries 
1348                 // loop is required in case the extra three bytes that cover the next entry are altered by another thread 
1351                         volatile int64_t* jumpPtr 
= (int64_t*)ptrToBind
; 
1353                         // By default the three extra bytes swapped follow the 5-byte JMP. 
1354                         // But, if the 5-byte jump is up against the end of the __IMPORT segment 
1355                         // We don't want to access bytes off the end of the segment, so we shift 
1356                         // the extra bytes to precede the 5-byte JMP. 
1357                         if ( (((uint32_t)ptrToBind 
+ 8) & 0x00000FFC) == 0x00000000 ) { 
1358                                 jumpPtr 
= (int64_t*)((uint32_t)ptrToBind 
- 3); 
1361                         int64_t oldEntry 
= *jumpPtr
; 
1366                         newEntry
.int64 
= oldEntry
; 
1367                         newEntry
.bytes
[pad
+0] = 0xE9; // JMP rel32 
1368                         newEntry
.bytes
[pad
+1] = rel32 
& 0xFF; 
1369                         newEntry
.bytes
[pad
+2] = (rel32 
>> 8) & 0xFF; 
1370                         newEntry
.bytes
[pad
+3] = (rel32 
>> 16) & 0xFF; 
1371                         newEntry
.bytes
[pad
+4] = (rel32 
>> 24) & 0xFF; 
1372                         done 
= OSAtomicCompareAndSwap64Barrier(oldEntry
, newEntry
.int64
, (int64_t*)jumpPtr
); 
1377         *ptrToBind 
= targetAddr
; 
1381 uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset
, const LinkContext
& context
, void (*lock
)(), void (*unlock
)()) 
1383         throw "compressed LINKEDIT lazy binder called with classic LINKEDIT"; 
1386 uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
) 
1388         // scan for all lazy-pointer sections 
1389         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1390         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1391         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1392         const struct load_command
* cmd 
= cmds
; 
1393         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1394         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1396                         case LC_SEGMENT_COMMAND
: 
1398                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1399                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1400                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1401                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1402                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1403                                                 uint32_t symbolIndex 
= INDIRECT_SYMBOL_LOCAL
; 
1404                                                 if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
1405                                                         const uint32_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
1406                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1407                                                         if ( (lazyPointer 
>= symbolPointers
) && (lazyPointer 
< &symbolPointers
[pointerCount
]) ) { 
1408                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1409                                                                 const uint32_t lazyIndex 
= lazyPointer 
- symbolPointers
; 
1410                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ lazyIndex
]; 
1414                                                 else if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
1415                                                         // 5 bytes stubs on i386 are new "fast stubs" 
1416                                                         uint8_t* const jmpTableBase 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
1417                                                         uint8_t* const jmpTableEnd 
= jmpTableBase 
+ sect
->size
; 
1418                                                         // initial CALL instruction in jump table leaves pointer to next entry, so back up 
1419                                                         uint8_t* const jmpTableEntryToPatch 
= ((uint8_t*)lazyPointer
) - 5;   
1420                                                         lazyPointer 
= (uintptr_t*)jmpTableEntryToPatch
;  
1421                                                         if ( (jmpTableEntryToPatch 
>= jmpTableBase
) && (jmpTableEntryToPatch 
< jmpTableEnd
) ) { 
1422                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1423                                                                 const uint32_t entryIndex 
= (jmpTableEntryToPatch 
- jmpTableBase
)/5; 
1424                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ entryIndex
]; 
1428                                                 if ( symbolIndex 
!= INDIRECT_SYMBOL_ABS 
&& symbolIndex 
!= INDIRECT_SYMBOL_LOCAL 
) { 
1429                                                         const char* symbolName 
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
]; 
1430                                                         const ImageLoader
* image 
= NULL
; 
1431                                                         uintptr_t symbolAddr 
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, false, &image
); 
1432                                                         symbolAddr 
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
,  context
); 
1433                                                         ++fgTotalLazyBindFixups
; 
1440                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1442         dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer
, this->getPath()); 
1447 void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
) 
1450         it
.symbolName 
= " "; 
1451         it
.loadOrder 
= loadOrder
; 
1452         it
.weakSymbol 
= false; 
1453         it
.symbolMatches 
= false; 
1456         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1458                 it
.endIndex 
= fDynamicInfo
->ntoc
; 
1462                 it
.endIndex 
= fDynamicInfo
->nextdefsym
; 
1467 bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator
& it
) 
1472         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1473                 if ( it
.curIndex 
>= fDynamicInfo
->ntoc 
) { 
1475                         it
.symbolName 
= "~~~"; 
1479                         const dylib_table_of_contents
* toc 
= (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
]; 
1480                         const uint32_t index 
= toc
[it
.curIndex
].symbol_index
; 
1481                         const struct macho_nlist
* sym 
= &fSymbolTable
[index
]; 
1482                         const char* symStr 
= &fStrings
[sym
->n_un
.n_strx
]; 
1483                         it
.symbolName 
= symStr
; 
1484                         it
.weakSymbol 
= (sym
->n_desc 
& N_WEAK_DEF
); 
1485                         it
.symbolMatches 
= false; 
1486                         it
.type 
= 0; // clear flag that says we applied updates for this symbol 
1487                         //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath()); 
1493                 if ( it
.curIndex 
>= fDynamicInfo
->nextdefsym 
) { 
1495                         it
.symbolName 
= "~~~"; 
1499                         const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+it
.curIndex
]; 
1500                         const char* symStr 
= &fStrings
[sym
->n_un
.n_strx
]; 
1501                         it
.symbolName 
= symStr
; 
1502                         it
.weakSymbol 
= (sym
->n_desc 
& N_WEAK_DEF
); 
1503                         it
.symbolMatches 
= false; 
1504                         it
.type 
= 0; // clear flag that says we applied updates for this symbol 
1505                         //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath()); 
1514 uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
) 
1516         uint32_t symbol_index 
= 0; 
1517         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1518                 const dylib_table_of_contents
* toc 
= (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
]; 
1519                 symbol_index 
= toc
[it
.curIndex
-1].symbol_index
; 
1522                 symbol_index 
= fDynamicInfo
->iextdefsym
+it
.curIndex
-1; 
1524         const struct macho_nlist
* sym 
= &fSymbolTable
[symbol_index
]; 
1525         //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath()); 
1527                 // processor assumes code address with low bit set is thumb 
1528                 if (sym
->n_desc 
& N_ARM_THUMB_DEF
) 
1529                         return (sym
->n_value 
| 1) + fSlide 
; 
1531                         return sym
->n_value 
+ fSlide
; 
1533         return sym
->n_value 
+ fSlide
; 
1538 void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, const LinkContext
& context
) 
1540         // flat_namespace images with classic LINKEDIT do not need late coalescing. 
1541         // They still need to be iterated becuase they may implement 
1542         // something needed by other coalescing images. 
1543         // But they need no updating because during the bind phase every symbol lookup is a full scan. 
1544         if ( !this->usesTwoLevelNameSpace() ) 
1547         // <rdar://problem/6570879> weak binding done too early with inserted libraries 
1548         if ( this->getState() < dyld_image_state_bound  
) 
1551         uint32_t symbol_index 
= 0; 
1552         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1553                 const dylib_table_of_contents
* toc 
= (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
]; 
1554                 symbol_index 
= toc
[it
.curIndex
-1].symbol_index
; 
1557                 symbol_index 
= fDynamicInfo
->iextdefsym
+it
.curIndex
-1; 
1560         // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here 
1561         if ( !symbolIsWeakReference(&fSymbolTable
[symbol_index
]) && !symbolIsWeakDefinition(&fSymbolTable
[symbol_index
]) ) { 
1565         // <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding 
1569         bool boundSomething 
= false; 
1570         // scan external relocations for uses of symbol_index 
1571         const uintptr_t relocBase 
= this->getRelocBase(); 
1572         const bool prebound 
= this->isPrebindable(); 
1573         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
1574         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
1575         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1576                 if ( reloc
->r_symbolnum 
== symbol_index 
) { 
1577                         //dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath()); 
1578                         const struct macho_nlist
* undefinedSymbol 
= &fSymbolTable
[reloc
->r_symbolnum
]; 
1579                         const char* symbolName 
= &fStrings
[undefinedSymbol
->n_un
.n_strx
]; 
1580                         uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
1581                         const uintptr_t initialValue 
= *location
; 
1582                         uintptr_t addend 
= 0; 
1584                                 // we are doing relocations, so prebinding was not usable 
1585                                 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 
1586                                 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 
1587                                 // if mach-o relocation structs had an "addend" field this complication would not be necessary. 
1588                                 if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1589                                         // weak symbols need special casing, since *location may have been prebound to a definition in another image. 
1590                                         // If *location is currently prebound to somewhere in the same section as the weak definition, we assume  
1591                                         // that we can subtract off the weak symbol address to get the addend. 
1592                                         // If prebound elsewhere, we've lost the addend and have to assume it is zero. 
1593                                         // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 
1594                                         if ( (initialValue 
== undefinedSymbol
->n_value
) || this->isAddrInSection(initialValue
, undefinedSymbol
->n_sect
) ) { 
1595                                                 addend 
= initialValue 
- undefinedSymbol
->n_value
; 
1597                                                 // if weak and thumb subtract off extra thumb bit 
1598                                                 if ( (undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0 ) 
1604                                 else if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0) ) { 
1605                                         // it was prebound to a defined symbol for thumb code in the same linkage unit 
1606                                         // we need to subtract off one to get real addend 
1607                                         addend 
= initialValue 
- (undefinedSymbol
->n_value
+1); 
1611                                         // is undefined or non-weak symbol, so do subtraction to get addend 
1612                                         addend 
= initialValue 
- undefinedSymbol
->n_value
; 
1616                                 // non-prebound case 
1617                                 if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1618                                         // if target is weak-def in same linkage unit, then bind phase has already set initialValue  
1619                                         // to be definition address plus addend 
1620                                         //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide); 
1621                                         addend 
= initialValue 
- (undefinedSymbol
->n_value 
+ fSlide
); 
1623                                         // if weak and thumb subtract off extra thumb bit 
1624                                         if ( (undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0 ) 
1629                                         // nothing fixed up yet, addend is just initial value 
1630                                         //dyld::log("addend=0x%lX\n", initialValue); 
1631                                         addend 
= initialValue
; 
1635                         uint8_t type 
= BIND_TYPE_POINTER
; 
1637                         if ( reloc
->r_pcrel 
)  
1638                                 type 
= BIND_TYPE_TEXT_PCREL32
; 
1640                         this->bindLocation(context
, (uintptr_t)location
, value
, targetImage
, type
, symbolName
, addend
, "weak "); 
1641                         boundSomething 
= true; 
1645         // scan lazy and non-lazy pointers for uses of symbol_index 
1646         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1647         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1648         const struct load_command
* cmd 
= cmds
; 
1649         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1650         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1651                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1652                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1653                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1654                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1655                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1656                                 uint32_t elementSize 
= sizeof(uintptr_t); 
1657                                 switch ( sect
->flags 
& SECTION_TYPE 
) { 
1659                                         case S_SYMBOL_STUBS
: 
1660                                                 if ( ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) ==0) || (sect
->reserved2 
!= 5) ) 
1664                                         case S_NON_LAZY_SYMBOL_POINTERS
: 
1665                                         case S_LAZY_SYMBOL_POINTERS
: 
1667                                                 uint32_t elementCount 
= sect
->size 
/ elementSize
; 
1668                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1669                                                 uint8_t* ptrToBind 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
1670                                                 //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind); 
1671                                                 for (uint32_t j
=0; j 
< elementCount
; ++j
, ptrToBind 
+= elementSize
) { 
1672                                                         if ( indirectTable
[indirectTableOffset 
+ j
] == symbol_index 
) { 
1673                                                                 //dyld::log("  found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind); 
1675                                                                 this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, it
.symbolName
, value
, targetImage
, context
); 
1676                                                                 boundSomething 
= true; 
1684                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1686         if ( boundSomething 
&& (targetImage 
!= this) ) { 
1687                 context
.addDynamicReference(this, targetImage
); 
1690         // mark that this symbol has already been bound, so we don't try to bind again 
1695 void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext
& context
, bool bindNonLazys
, bool bindLazys
) 
1697         // scan for all non-lazy-pointer sections  
1698         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1699         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1700         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1701         const struct load_command
* cmd 
= cmds
; 
1702         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1703         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1705                         case LC_SEGMENT_COMMAND
: 
1707                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1708                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1709                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1710                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1711                                                 bool isLazySymbol 
= false; 
1712                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1713                                                 uint32_t elementSize 
= sizeof(uintptr_t); 
1714                                                 uint32_t elementCount 
= sect
->size 
/ elementSize
; 
1715                                                 if ( type 
== S_NON_LAZY_SYMBOL_POINTERS 
) { 
1716                                                         if ( ! bindNonLazys 
) 
1719                                                 else if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
1720                                                         // process each symbol pointer in this section 
1721                                                         fgTotalPossibleLazyBindFixups 
+= elementCount
; 
1722                                                         isLazySymbol 
= true; 
1727                                                 else if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
1728                                                         // process each jmp entry in this section 
1729                                                         elementCount 
= sect
->size 
/ 5; 
1731                                                         fgTotalPossibleLazyBindFixups 
+= elementCount
; 
1732                                                         isLazySymbol 
= true; 
1740                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1741                                                 uint8_t* ptrToBind 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
1742                                                 for (uint32_t j
=0; j 
< elementCount
; ++j
, ptrToBind 
+= elementSize
) { 
1743                                 #if LINKEDIT_USAGE_DEBUG 
1744                                                         noteAccessedLinkEditAddress(&indirectTable
[indirectTableOffset 
+ j
]); 
1746                                                         uint32_t symbolIndex 
= indirectTable
[indirectTableOffset 
+ j
]; 
1747                                                         if ( symbolIndex 
== INDIRECT_SYMBOL_LOCAL
) { 
1748                                                                 *((uintptr_t*)ptrToBind
) += this->fSlide
; 
1750                                                         else if ( symbolIndex 
== INDIRECT_SYMBOL_ABS
) { 
1751                                                                 // do nothing since already has absolute address 
1754                                                                 const struct macho_nlist
* sym 
= &fSymbolTable
[symbolIndex
]; 
1755                                                                 if ( symbolIndex 
== 0 ) { 
1756                                                                         // This could be rdar://problem/3534709  
1757                                                                         if ( ((const macho_header
*)fMachOData
)->filetype 
== MH_EXECUTE 
) { 
1758                                                                                 static bool alreadyWarned 
= false; 
1759                                                                                 if ( (sym
->n_type 
& N_TYPE
) != N_UNDF 
) { 
1760                                                                                         // The indirect table parallels the (non)lazy pointer sections.  For 
1761                                                                                         // instance, to find info about the fifth lazy pointer you look at the 
1762                                                                                         // fifth entry in the indirect table.  (try otool -Iv on a file). 
1763                                                                                         // The entry in the indirect table contains an index into the symbol table. 
1765                                                                                         // The bug in ld caused the entry in the indirect table to be zero 
1766                                                                                         // (instead of a magic value that means a local symbol).  So, if the 
1767                                                                                         // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid 
1768                                                                                         // symbol table index. The check I put in place is to see if the zero'th 
1769                                                                                         // symbol table entry is an import entry (usually it is a local symbol 
1771                                                                                         if ( context
.verboseWarnings 
&& !alreadyWarned 
) { 
1772                                                                                                 dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n", 
1773                                                                                                                 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]); 
1774                                                                                                 alreadyWarned 
= true; 
1780                                                                 const ImageLoader
* image 
= NULL
; 
1781                                                                 // let weak definitions resolve to themselves, later coalescing may overwrite them 
1782                                                                 bool dontCoalesce 
= true; 
1783                                                                 if ( bindLazys 
&& isLazySymbol 
) { 
1784                                                                         // if this is something normally lazy bound, but we are forcing 
1785                                                                         // it to be bound now, do coalescing 
1786                                                                         dontCoalesce 
= false; 
1788                                                                 if ( symbolIsWeakReference(sym
) ) {  
1789                                                                         // when weakbind() is run on a classic mach-o encoding, it won't try 
1790                                                                         // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted 
1791                                                                         // range of global symbols.  To handle that case we do the coalesing now. 
1792                                                                         dontCoalesce 
= false; 
1794                                                                 uintptr_t symbolAddr 
= resolveUndefined(context
, sym
, twoLevel
, dontCoalesce
, &image
); 
1796                                                                 symbolAddr 
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
,  context
); 
1798                                                                 ++fgTotalBindFixups
; 
1805                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1812 void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext
& context
) 
1814         if ( ! this->usablePrebinding(context
) ) { 
1815                 // reset all "fast" stubs 
1816                 const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1817                 const uint32_t cmd_count 
= mh
->ncmds
; 
1818                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1819                 const struct load_command
* cmd 
= cmds
; 
1820                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1822                                 case LC_SEGMENT_COMMAND
: 
1824                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1825                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1826                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1827                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1828                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1829                                                 if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
1830                                                         // reset each jmp entry in this section 
1831                                                         const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1832                                                         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1833                                                         uint8_t* start 
= (uint8_t*)(sect
->addr 
+ this->fSlide
); 
1834                                                         uint8_t* end 
= start 
+ sect
->size
; 
1835                                                         uintptr_t dyldHandler 
= (uintptr_t)&fast_stub_binding_helper_interface
; 
1836                                                         uint32_t entryIndex 
= 0; 
1837                                                         for (uint8_t* entry 
= start
; entry 
< end
; entry 
+= 5, ++entryIndex
) { 
1838                                                                 bool installLazyHandler 
= true; 
1839                                                                 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes 
1840                                                                 // if the instruction is updated by one thread while being executed by another 
1841                                                                 if ( ((uint32_t)entry 
& 0xFFFFFFC0) != ((uint32_t)entry
+4 & 0xFFFFFFC0) ) { 
1842                                                                         // need to bind this now to avoid a potential problem if bound lazily 
1843                                                                         uint32_t symbolIndex 
= indirectTable
[indirectTableOffset 
+ entryIndex
]; 
1844                                                                         // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used 
1845                                                                         if ( symbolIndex 
!= INDIRECT_SYMBOL_ABS 
) { 
1846                                                                                 const char* symbolName 
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
]; 
1847                                                                                 const ImageLoader
* image 
= NULL
; 
1849                                                                                         uintptr_t symbolAddr 
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], this->usesTwoLevelNameSpace(), false, &image
); 
1850                                                                                         symbolAddr 
= this->bindIndirectSymbol((uintptr_t*)entry
, sect
, symbolName
, symbolAddr
, image
, context
); 
1851                                                                                         ++fgTotalBindFixups
; 
1852                                                                                         uint32_t rel32 
= symbolAddr 
- (((uint32_t)entry
)+5); 
1853                                                                                         entry
[0] = 0xE9; // JMP rel32 
1854                                                                                         entry
[1] = rel32 
& 0xFF; 
1855                                                                                         entry
[2] = (rel32 
>> 8) & 0xFF; 
1856                                                                                         entry
[3] = (rel32 
>> 16) & 0xFF; 
1857                                                                                         entry
[4] = (rel32 
>> 24) & 0xFF; 
1858                                                                                         installLazyHandler 
= false; 
1860                                                                                 catch (const char* msg
) { 
1861                                                                                         // ignore errors when binding symbols early 
1862                                                                                         // maybe the function is never called, and therefore erroring out now would be a regression 
1866                                                                 if ( installLazyHandler 
) { 
1867                                                                         uint32_t rel32 
= dyldHandler 
- (((uint32_t)entry
)+5); 
1868                                                                         entry
[0] = 0xE8; // CALL rel32 
1869                                                                         entry
[1] = rel32 
& 0xFF; 
1870                                                                         entry
[2] = (rel32 
>> 8) & 0xFF; 
1871                                                                         entry
[3] = (rel32 
>> 16) & 0xFF; 
1872                                                                         entry
[4] = (rel32 
>> 24) & 0xFF; 
1879                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1886 void ImageLoaderMachOClassic::doBind(const LinkContext
& context
, bool forceLazysBound
) 
1888         CRSetCrashLogMessage2(this->getPath()); 
1890         this->initializeLazyStubs(context
); 
1893         // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 
1894         // note: flat-namespace binaries need to have imports rebound (even if correctly prebound) 
1895         if ( this->usablePrebinding(context
) ) { 
1896                 // binding already up to date 
1899                 // no valid prebinding, so bind symbols. 
1900                 // values bound by name are stored two different ways in classic mach-o: 
1902         #if TEXT_RELOC_SUPPORT 
1903                 // if there are __TEXT fixups, temporarily make __TEXT writable 
1904                 if ( fTextSegmentBinds 
)  
1905                         this->makeTextSegmentWritable(context
, true); 
1908                 // 1) external relocations are used for data initialized to external symbols 
1909                 this->doBindExternalRelocations(context
); 
1911                 // 2) "indirect symbols" are used for code references to external symbols 
1912                 // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now 
1913                 this->bindIndirectSymbolPointers(context
, true, forceLazysBound 
|| fInSharedCache
); 
1915         #if TEXT_RELOC_SUPPORT 
1916                 // if there were __TEXT fixups, restore write protection 
1917                 if ( fTextSegmentBinds 
)  
1918                         this->makeTextSegmentWritable(context
, false); 
1922         // set up dyld entry points in image 
1923         this->setupLazyPointerHandler(context
); 
1925         CRSetCrashLogMessage2(NULL
); 
1928 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext
& context
) 
1930         // some API called requested that all lazy pointers in this image be force bound 
1931         this->bindIndirectSymbolPointers(context
, false, true); 
1934 void ImageLoaderMachOClassic::doInterpose(const LinkContext
& context
) 
1936         if ( context
.verboseInterposing 
) 
1937                 dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples
.size(), this->getPath()); 
1939         // scan indirect symbols 
1940         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1941         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1942         const struct load_command
* cmd 
= cmds
; 
1943         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1945                         case LC_SEGMENT_COMMAND
: 
1947                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1948                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1949                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1950                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1951                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1952                                                 if ( (type 
== S_NON_LAZY_SYMBOL_POINTERS
) || (type 
== S_LAZY_SYMBOL_POINTERS
) ) { 
1953                                                         const uint32_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
1954                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1955                                                         for (uint32_t pointerIndex
=0; pointerIndex 
< pointerCount
; ++pointerIndex
) { 
1956                                                                 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
1957                                                                         // replace all references to 'replacee' with 'replacement' 
1958                                                                         if ( (symbolPointers
[pointerIndex
] == it
->replacee
) && (this != it
->replacementImage
) ) { 
1959                                                                                 if ( context
.verboseInterposing 
) { 
1960                                                                                         dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n",  
1961                                                                                                 &symbolPointers
[pointerIndex
], it
->replacee
, it
->replacement
, this->getPath()); 
1963                                                                                 symbolPointers
[pointerIndex
] = it
->replacement
; 
1969                                                 // i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking 
1970                                                 else if ( (type 
== S_SYMBOL_STUBS
) && ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2 
== 5) ) { 
1971                                                         // check each jmp entry in this section 
1972                                                         uint8_t* start 
= (uint8_t*)(sect
->addr 
+ this->fSlide
); 
1973                                                         uint8_t* end 
= start 
+ sect
->size
; 
1974                                                         for (uint8_t* entry 
= start
; entry 
< end
; entry 
+= 5) { 
1975                                                                 if ( entry
[0] == 0xE9 ) { // 0xE9 == JMP  
1976                                                                         uint32_t rel32 
= *((uint32_t*)&entry
[1]); // assume unaligned load of uint32_t is ok 
1977                                                                         uint32_t target 
= (uint32_t)&entry
[5] + rel32
; 
1978                                                                         for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
1979                                                                                 // replace all references to 'replacee' with 'replacement' 
1980                                                                                 if ( (it
->replacee 
== target
) && (this != it
->replacementImage
) ) { 
1981                                                                                         if ( context
.verboseInterposing 
) { 
1982                                                                                                 dyld::log("dyld: interposing: at %p replace JMP 0x%lX with JMP 0x%lX in %s\n",  
1983                                                                                                         &entry
[1], it
->replacee
, it
->replacement
, this->getPath()); 
1985                                                                                         uint32_t newRel32 
= it
->replacement 
- (uint32_t)&entry
[5]; 
1986                                                                                         *((uint32_t*)&entry
[1]) = newRel32
; // assume unaligned store of uint32_t is ok 
1997                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2000         // scan external relocations  
2001         const uintptr_t relocBase 
= this->getRelocBase(); 
2002         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
2003         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
2004         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
2005                 if (reloc
->r_length 
== RELOC_SIZE
) { 
2006                         switch(reloc
->r_type
) { 
2009                                                 uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
2010                                                 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
2011                                                         // replace all references to 'replacee' with 'replacement' 
2012                                                         if ( (*location 
== it
->replacee
) && (this != it
->replacementImage
) ) { 
2013                                                                 if ( context
.verboseInterposing 
) { 
2014                                                                         dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n",  
2015                                                                                 location
, it
->replacee
, it
->replacement
, this->getPath()); 
2017                                                                 *location 
= it
->replacement
; 
2028 const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr
, const void** closestAddr
) const 
2030         uintptr_t targetAddress 
= (uintptr_t)addr 
- fSlide
; 
2031         const struct macho_nlist
* bestSymbol 
= NULL
; 
2032         // first walk all global symbols 
2033         const struct macho_nlist
* const globalsStart 
= &fSymbolTable
[fDynamicInfo
->iextdefsym
]; 
2034         const struct macho_nlist
* const globalsEnd
= &globalsStart
[fDynamicInfo
->nextdefsym
]; 
2035         for (const struct macho_nlist
* s 
= globalsStart
; s 
< globalsEnd
; ++s
) { 
2036                 if ( (s
->n_type 
& N_TYPE
) == N_SECT 
) { 
2037                         if ( bestSymbol 
== NULL 
) { 
2038                                 if ( s
->n_value 
<= targetAddress 
) 
2041                         else if ( (s
->n_value 
<= targetAddress
) && (bestSymbol
->n_value 
< s
->n_value
) ) { 
2046         // next walk all local symbols 
2047         const struct macho_nlist
* const localsStart 
= &fSymbolTable
[fDynamicInfo
->ilocalsym
]; 
2048         const struct macho_nlist
* const localsEnd
= &localsStart
[fDynamicInfo
->nlocalsym
]; 
2049         for (const struct macho_nlist
* s 
= localsStart
; s 
< localsEnd
; ++s
) { 
2050                 if ( ((s
->n_type 
& N_TYPE
) == N_SECT
) && ((s
->n_type 
& N_STAB
) == 0) ) { 
2051                         if ( bestSymbol 
== NULL 
) { 
2052                                 if ( s
->n_value 
<= targetAddress 
) 
2055                         else if ( (s
->n_value 
<= targetAddress
) && (bestSymbol
->n_value 
< s
->n_value
) ) { 
2060         if ( bestSymbol 
!= NULL 
) { 
2062                 if (bestSymbol
->n_desc 
& N_ARM_THUMB_DEF
) 
2063                         *closestAddr 
= (void*)((bestSymbol
->n_value 
| 1) + fSlide
); 
2065                         *closestAddr 
= (void*)(bestSymbol
->n_value 
+ fSlide
); 
2067                 *closestAddr 
= (void*)(bestSymbol
->n_value 
+ fSlide
); 
2069                 return &fStrings
[bestSymbol
->n_un
.n_strx
];