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 stub_binding_helper_i386_old(); 
  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
->disableCoverageCheck(); 
 102         image
->instantiateFinish(context
); 
 103         image
->setMapped(context
); 
 106         // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding 
 107         if ( image
->fReadOnlyImportSegment 
) { 
 108                 for(unsigned int i
=0; i 
< image
->fSegmentsCount
; ++i
) { 
 109                         if ( image
->segIsReadOnlyImport(i
) ) 
 110                                 image
->segMakeWritable(i
, context
); 
 115         if ( context
.verboseMapping 
) { 
 116                 dyld::log("dyld: Main executable mapped %s\n", path
); 
 117                 for(unsigned int i
=0, e
=image
->segmentCount(); i 
< e
; ++i
) { 
 118                         const char* name 
= image
->segName(i
); 
 119                         if ( (strcmp(name
, "__PAGEZERO") == 0) || (strcmp(name
, "__UNIXSTACK") == 0)  ) 
 120                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segPreferredLoadAddress(i
), image
->segPreferredLoadAddress(i
)+image
->segSize(i
)); 
 122                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", name
, image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
)); 
 129 // create image by mapping in a mach-o file 
 130 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateFromFile(const char* path
, int fd
, const uint8_t* fileData
, size_t lenFileData
, 
 131                                                                                                                         uint64_t offsetInFat
, uint64_t lenInFat
, const struct stat
& info
,  
 132                                                                                                                         unsigned int segCount
, unsigned int libCount
,  
 133                                                                                                                         const struct linkedit_data_command
* codeSigCmd
, const LinkContext
& context
) 
 135         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart((macho_header
*)fileData
, path
, segCount
, libCount
); 
 137                 // record info about file   
 138                 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
); 
 140                 // if this image is code signed, let kernel validate signature before mapping any pages from image 
 141                 image
->loadCodeSignature(codeSigCmd
, fd
, offsetInFat
, context
); 
 143                 // Validate that first data we read with pread actually matches with code signature 
 144                 image
->validateFirstPages(codeSigCmd
, fd
, fileData
, lenFileData
, offsetInFat
, context
); 
 147                 image
->mapSegmentsClassic(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
); 
 150                 image
->instantiateFinish(context
); 
 152                 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path 
 153                 const char* installName 
= image
->getInstallPath(); 
 154                 if ( (installName 
!= NULL
) && (strcmp(installName
, path
) == 0) && (path
[0] == '/') ) 
 155                         image
->setPathUnowned(installName
); 
 156                 else if ( (path
[0] != '/') || (strstr(path
, "../") != NULL
) ) { 
 157                         // rdar://problem/10733082 Fix up @path based paths during introspection 
 158                         // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them 
 159                         char realPath
[MAXPATHLEN
]; 
 160                         if ( fcntl(fd
, F_GETPATH
, realPath
) == 0 )  
 161                                 image
->setPaths(path
, realPath
); 
 163                                 image
->setPath(path
); 
 166                         image
->setPath(path
); 
 168                 // make sure path is stable before recording in dyld_all_image_infos 
 169                 image
->setMapped(context
); 
 171                 // pre-fetch content of __DATA segment for faster launches 
 172                 // don't do this on prebound images or if prefetching is disabled 
 173         if ( !context
.preFetchDisabled 
&& !image
->isPrebindable()) 
 174                         image
->preFetchDATA(fd
, offsetInFat
, context
); 
 178                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 179                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 187 // create image by using cached mach-o file 
 188 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, 
 189                                                                                                                                 unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
 191         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart(mh
, path
, segCount
, libCount
); 
 193                 // record info about file   
 194                 image
->setFileInfo(info
.st_dev
, info
.st_ino
, info
.st_mtime
); 
 196                 // remember this is from shared cache and cannot be unloaded 
 197                 image
->fInSharedCache 
= true; 
 198                 image
->setNeverUnload(); 
 199                 image
->disableCoverageCheck(); 
 201                 // segments already mapped in cache 
 202                 if ( context
.verboseMapping 
) { 
 203                         dyld::log("dyld: Using shared cached for %s\n", path
); 
 204                         for(unsigned int i
=0, e
=image
->segmentCount(); i 
< e
; ++i
) { 
 205                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", image
->segName(i
), image
->segActualLoadAddress(i
), image
->segActualEndAddress(i
)); 
 209                 image
->instantiateFinish(context
); 
 210                 image
->setMapped(context
); 
 213                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 214                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 222 // create image by copying an in-memory mach-o file 
 223 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
,  
 224                                                                                                                         unsigned int segCount
, unsigned int libCount
, const LinkContext
& context
) 
 226         ImageLoaderMachOClassic
* image 
= ImageLoaderMachOClassic::instantiateStart(mh
, moduleName
, segCount
, libCount
); 
 229                 if ( mh
->filetype 
== MH_EXECUTE 
)  
 230                         throw "can't load another MH_EXECUTE"; 
 233                 image
->ImageLoaderMachO::mapSegments((const void*)mh
, len
, context
); 
 235                 // for compatibility, never unload dylibs loaded from memory 
 236                 image
->setNeverUnload(); 
 238                 image
->disableCoverageCheck(); 
 240                 // bundle loads need path copied 
 241                 if ( moduleName 
!= NULL 
)  
 242                         image
->setPath(moduleName
); 
 244                 image
->instantiateFinish(context
); 
 245                 image
->setMapped(context
); 
 248                 // ImageLoader::setMapped() can throw an exception to block loading of image 
 249                 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 
 258 ImageLoaderMachOClassic::ImageLoaderMachOClassic(const macho_header
* mh
, const char* path
,  
 259                                                                                                         unsigned int segCount
, uint32_t segOffsets
[], unsigned int libCount
) 
 260  : ImageLoaderMachO(mh
, path
, segCount
, segOffsets
, libCount
), fStrings(NULL
), fSymbolTable(NULL
), fDynamicInfo(NULL
) 
 264 // construct ImageLoaderMachOClassic using "placement new" with SegmentMachO objects array at end 
 265 ImageLoaderMachOClassic
* ImageLoaderMachOClassic::instantiateStart(const macho_header
* mh
, const char* path
, 
 266                                                                                                                                                 unsigned int segCount
, unsigned int libCount
) 
 268         size_t size 
= sizeof(ImageLoaderMachOClassic
) + segCount 
* sizeof(uint32_t) + libCount 
* sizeof(ImageLoader
*); 
 269         ImageLoaderMachOClassic
* allocatedSpace 
= static_cast<ImageLoaderMachOClassic
*>(malloc(size
)); 
 270         if ( allocatedSpace 
== NULL 
) 
 271                 throw "malloc failed"; 
 272         uint32_t* segOffsets 
= ((uint32_t*)(((uint8_t*)allocatedSpace
) + sizeof(ImageLoaderMachOClassic
))); 
 273         bzero(&segOffsets
[segCount
], libCount
*sizeof(void*));   // zero out lib array 
 274         return new (allocatedSpace
) ImageLoaderMachOClassic(mh
, path
, segCount
, segOffsets
, libCount
); 
 279 // common code to finish initializing object 
 280 void ImageLoaderMachOClassic::instantiateFinish(const LinkContext
& context
) 
 282         // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 
 283         this->parseLoadCmds(context
); 
 286 ImageLoaderMachOClassic::~ImageLoaderMachOClassic() 
 288         // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work 
 292 uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const 
 294         return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
))); 
 298 ImageLoader
* ImageLoaderMachOClassic::libImage(unsigned int libIndex
) const 
 300         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 302         return (ImageLoader
*)(images
[libIndex
] & (-4)); 
 305 bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex
) const 
 307         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 308         // re-export flag is low bit 
 309         return ((images
[libIndex
] & 1) != 0); 
 312 bool ImageLoaderMachOClassic::libIsUpward(unsigned int libIndex
) const 
 314         const uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 315         // upward flag is second bit 
 316         return ((images
[libIndex
] & 2) != 0); 
 320 void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex
, ImageLoader
* image
, bool reExported
, bool upward
) 
 322         uintptr_t* images 
= ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic
) + fSegmentsCount
*sizeof(uint32_t))); 
 323         uintptr_t value 
= (uintptr_t)image
; 
 328         images
[libIndex
] = value
; 
 332 void ImageLoaderMachOClassic::setSymbolTableInfo(const macho_nlist
* symbols
, const char* strings
, const dysymtab_command
* dynSym
) 
 334         fSymbolTable 
= symbols
; 
 336         fDynamicInfo 
= dynSym
; 
 339 void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext
& context
) 
 341         // always prefetch a subrange of __LINKEDIT pages 
 342         uintptr_t symbolTableStart 
= (uintptr_t)fSymbolTable
; 
 343         uintptr_t stringTableStart 
= (uintptr_t)fStrings
; 
 345         // if image did not load at preferred address 
 346         if ( segPreferredLoadAddress(0) != (uintptr_t)fMachOData 
) { 
 347                 // local relocations will be processed, so start pre-fetch at local symbols 
 348                 start 
= (uintptr_t)fMachOData 
+ fDynamicInfo
->locreloff
; 
 351                 // otherwise start pre-fetch at global symbols section of symbol table 
 352                 start 
= symbolTableStart 
+ fDynamicInfo
->iextdefsym 
* sizeof(macho_nlist
); 
 354         // prefetch ends at end of last undefined string in string pool 
 355         uintptr_t end 
= stringTableStart
; 
 356         if ( fDynamicInfo
->nundefsym 
!= 0 ) 
 357                 end 
+= fSymbolTable
[fDynamicInfo
->iundefsym
+fDynamicInfo
->nundefsym
-1].n_un
.n_strx
; 
 358         else if ( fDynamicInfo
->nextdefsym 
!= 0 ) 
 359                 end 
+= fSymbolTable
[fDynamicInfo
->iextdefsym
+fDynamicInfo
->nextdefsym
-1].n_un
.n_strx
; 
 361         // round to whole pages 
 362         start 
= dyld_page_trunc(start
); 
 363         end 
= dyld_page_round(end
); 
 365         // skip if there is only one page 
 366         if ( (end
-start
) > dyld_page_size 
) { 
 367                 madvise((void*)start
, end
-start
, MADV_WILLNEED
); 
 368                 fgTotalBytesPreFetched 
+= (end
-start
); 
 369                 if ( context
.verboseMapping 
) { 
 370                         dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", "__LINKEDIT", start
, end
-1); 
 376 #if SPLIT_SEG_DYLIB_SUPPORT      
 378 ImageLoaderMachOClassic::getExtraZeroFillEntriesCount() 
 380         // calculate mapping entries 
 381         unsigned int extraZeroFillEntries 
= 0; 
 382         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 383                 if ( segHasTrailingZeroFill(i
) ) 
 384                         ++extraZeroFillEntries
; 
 387         return extraZeroFillEntries
; 
 391 ImageLoaderMachOClassic::initMappingTable(uint64_t offsetInFat
, 
 392                                                                    shared_file_mapping_np 
*mappingTable
) 
 394         for(unsigned int i
=0,entryIndex
=0; i 
< fSegmentsCount
; ++i
, ++entryIndex
) { 
 395                 shared_file_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 396                 entry
->sfm_address                      
= segActualLoadAddress(i
); 
 397                 entry
->sfm_size                         
= segFileSize(i
); 
 398                 entry
->sfm_file_offset          
= segFileOffset(i
) + offsetInFat
; 
 399                 entry
->sfm_init_prot            
= VM_PROT_NONE
; 
 400                 if ( !segUnaccessible(i
) ) { 
 401                         if ( segExecutable(i
) ) 
 402                                 entry
->sfm_init_prot   
|= VM_PROT_EXECUTE
; 
 403                         if ( segReadable(i
) ) 
 404                                 entry
->sfm_init_prot   
|= VM_PROT_READ
; 
 405                         if ( segWriteable(i
) ) 
 406                                 entry
->sfm_init_prot   
|= VM_PROT_WRITE 
| VM_PROT_COW
; 
 408                 entry
->sfm_max_prot                     
= entry
->sfm_init_prot
; 
 409                 if ( segHasTrailingZeroFill(i
) ) { 
 410                         shared_file_mapping_np
* zfentry 
= &mappingTable
[++entryIndex
]; 
 411                         zfentry
->sfm_address            
= entry
->sfm_address 
+ segFileSize(i
); 
 412                         zfentry
->sfm_size                       
= segSize(i
) - segFileSize(i
); 
 413                         zfentry
->sfm_file_offset        
= 0; 
 414                         zfentry
->sfm_init_prot          
= entry
->sfm_init_prot 
| VM_PROT_COW 
| VM_PROT_ZF
; 
 415                         zfentry
->sfm_max_prot           
= zfentry
->sfm_init_prot
; 
 421 ImageLoaderMachOClassic::mapSplitSegDylibOutsideSharedRegion(int fd
, 
 422                                                                                                         uint64_t offsetInFat
, 
 425                                                                                                         const LinkContext
& context
) 
 427         uintptr_t nextAltLoadAddress 
= 0; 
 428         const unsigned int segmentCount 
= fSegmentsCount
; 
 429         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 430         const unsigned int regionCount 
= segmentCount
+extraZeroFillEntries
; 
 431         shared_file_mapping_np regions
[regionCount
]; 
 432         initMappingTable(offsetInFat
, regions
); 
 434         // find space somewhere to allocate split seg 
 435         bool foundRoom 
= false; 
 436         while ( ! foundRoom 
) { 
 438                 for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 439                         vm_address_t addr 
= (vm_address_t
)(nextAltLoadAddress 
+ regions
[i
].sfm_address 
- regions
[0].sfm_address
); 
 440                         vm_size_t size 
= (vm_size_t
)regions
[i
].sfm_size 
; 
 441                         r 
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/); 
 443                                 // no room here, deallocate what has succeeded so far 
 444                                 for(unsigned int j
=0; j 
< i
; ++j
) { 
 445                                         addr 
= (vm_address_t
)(nextAltLoadAddress 
+ regions
[j
].sfm_address 
- regions
[0].sfm_address
); 
 446                                         size 
= (vm_size_t
)(regions
[j
].sfm_size
); 
 447                                         (void)vm_deallocate(mach_task_self(), addr
, size
); 
 449                                 nextAltLoadAddress 
+= 0x00100000;  // skip ahead 1MB and try again 
 450                                 // skip over shared region 
 451                                 if ( (SHARED_REGION_BASE 
<= nextAltLoadAddress
) && (nextAltLoadAddress 
< (SHARED_REGION_BASE 
+ SHARED_REGION_SIZE
)) ) 
 452                                         nextAltLoadAddress 
= (SHARED_REGION_BASE 
+ SHARED_REGION_SIZE
); 
 453                                 if ( nextAltLoadAddress 
> 0xFF000000 ) 
 454                                         throw "can't map split seg anywhere"; 
 461         // map in each region 
 462         uintptr_t slide 
= (uintptr_t)(nextAltLoadAddress 
- regions
[0].sfm_address
); 
 463         this->setSlide(slide
); 
 464         for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 465                 if ( ((regions
[i
].sfm_init_prot 
& VM_PROT_ZF
) != 0) || (regions
[i
].sfm_size 
== 0) ) { 
 466                         // nothing to mmap for zero-fills areas, they are just vm_allocated  
 469                         void* mmapAddress 
= (void*)(uintptr_t)(regions
[i
].sfm_address 
+ slide
); 
 470                         size_t size 
= (size_t)regions
[i
].sfm_size
; 
 472                         if ( regions
[i
].sfm_init_prot 
& VM_PROT_EXECUTE 
) 
 473                                 protection   
|= PROT_EXEC
; 
 474                         if ( regions
[i
].sfm_init_prot 
& VM_PROT_READ 
) 
 475                                 protection   
|= PROT_READ
; 
 476                         if ( regions
[i
].sfm_init_prot 
& VM_PROT_WRITE 
) 
 477                                 protection   
|= PROT_WRITE
; 
 478                         off_t offset 
= regions
[i
].sfm_file_offset
; 
 479                         //dyld::log("mmap(%p, 0x%08lX, %s\n", mmapAddress, size, fPath); 
 480                         mmapAddress 
= mmap(mmapAddress
, size
, protection
, MAP_FIXED 
| MAP_PRIVATE
, fd
, offset
); 
 481                         if ( mmapAddress 
== ((void*)(-1)) ) 
 487         if ( context
.verboseMapping 
) { 
 488                 dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath()); 
 489                 for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 490                         const shared_file_mapping_np
* entry 
= ®ions
[entryIndex
]; 
 491                         if ( (entry
->sfm_init_prot 
& VM_PROT_ZF
) == 0 )  
 492                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", 
 493                                                 segName(segIndex
), segActualLoadAddress(segIndex
), segActualEndAddress(segIndex
)-1); 
 494                         if ( entryIndex 
< (regionCount
-1) ) { 
 495                                 const shared_file_mapping_np
* nextEntry 
= ®ions
[entryIndex
+1]; 
 496                                 if ( (nextEntry
->sfm_init_prot 
& VM_PROT_ZF
) != 0 ) { 
 497                                         uint64_t segOffset 
= nextEntry
->sfm_address 
- entry
->sfm_address
; 
 498                                         dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n", 
 499                                                         segName(segIndex
), (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset
), (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset 
+ nextEntry
->sfm_size 
- 1)); 
 508 #endif // SPLIT_SEG_DYLIB_SUPPORT 
 511 void ImageLoaderMachOClassic::mapSegmentsClassic(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
) 
 513         // non-split segment libraries handled by super class 
 515                 return ImageLoaderMachO::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
); 
 517 #if SPLIT_SEG_SHARED_REGION_SUPPORT      
 518         // don't map split-seg dylibs into shared region if shared cache is in use 
 519         if ( ! context
.dyldLoadedAtSameAddressNeededBySharedCache 
) { 
 520                 // try to map into shared region at preferred address 
 521                 if ( mapSplitSegDylibInfoSharedRegion(fd
, offsetInFat
, lenInFat
, fileLen
, context
) == 0)  
 524         // if there is a problem, fall into case where we map file somewhere outside the shared region 
 527 #if SPLIT_SEG_DYLIB_SUPPORT 
 528         // support old split-seg dylibs by mapping them where ever we find space 
 529         if ( mapSplitSegDylibOutsideSharedRegion(fd
, offsetInFat
, lenInFat
, fileLen
, context
) != 0 )  
 531                 throw "mapping error"; 
 535 #if SPLIT_SEG_SHARED_REGION_SUPPORT      
 536 static int _shared_region_map_np(int fd
, uint32_t count
, const shared_file_mapping_np mappings
[]) 
 538         return syscall(295, fd
, count
, mappings
); 
 542 ImageLoaderMachOClassic::mapSplitSegDylibInfoSharedRegion(int fd
, 
 543                                          uint64_t offsetInFat
, 
 546                                          const LinkContext
& context
) 
 548         // build table of segments to map 
 549         const unsigned int segmentCount 
= fSegmentsCount
; 
 550         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 551         const unsigned int mappingTableCount 
= segmentCount
+extraZeroFillEntries
; 
 552         shared_file_mapping_np mappingTable
[mappingTableCount
]; 
 553         initMappingTable(offsetInFat
, mappingTable
); 
 555         // try to map it in shared 
 556         int r 
= _shared_region_map_np(fd
, mappingTableCount
, mappingTable
); 
 558                 this->setNeverUnload(); 
 559                 if ( context
.verboseMapping 
) { 
 560                         dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath()); 
 561                         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 562                                 const shared_file_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 563                                 if ( (entry
->sfm_init_prot 
& VM_PROT_ZF
) == 0 )  
 564                                         dyld::log("%18s at 0x%08lX->0x%08lX\n", 
 565                                                           segName(segIndex
), segActualLoadAddress(segIndex
), segActualEndAddress(segIndex
)-1); 
 566                                 if ( entryIndex 
< (mappingTableCount
-1) ) { 
 567                                         const shared_file_mapping_np
* nextEntry 
= &mappingTable
[entryIndex
+1]; 
 568                                         if ( (nextEntry
->sfm_init_prot 
& VM_PROT_ZF
) != 0 ) { 
 569                                                 uint64_t segOffset 
= nextEntry
->sfm_address 
- entry
->sfm_address
; 
 570                                                 dyld::log("%18s at 0x%08lX->0x%08lX\n", 
 571                                                                   segName(segIndex
), (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset
),  
 572                                                                   (uintptr_t)(segActualLoadAddress(segIndex
) + segOffset 
+ nextEntry
->sfm_size 
- 1)); 
 582 #endif // SPLIT_SEG_SHARED_REGION_SUPPORT        
 584 // test if this image is re-exported through parent (the image that loaded this one) 
 585 bool ImageLoaderMachOClassic::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const 
 588                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 589                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 590                 const struct load_command
* cmd 
= cmds
; 
 591                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 592                         if (cmd
->cmd 
== LC_SUB_FRAMEWORK
) { 
 593                                 const struct sub_framework_command
* subf 
= (struct sub_framework_command
*)cmd
; 
 594                                 const char* exportThruName 
= (char*)cmd 
+ subf
->umbrella
.offset
; 
 595                                 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent... 
 596                                 const char* parentInstallPath 
= parent
->getInstallPath(); 
 597                                 if ( parentInstallPath 
!= NULL 
) { 
 598                                         const char* lastSlash 
= strrchr(parentInstallPath
, '/'); 
 599                                         if ( lastSlash 
!= NULL 
) { 
 600                                                 if ( strcmp(&lastSlash
[1], exportThruName
) == 0 ) 
 602                                                 if ( context
.imageSuffix 
!= NULL 
) { 
 603                                                         // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 
 604                                                         char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(exportThruName
)+1]; 
 605                                                         strcpy(reexportAndSuffix
, exportThruName
); 
 606                                                         strcat(reexportAndSuffix
, context
.imageSuffix
); 
 607                                                         if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 ) 
 613                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 619 // test if child is re-exported  
 620 bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const 
 622         if ( fHasSubLibraries 
) { 
 623                 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child... 
 624                 const char* childInstallPath 
= child
->getInstallPath(); 
 625                 if ( childInstallPath 
!= NULL 
) { 
 626                         const char* lastSlash 
= strrchr(childInstallPath
, '/'); 
 627                         if ( lastSlash 
!= NULL 
) { 
 628                                 const char* firstDot 
= strchr(lastSlash
, '.'); 
 630                                 if ( firstDot 
== NULL 
) 
 631                                         len 
= strlen(lastSlash
); 
 633                                         len 
= firstDot
-lastSlash
-1; 
 634                                 char childLeafName
[len
+1]; 
 635                                 strncpy(childLeafName
, &lastSlash
[1], len
); 
 636                                 childLeafName
[len
] = '\0'; 
 637                                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 638                                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 639                                 const struct load_command
* cmd 
= cmds
; 
 640                                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 644                                                                 const struct sub_library_command
* lib 
= (struct sub_library_command
*)cmd
; 
 645                                                                 const char* aSubLibName 
= (char*)cmd 
+ lib
->sub_library
.offset
; 
 646                                                                 if ( strcmp(aSubLibName
, childLeafName
) == 0 ) 
 648                                                                 if ( context
.imageSuffix 
!= NULL 
) { 
 649                                                                         // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end 
 650                                                                         char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1]; 
 651                                                                         strcpy(aSubLibNameAndSuffix
, aSubLibName
); 
 652                                                                         strcat(aSubLibNameAndSuffix
, context
.imageSuffix
); 
 653                                                                         if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 ) 
 659                                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 664         if ( fHasSubUmbrella 
) { 
 665                 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child... 
 666                 const char* childInstallPath 
= child
->getInstallPath(); 
 667                 if ( childInstallPath 
!= NULL 
) { 
 668                         const char* lastSlash 
= strrchr(childInstallPath
, '/'); 
 669                         if ( lastSlash 
!= NULL 
) { 
 670                                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 671                                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 672                                 const struct load_command
* cmd 
= cmds
; 
 673                                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 675                                                 case LC_SUB_UMBRELLA
: 
 677                                                                 const struct sub_umbrella_command
* um 
= (struct sub_umbrella_command
*)cmd
; 
 678                                                                 const char* aSubUmbrellaName 
= (char*)cmd 
+ um
->sub_umbrella
.offset
; 
 679                                                                 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 ) 
 681                                                                 if ( context
.imageSuffix 
!= NULL 
) { 
 682                                                                         // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 
 683                                                                         char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1]; 
 684                                                                         strcpy(umbrellaAndSuffix
, aSubUmbrellaName
); 
 685                                                                         strcat(umbrellaAndSuffix
, context
.imageSuffix
); 
 686                                                                         if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 ) 
 692                                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 701 uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress() 
 703         // in split segment libraries r_address is offset from first writable segment 
 704         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 705                 if ( segWriteable(i
) )  
 706                         return segActualLoadAddress(i
); 
 708         throw "no writable segment"; 
 711 uintptr_t ImageLoaderMachOClassic::getRelocBase() 
 713         // r_address is either an offset from the first segment address 
 714         // or from the first writable segment address 
 716         return getFirstWritableSegmentAddress(); 
 719                 return getFirstWritableSegmentAddress(); 
 721                 return segActualLoadAddress(0); 
 726 #if PREBOUND_IMAGE_SUPPORT 
 727 void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext
& context
) 
 729         // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values 
 730         const uintptr_t relocBase 
= this->getRelocBase(); 
 731     const uintptr_t slide 
= this->fSlide
; 
 732         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]); 
 733         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nlocrel
]; 
 734         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
 735                 if ( (reloc
->r_address 
& R_SCATTERED
) != 0 ) { 
 736                         const struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
 737                         if (sreloc
->r_length 
== RELOC_SIZE
) { 
 738                                 uintptr_t* locationToFix 
= (uintptr_t*)(sreloc
->r_address 
+ relocBase
); 
 739                                 switch(sreloc
->r_type
) { 
 741                                         case GENERIC_RELOC_PB_LA_PTR
: 
 742                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
 746                                         case ARM_RELOC_PB_LA_PTR
: 
 747                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
 760 void ImageLoaderMachOClassic::rebase(const LinkContext
& context
, uintptr_t slide
) 
 762         CRSetCrashLogMessage2(this->getPath()); 
 763         const uintptr_t relocBase 
= this->getRelocBase(); 
 765         // prefetch any LINKEDIT pages needed 
 766         if ( !context
.preFetchDisabled 
&& !this->isPrebindable()) 
 767                 this->prefetchLINKEDIT(context
); 
 769         // loop through all local (internal) relocation records 
 770         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]); 
 771         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nlocrel
]; 
 772         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
 773                 uintptr_t rebaseAddr
; 
 775         #if LINKEDIT_USAGE_DEBUG 
 776                         noteAccessedLinkEditAddress(reloc
); 
 779                         // only one kind of local relocation supported for x86_64 
 780                         if ( reloc
->r_length 
!= 3 )  
 781                                 throw "bad local relocation length"; 
 782                         if ( reloc
->r_type 
!= X86_64_RELOC_UNSIGNED 
)  
 783                                 throw "unknown local relocation type"; 
 784                         if ( reloc
->r_pcrel 
!= 0 )  
 785                                 throw "bad local relocation pc_rel"; 
 786                         if ( reloc
->r_extern 
!= 0 )  
 787                                 throw "extern relocation found with local relocations"; 
 788                         rebaseAddr 
= reloc
->r_address 
+ relocBase
; 
 789                         if ( ! this->containsAddress((void*)rebaseAddr
) ) 
 790                                 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr
); 
 791                         *((uintptr_t*)rebaseAddr
) += slide
; 
 792                         if ( context
.verboseRebase 
) 
 793                                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr
, slide
); 
 795                         if ( (reloc
->r_address 
& R_SCATTERED
) == 0 ) { 
 796                                 if ( reloc
->r_symbolnum 
== R_ABS 
) { 
 797                                         // ignore absolute relocations 
 799                                 else if (reloc
->r_length 
== RELOC_SIZE
) { 
 800                                         switch(reloc
->r_type
) { 
 801                                                 case GENERIC_RELOC_VANILLA
: 
 802                                                         rebaseAddr 
= reloc
->r_address 
+ relocBase
; 
 803                                                         if ( ! this->containsAddress((void*)rebaseAddr
) ) 
 804                                                                 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr
); 
 805                                                         *((uintptr_t*)rebaseAddr
) += slide
; 
 806                                                         if ( context
.verboseRebase 
) 
 807                                                                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr
, slide
); 
 810                                                         throw "unknown local relocation type"; 
 814                                         throw "bad local relocation length"; 
 818                                 const struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
 819                                 if (sreloc
->r_length 
== RELOC_SIZE
) { 
 820                                         uintptr_t* locationToFix 
= (uintptr_t*)(sreloc
->r_address 
+ relocBase
); 
 821                                         switch(sreloc
->r_type
) { 
 822                                                 case GENERIC_RELOC_VANILLA
: 
 823                                                         if ( ! this->containsAddress((void*)locationToFix
) )  
 824                                                                 dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix
); 
 825                                                         *locationToFix 
+= slide
; 
 826                                                         if ( context
.verboseRebase 
) 
 827                                                                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix
, slide
); 
 830                                                 case GENERIC_RELOC_PB_LA_PTR
: 
 834                                                 case ARM_RELOC_PB_LA_PTR
: 
 839                                                         throw "unknown local scattered relocation type"; 
 843                                         throw "bad local scattered relocation length"; 
 848                 catch (const char* msg
) { 
 849                         const uint8_t* r 
= (uint8_t*)reloc
; 
 850                         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", 
 851                                 msg
, this->getPath(), reloc
, r
[0], r
[1], r
[2], r
[3], r
[4], r
[5], r
[6], r
[7]); 
 856         fgTotalRebaseFixups 
+= fDynamicInfo
->nlocrel
; 
 857         CRSetCrashLogMessage2(NULL
); 
 862 const struct macho_nlist
* ImageLoaderMachOClassic::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],  
 863                                                                                                 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
) const 
 865         int32_t high 
= symbolCount
-1; 
 866         int32_t mid 
= hintIndex
; 
 868         // handle out of range hint 
 869         if ( mid 
>= (int32_t)symbolCount 
) 
 871         ++ImageLoaderMachO::fgSymbolTableBinarySearchs
; 
 872         ++fgTotalBindImageSearches
;      
 874         //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName()); 
 876         for (int32_t low 
= 0; low 
<= high
; mid 
= (low
+high
)/2) { 
 877                 const uint32_t index 
= toc
[mid
].symbol_index
; 
 878                 const struct macho_nlist
* pivot 
= &symbols
[index
]; 
 879                 const char* pivotStr 
= &stringPool
[pivot
->n_un
.n_strx
]; 
 880 #if LINKEDIT_USAGE_DEBUG 
 881                 noteAccessedLinkEditAddress(&toc
[mid
]); 
 882                 noteAccessedLinkEditAddress(pivot
); 
 883                 noteAccessedLinkEditAddress(pivotStr
); 
 885                 int cmp 
= strcmp(key
, pivotStr
); 
 900 const struct macho_nlist
* ImageLoaderMachOClassic::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
) const 
 903         ++fgTotalBindImageSearches
;      
 904         ++ImageLoaderMachO::fgSymbolTableBinarySearchs
; 
 906         //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n",  
 907         //                              key, this->getShortName(), stringPool, symbols, symbolCount); 
 909         const struct macho_nlist
* base 
= symbols
; 
 910         for (uint32_t n 
= symbolCount
; n 
> 0; n 
/= 2) { 
 911                 const struct macho_nlist
* pivot 
= &base
[n
/2]; 
 912                 const char* pivotStr 
= &stringPool
[pivot
->n_un
.n_strx
]; 
 913 #if LINKEDIT_USAGE_DEBUG 
 914                 noteAccessedLinkEditAddress(pivot
); 
 915                 noteAccessedLinkEditAddress(pivotStr
); 
 917                 int cmp 
= strcmp(key
, pivotStr
); 
 922                         // move base to symbol after pivot 
 935 const ImageLoader::Symbol
* ImageLoaderMachOClassic::findShallowExportedSymbol(const char* name
, const ImageLoader
** foundIn
) const 
 937         const struct macho_nlist
* sym 
= NULL
; 
 938         if ( fDynamicInfo
->tocoff 
== 0 ) 
 939                 sym 
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
); 
 941                 sym 
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],  
 942                                                                                 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
); 
 944                 if ( foundIn 
!= NULL 
) 
 945                         *foundIn 
= (ImageLoader
*)this;           
 946                 return (const Symbol
*)sym
; 
 953 bool ImageLoaderMachOClassic::containsSymbol(const void* addr
) const 
 955         return ( (fSymbolTable 
<= addr
) && (addr 
< fStrings
) ); 
 959 uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext
& context
, const Symbol
* symbol
, const ImageLoader
* requestor
, bool runResolver
) const 
 961         const struct macho_nlist
* sym 
= (macho_nlist
*)symbol
; 
 962         uintptr_t result 
= sym
->n_value 
+ fSlide
; 
 964                 // processor assumes code address with low bit set is thumb 
 965                 if (sym
->n_desc 
& N_ARM_THUMB_DEF
) 
 971 bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol
* symbol
) const 
 973         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)symbol
; 
 974         return ( (nlistSym
->n_desc 
& N_WEAK_DEF
) != 0 ); 
 977 const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol
* symbol
) const 
 979         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)symbol
; 
 980         return &fStrings
[nlistSym
->n_un
.n_strx
]; 
 983 unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const 
 985         return fDynamicInfo
->nextdefsym
; 
 988 const ImageLoader::Symbol
* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index
) const 
 990         if ( index 
< fDynamicInfo
->nextdefsym 
) { 
 991                 const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iextdefsym 
+ index
]; 
 992                 return (const ImageLoader::Symbol
*)sym
; 
 997 unsigned int ImageLoaderMachOClassic::importedSymbolCount() const 
 999         return fDynamicInfo
->nundefsym
; 
1002 const ImageLoader::Symbol
* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index
) const 
1004         if ( index 
< fDynamicInfo
->nundefsym 
) { 
1005                 const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iundefsym 
+ index
]; 
1006                 return (const ImageLoader::Symbol
*)sym
; 
1011 const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol
* symbol
) const 
1013         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)symbol
; 
1014         return &fStrings
[nlistSym
->n_un
.n_strx
]; 
1019 bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist
* symbol
) 
1021         // if a define and weak ==> coalesced  
1022         if ( ((symbol
->n_type 
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc 
& N_WEAK_DEF
) != 0) )  
1029 bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist
* symbol
) 
1031         // if an undefine and not referencing a weak symbol ==> coalesced 
1032         if ( ((symbol
->n_type 
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc 
& N_REF_TO_WEAK
) != 0) ) 
1039 uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist
* sym
, const LinkContext
& context
, bool runResolver
) const 
1041         return ImageLoaderMachO::getSymbolAddress((Symbol
*)sym
, this, context
, runResolver
); 
1044 uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
,  
1045                                                                                 bool twoLevel
, bool dontCoalesce
, bool runResolver
, const ImageLoader
** foundIn
) 
1047         ++fgTotalBindSymbolsResolved
; 
1048         const char* symbolName 
= &fStrings
[undefinedSymbol
->n_un
.n_strx
]; 
1050 #if LINKEDIT_USAGE_DEBUG 
1051         noteAccessedLinkEditAddress(undefinedSymbol
); 
1052         noteAccessedLinkEditAddress(symbolName
); 
1054         if ( context
.bindFlat 
|| !twoLevel 
) { 
1056                 if ( ((undefinedSymbol
->n_type 
& N_PEXT
) != 0) && ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) ) { 
1057                         // is a multi-module private_extern internal reference that the linker did not optimize away 
1058                         uintptr_t addr 
= this->getSymbolAddress(undefinedSymbol
, context
, false); 
1063                 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) { 
1064                         if ( *foundIn 
!= this ) 
1065                                 context
.addDynamicReference(this, const_cast<ImageLoader
*>(*foundIn
)); 
1066                         return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1068                 // if a bundle is loaded privately the above will not find its exports 
1069                 if ( this->isBundle() && this->hasHiddenExports() ) { 
1070                         // look in self for needed symbol 
1071                         sym 
= this->findShallowExportedSymbol(symbolName
, foundIn
); 
1073                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1075                 if ( (undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0 ) { 
1076                         // definition can't be found anywhere 
1077                         // if reference is weak_import, then it is ok, just return 0 
1080                 throwSymbolNotFound(context
, symbolName
, this->getPath(), "", "flat namespace"); 
1083                 // symbol requires searching images with coalesced symbols (not done during prebinding) 
1084                 if ( !context
.prebinding 
&& !dontCoalesce 
&& (symbolIsWeakReference(undefinedSymbol
) || symbolIsWeakDefinition(undefinedSymbol
)) ) { 
1086                         if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) ) { 
1087                                 if ( *foundIn 
!= this ) 
1088                                         context
.addDynamicReference(this, const_cast<ImageLoader
*>(*foundIn
)); 
1089                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1091                         //throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace"); 
1092                         //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName); 
1095                 // if this is a real definition (not an undefined symbol) there is no ordinal 
1096                 if ( (undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT 
) { 
1097                         // static linker should never generate this case, but if it does, do something sane 
1098                         uintptr_t addr 
= this->getSymbolAddress(undefinedSymbol
, context
, false); 
1104                 ImageLoader
* target 
= NULL
; 
1105                 uint8_t ord 
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
); 
1106                 if ( ord 
== EXECUTABLE_ORDINAL 
) { 
1107                         target 
= context
.mainExecutable
; 
1109                 else if ( ord 
== SELF_LIBRARY_ORDINAL 
) { 
1112                 else if ( ord 
== DYNAMIC_LOOKUP_ORDINAL 
) { 
1113                         // rnielsen: HACKHACK 
1116                         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1117                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1118                         // no image has exports this symbol 
1120                         context
.undefinedHandler(symbolName
); 
1121                         // try looking again 
1122                         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1123                                 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this); 
1125                         throwSymbolNotFound(context
, symbolName
, this->getPath(), "", "dynamic lookup"); 
1127                 else if ( ord 
<= libraryCount() ) { 
1128                         target 
= libImage(ord
-1); 
1129                         if ( target 
== NULL 
) { 
1130                                 // if target library not loaded and reference is weak or library is weak return 0 
1135                         dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s", 
1136                                 ord
, libraryCount(), symbolName
, this->getPath()); 
1139                 if ( target 
== NULL 
) { 
1140                         //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath()); 
1141                         throw "symbol not found"; 
1145                 if ( target
->findExportedSymbolAddress(context
, symbolName
, this, ord
, runResolver
, foundIn
, &address
) ) 
1148                 if ( (undefinedSymbol
->n_type 
& N_PEXT
) != 0 ) { 
1149                         // don't know why the static linker did not eliminate the internal reference to a private extern definition 
1151                         return this->getSymbolAddress(undefinedSymbol
, context
, false); 
1153                 else if ( (undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0 ) { 
1154                         // if definition not found and reference is weak return 0 
1158                 // nowhere to be found 
1159                 throwSymbolNotFound(context
, symbolName
, this->getPath(), "", target
->getPath()); 
1165 // returns if 'addr' is within the address range of section 'sectionIndex' 
1166 // fSlide is not used.  'addr' is assumed to be a prebound address in this image  
1167 bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
) 
1169         uint8_t currentSectionIndex 
= 1; 
1170         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1171         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1172         const struct load_command
* cmd 
= cmds
; 
1173         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1174                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1175                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1176                         if ( (currentSectionIndex 
<= sectionIndex
) && (sectionIndex 
< currentSectionIndex
+seg
->nsects
) ) { 
1177                                 // 'sectionIndex' is in this segment, get section info 
1178                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1179                                 const struct macho_section
* const section 
= §ionsStart
[sectionIndex
-currentSectionIndex
]; 
1180                                 return ( (section
->addr 
<= addr
) && (addr 
< section
->addr
+section
->size
) ); 
1183                                 // 'sectionIndex' not in this segment, skip to next segment 
1184                                 currentSectionIndex 
+= seg
->nsects
; 
1187                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1193 void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext
& context
) 
1195         const uintptr_t relocBase 
= this->getRelocBase(); 
1196         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1197         const bool prebound 
= this->isPrebindable(); 
1199 #if TEXT_RELOC_SUPPORT 
1200         // if there are __TEXT fixups, temporarily make __TEXT writable 
1201         if ( fTextSegmentBinds 
)  
1202                 this->makeTextSegmentWritable(context
, true); 
1204         // cache last lookup 
1205         const struct macho_nlist
*       lastUndefinedSymbol 
= NULL
; 
1206         uintptr_t                                       symbolAddr 
= 0; 
1207         const ImageLoader
*                      image 
= NULL
; 
1209         // loop through all external relocation records and bind each 
1210         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
1211         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
1212         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1213                 if (reloc
->r_length 
== RELOC_SIZE
) { 
1214                         switch(reloc
->r_type
) { 
1217                                                 const struct macho_nlist
* undefinedSymbol 
= &fSymbolTable
[reloc
->r_symbolnum
]; 
1218                                                 uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
1219                                                 if ( ! this->containsAddress((void*)location
) ) 
1220                                                         dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location
, this->getPath()); 
1221                                                 uintptr_t value 
= *location
; 
1222                                                 bool symbolAddrCached 
= true; 
1224                                                 if ( reloc
->r_pcrel 
) { 
1225                                                         value 
+= (uintptr_t)location 
+ 4 - fSlide
; 
1229                                                         // we are doing relocations, so prebinding was not usable 
1230                                                         // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 
1231                                                         // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 
1232                                                         // if mach-o relocation structs had an "addend" field this complication would not be necessary. 
1233                                                         if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1234                                                                 // weak symbols need special casing, since *location may have been prebound to a definition in another image. 
1235                                                                 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume  
1236                                                                 // that we can subtract off the weak symbol address to get the addend. 
1237                                                                 // If prebound elsewhere, we've lost the addend and have to assume it is zero. 
1238                                                                 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 
1239                                                                 if ( (value 
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) ) { 
1240                                                                         value 
-= undefinedSymbol
->n_value
; 
1242                                     // if weak and thumb subtract off extra thumb bit 
1243                                     if ( (undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0 ) 
1251                                                         else if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0) ) { 
1252                                                                 // it was prebound to a defined symbol for thumb code in the same linkage unit 
1253                                                                 // we need to subtract off one to get real addend 
1254                                                                 value 
-= (undefinedSymbol
->n_value
+1); 
1258                                                                 // is undefined or non-weak symbol, so do subtraction to get addend 
1259                                                                 value 
-= undefinedSymbol
->n_value
; 
1262                                                 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too 
1263                                                 if ( undefinedSymbol 
!= lastUndefinedSymbol 
) { 
1264                                                         bool dontCoalesce 
= true; 
1265                                                         if ( symbolIsWeakReference(undefinedSymbol
) ) {  
1266                                                                 // when weakbind() is run on a classic mach-o encoding, it won't try 
1267                                                                 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted 
1268                                                                 // range of global symbols.  To handle that case we do the coalesing now. 
1269                                                                 dontCoalesce 
= false; 
1271                                                         symbolAddr 
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, dontCoalesce
, false, &image
); 
1272                                                         lastUndefinedSymbol 
= undefinedSymbol
; 
1273                                                         symbolAddrCached 
= false; 
1275                                                 if ( context
.verboseBind 
) { 
1276                                                         const char *path 
= NULL
; 
1277                                                         if ( image 
!= NULL 
) { 
1278                                                                 path 
= image
->getShortName(); 
1280                                                         const char* cachedString 
= "(cached)"; 
1281                                                         if ( !symbolAddrCached 
)  
1284                                                                 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n", 
1285                                                                                 this->getShortName(), (uintptr_t)location
, 
1286                                                                                 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, cachedString
); 
1289                                                                 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n", 
1290                                                                                 this->getShortName(), (uintptr_t)location
, 
1291                                                                                 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, cachedString
, value
); 
1294                                                 value 
+= symbolAddr
; 
1296                                                 if ( reloc
->r_pcrel 
) { 
1297                                                         *location 
= value 
- ((uintptr_t)location 
+ 4); 
1300                                                         // don't dirty page if prebound value was correct 
1301                                                         if ( !prebound 
|| (*location 
!= value
) ) 
1305                                                 // don't dirty page if prebound value was correct 
1306                                                 if ( !prebound 
|| (*location 
!= value
) ) 
1310                                                 ++fgTotalBindFixups
; 
1314                                         throw "unknown external relocation type"; 
1318                         throw "bad external relocation length"; 
1322 #if TEXT_RELOC_SUPPORT 
1323         // if there were __TEXT fixups, restore write protection 
1324         if ( fTextSegmentBinds 
) { 
1325                 this->makeTextSegmentWritable(context
, true); 
1332 uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, const ImageLoader
* targetImage
, const LinkContext
& context
) 
1334         if ( context
.verboseBind 
) { 
1335                 const char* path 
= NULL
; 
1336                 if ( targetImage 
!= NULL 
) 
1337                         path 
= targetImage
->getShortName(); 
1338                 dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n", 
1339                                 this->getShortName(), symbolName
, (((sect
->flags 
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"), 
1340                                 ((path 
!= NULL
) ? path 
: "<weak_import-not-found>"), symbolName
, (uintptr_t)ptrToBind
, targetAddr
); 
1342         if ( context
.bindingHandler 
!= NULL 
) { 
1343                 const char* path 
= NULL
; 
1344                 if ( targetImage 
!= NULL 
) 
1345                         path 
= targetImage
->getShortName(); 
1346                 targetAddr 
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
); 
1349         // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32" 
1350         if ( ((sect
->flags 
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2 
== 5) ) { 
1351                 uint32_t rel32 
= targetAddr 
- (((uint32_t)ptrToBind
)+5); 
1352                 // re-write instruction in a thread-safe manner 
1353                 // use 8-byte compare-and-swap to alter 5-byte jump table entries 
1354                 // loop is required in case the extra three bytes that cover the next entry are altered by another thread 
1357                         volatile int64_t* jumpPtr 
= (int64_t*)ptrToBind
; 
1359                         // By default the three extra bytes swapped follow the 5-byte JMP. 
1360                         // But, if the 5-byte jump is up against the end of the __IMPORT segment 
1361                         // We don't want to access bytes off the end of the segment, so we shift 
1362                         // the extra bytes to precede the 5-byte JMP. 
1363                         if ( (((uint32_t)ptrToBind 
+ 8) & 0x00000FFC) == 0x00000000 ) { 
1364                                 jumpPtr 
= (int64_t*)((uint32_t)ptrToBind 
- 3); 
1367                         int64_t oldEntry 
= *jumpPtr
; 
1372                         newEntry
.int64 
= oldEntry
; 
1373                         newEntry
.bytes
[pad
+0] = 0xE9; // JMP rel32 
1374                         newEntry
.bytes
[pad
+1] = rel32 
& 0xFF; 
1375                         newEntry
.bytes
[pad
+2] = (rel32 
>> 8) & 0xFF; 
1376                         newEntry
.bytes
[pad
+3] = (rel32 
>> 16) & 0xFF; 
1377                         newEntry
.bytes
[pad
+4] = (rel32 
>> 24) & 0xFF; 
1378                         done 
= OSAtomicCompareAndSwap64Barrier(oldEntry
, newEntry
.int64
, (int64_t*)jumpPtr
); 
1383         *ptrToBind 
= targetAddr
; 
1387 uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset
, const LinkContext
& context
, void (*lock
)(), void (*unlock
)()) 
1389         throw "compressed LINKEDIT lazy binder called with classic LINKEDIT"; 
1392 uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
) 
1394         // scan for all lazy-pointer sections 
1395         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1396         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1397         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1398         const struct load_command
* cmd 
= cmds
; 
1399         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1400         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1402                         case LC_SEGMENT_COMMAND
: 
1404                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1405                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1406                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1407                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1408                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1409                                                 uint32_t symbolIndex 
= INDIRECT_SYMBOL_LOCAL
; 
1410                                                 if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
1411                                                         const size_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
1412                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1413                                                         if ( (lazyPointer 
>= symbolPointers
) && (lazyPointer 
< &symbolPointers
[pointerCount
]) ) { 
1414                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1415                                                                 const size_t lazyIndex 
= lazyPointer 
- symbolPointers
; 
1416                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ lazyIndex
]; 
1420                                                 else if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
1421                                                         // 5 bytes stubs on i386 are new "fast stubs" 
1422                                                         uint8_t* const jmpTableBase 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
1423                                                         uint8_t* const jmpTableEnd 
= jmpTableBase 
+ sect
->size
; 
1424                                                         // initial CALL instruction in jump table leaves pointer to next entry, so back up 
1425                                                         uint8_t* const jmpTableEntryToPatch 
= ((uint8_t*)lazyPointer
) - 5;   
1426                                                         lazyPointer 
= (uintptr_t*)jmpTableEntryToPatch
;  
1427                                                         if ( (jmpTableEntryToPatch 
>= jmpTableBase
) && (jmpTableEntryToPatch 
< jmpTableEnd
) ) { 
1428                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1429                                                                 const uint32_t entryIndex 
= (jmpTableEntryToPatch 
- jmpTableBase
)/5; 
1430                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ entryIndex
]; 
1434                                                 if ( symbolIndex 
!= INDIRECT_SYMBOL_ABS 
&& symbolIndex 
!= INDIRECT_SYMBOL_LOCAL 
) { 
1435                                                         const char* symbolName 
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
]; 
1436                                                         const ImageLoader
* image 
= NULL
; 
1437                                                         uintptr_t symbolAddr 
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, false, true, &image
); 
1438                                                         symbolAddr 
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
,  context
); 
1439                                                         ++fgTotalLazyBindFixups
; 
1446                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1448         dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer
, this->getPath()); 
1453 void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator
& it
, unsigned int loadOrder
, unsigned) 
1456         it
.symbolName 
= " "; 
1457         it
.loadOrder 
= loadOrder
; 
1458         it
.weakSymbol 
= false; 
1459         it
.symbolMatches 
= false; 
1462         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1464                 it
.endIndex 
= fDynamicInfo
->ntoc
; 
1468                 it
.endIndex 
= fDynamicInfo
->nextdefsym
; 
1473 bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator
& it
) 
1478         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1479                 if ( it
.curIndex 
>= fDynamicInfo
->ntoc 
) { 
1481                         it
.symbolName 
= "~~~"; 
1485                         const dylib_table_of_contents
* toc 
= (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
]; 
1486                         const uint32_t index 
= toc
[it
.curIndex
].symbol_index
; 
1487                         const struct macho_nlist
* sym 
= &fSymbolTable
[index
]; 
1488                         const char* symStr 
= &fStrings
[sym
->n_un
.n_strx
]; 
1489                         it
.symbolName 
= symStr
; 
1490                         it
.weakSymbol 
= (sym
->n_desc 
& N_WEAK_DEF
); 
1491                         it
.symbolMatches 
= false; 
1492                         it
.type 
= 0; // clear flag that says we applied updates for this symbol 
1493                         //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath()); 
1499                 if ( it
.curIndex 
>= fDynamicInfo
->nextdefsym 
) { 
1501                         it
.symbolName 
= "~~~"; 
1505                         const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+it
.curIndex
]; 
1506                         const char* symStr 
= &fStrings
[sym
->n_un
.n_strx
]; 
1507                         it
.symbolName 
= symStr
; 
1508                         it
.weakSymbol 
= (sym
->n_desc 
& N_WEAK_DEF
); 
1509                         it
.symbolMatches 
= false; 
1510                         it
.type 
= 0; // clear flag that says we applied updates for this symbol 
1511                         //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath()); 
1520 uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator
& it
, const LinkContext
& context
) 
1522         uint32_t symbol_index 
= 0; 
1523         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1524                 const dylib_table_of_contents
* toc 
= (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
]; 
1525                 symbol_index 
= toc
[it
.curIndex
-1].symbol_index
; 
1528                 symbol_index 
= fDynamicInfo
->iextdefsym 
+ (uint32_t)it
.curIndex 
- 1; 
1530         const struct macho_nlist
* sym 
= &fSymbolTable
[symbol_index
]; 
1531         //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()); 
1533                 // processor assumes code address with low bit set is thumb 
1534                 if (sym
->n_desc 
& N_ARM_THUMB_DEF
) 
1535                         return (sym
->n_value 
| 1) + fSlide 
; 
1537                         return sym
->n_value 
+ fSlide
; 
1539         return sym
->n_value 
+ fSlide
; 
1544 void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator
& it
, uintptr_t value
, ImageLoader
* targetImage
, unsigned targetIndex
, const LinkContext
& context
) 
1546         // flat_namespace images with classic LINKEDIT do not need late coalescing. 
1547         // They still need to be iterated becuase they may implement 
1548         // something needed by other coalescing images. 
1549         // But they need no updating because during the bind phase every symbol lookup is a full scan. 
1550         if ( !this->usesTwoLevelNameSpace() ) 
1553         // <rdar://problem/6570879> weak binding done too early with inserted libraries 
1554         if ( this->getState() < dyld_image_state_bound  
) 
1557         uint32_t symbol_index 
= 0; 
1558         if ( fDynamicInfo
->tocoff 
!= 0 ) { 
1559                 const dylib_table_of_contents
* toc 
= (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
]; 
1560                 symbol_index 
= toc
[it
.curIndex
-1].symbol_index
; 
1563                 symbol_index 
= fDynamicInfo
->iextdefsym 
+ (uint32_t)it
.curIndex 
- 1; 
1566         // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here 
1567         if ( !symbolIsWeakReference(&fSymbolTable
[symbol_index
]) && !symbolIsWeakDefinition(&fSymbolTable
[symbol_index
]) ) { 
1571         // <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding 
1575         bool boundSomething 
= false; 
1576         // scan external relocations for uses of symbol_index 
1577         const uintptr_t relocBase 
= this->getRelocBase(); 
1578         const bool prebound 
= this->isPrebindable(); 
1579         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
1580         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
1581         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1582                 if ( reloc
->r_symbolnum 
== symbol_index 
) { 
1583                         //dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath()); 
1584                         const struct macho_nlist
* undefinedSymbol 
= &fSymbolTable
[reloc
->r_symbolnum
]; 
1585                         const char* symbolName 
= &fStrings
[undefinedSymbol
->n_un
.n_strx
]; 
1586                         uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
1587                         const uintptr_t initialValue 
= *location
; 
1588                         uintptr_t addend 
= 0; 
1590                                 // we are doing relocations, so prebinding was not usable 
1591                                 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 
1592                                 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 
1593                                 // if mach-o relocation structs had an "addend" field this complication would not be necessary. 
1594                                 if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1595                                         // weak symbols need special casing, since *location may have been prebound to a definition in another image. 
1596                                         // If *location is currently prebound to somewhere in the same section as the weak definition, we assume  
1597                                         // that we can subtract off the weak symbol address to get the addend. 
1598                                         // If prebound elsewhere, we've lost the addend and have to assume it is zero. 
1599                                         // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 
1600                                         if ( (initialValue 
== undefinedSymbol
->n_value
) || this->isAddrInSection(initialValue
, undefinedSymbol
->n_sect
) ) { 
1601                                                 addend 
= initialValue 
- undefinedSymbol
->n_value
; 
1603                                                 // if weak and thumb subtract off extra thumb bit 
1604                                                 if ( (undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0 ) 
1610                                 else if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0) ) { 
1611                                         // it was prebound to a defined symbol for thumb code in the same linkage unit 
1612                                         // we need to subtract off one to get real addend 
1613                                         addend 
= initialValue 
- (undefinedSymbol
->n_value
+1); 
1617                                         // is undefined or non-weak symbol, so do subtraction to get addend 
1618                                         addend 
= initialValue 
- undefinedSymbol
->n_value
; 
1622                                 // non-prebound case 
1623                                 if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1624                                         // if target is weak-def in same linkage unit, then bind phase has already set initialValue  
1625                                         // to be definition address plus addend 
1626                                         //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide); 
1627                                         addend 
= initialValue 
- (undefinedSymbol
->n_value 
+ fSlide
); 
1629                                         // if weak and thumb subtract off extra thumb bit 
1630                                         if ( (undefinedSymbol
->n_desc 
& N_ARM_THUMB_DEF
) != 0 ) 
1635                                         // nothing fixed up yet, addend is just initial value 
1636                                         //dyld::log("addend=0x%lX\n", initialValue); 
1637                                         addend 
= initialValue
; 
1641                         uint8_t type 
= BIND_TYPE_POINTER
; 
1643                         if ( reloc
->r_pcrel 
)  
1644                                 type 
= BIND_TYPE_TEXT_PCREL32
; 
1646                         this->bindLocation(context
, (uintptr_t)location
, value
, type
, symbolName
, addend
, this->getPath(), targetImage 
? targetImage
->getPath() : NULL
, "weak "); 
1647                         boundSomething 
= true; 
1651         // scan lazy and non-lazy pointers for uses of symbol_index 
1652         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1653         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1654         const struct load_command
* cmd 
= cmds
; 
1655         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1656         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1657                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1658                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1659                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1660                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1661                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1662                                 uint32_t elementSize 
= sizeof(uintptr_t); 
1663                                 switch ( sect
->flags 
& SECTION_TYPE 
) { 
1665                                         case S_SYMBOL_STUBS
: 
1666                                                 if ( ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) ==0) || (sect
->reserved2 
!= 5) ) 
1670                                         case S_NON_LAZY_SYMBOL_POINTERS
: 
1671                                         case S_LAZY_SYMBOL_POINTERS
: 
1673                                                 size_t elementCount 
= sect
->size 
/ elementSize
; 
1674                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1675                                                 uint8_t* ptrToBind 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
1676                                                 //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind); 
1677                                                 for (size_t j
=0; j 
< elementCount
; ++j
, ptrToBind 
+= elementSize
) { 
1678                                                         if ( indirectTable
[indirectTableOffset 
+ j
] == symbol_index 
) { 
1679                                                                 //dyld::log("  found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind); 
1681                                                                 this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, it
.symbolName
, value
, targetImage
, context
); 
1682                                                                 boundSomething 
= true; 
1690                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1692         if ( boundSomething 
&& (targetImage 
!= this) ) { 
1693                 context
.addDynamicReference(this, targetImage
); 
1696         // mark that this symbol has already been bound, so we don't try to bind again 
1701 void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext
& context
, bool bindNonLazys
, bool bindLazys
) 
1703         // scan for all non-lazy-pointer sections  
1704         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1705         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1706         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1707         const struct load_command
* cmd 
= cmds
; 
1708         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1709         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1711                         case LC_SEGMENT_COMMAND
: 
1713                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1714                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1715                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1716                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1717                                                 bool isLazySymbol 
= false; 
1718                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1719                                                 uint32_t elementSize 
= sizeof(uintptr_t); 
1720                                                 size_t elementCount 
= sect
->size 
/ elementSize
; 
1721                                                 if ( type 
== S_NON_LAZY_SYMBOL_POINTERS 
) { 
1722                                                         if ( ! bindNonLazys 
) 
1725                                                 else if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
1726                                                         // process each symbol pointer in this section 
1727                                                         fgTotalPossibleLazyBindFixups 
+= elementCount
; 
1728                                                         isLazySymbol 
= true; 
1733                                                 else if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
1734                                                         // process each jmp entry in this section 
1735                                                         elementCount 
= sect
->size 
/ 5; 
1737                                                         fgTotalPossibleLazyBindFixups 
+= elementCount
; 
1738                                                         isLazySymbol 
= true; 
1746                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1747                                                 uint8_t* ptrToBind 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
1748                                                 for (size_t j
=0; j 
< elementCount
; ++j
, ptrToBind 
+= elementSize
) { 
1749                                 #if LINKEDIT_USAGE_DEBUG 
1750                                                         noteAccessedLinkEditAddress(&indirectTable
[indirectTableOffset 
+ j
]); 
1752                                                         uint32_t symbolIndex 
= indirectTable
[indirectTableOffset 
+ j
]; 
1753                                                         if ( symbolIndex 
== INDIRECT_SYMBOL_LOCAL
) { 
1754                                                                 *((uintptr_t*)ptrToBind
) += this->fSlide
; 
1756                                                         else if ( symbolIndex 
== INDIRECT_SYMBOL_ABS
) { 
1757                                                                 // do nothing since already has absolute address 
1760                                                                 const struct macho_nlist
* sym 
= &fSymbolTable
[symbolIndex
]; 
1761                                                                 if ( symbolIndex 
== 0 ) { 
1762                                                                         // This could be rdar://problem/3534709  
1763                                                                         if ( ((const macho_header
*)fMachOData
)->filetype 
== MH_EXECUTE 
) { 
1764                                                                                 static bool alreadyWarned 
= false; 
1765                                                                                 if ( (sym
->n_type 
& N_TYPE
) != N_UNDF 
) { 
1766                                                                                         // The indirect table parallels the (non)lazy pointer sections.  For 
1767                                                                                         // instance, to find info about the fifth lazy pointer you look at the 
1768                                                                                         // fifth entry in the indirect table.  (try otool -Iv on a file). 
1769                                                                                         // The entry in the indirect table contains an index into the symbol table. 
1771                                                                                         // The bug in ld caused the entry in the indirect table to be zero 
1772                                                                                         // (instead of a magic value that means a local symbol).  So, if the 
1773                                                                                         // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid 
1774                                                                                         // symbol table index. The check I put in place is to see if the zero'th 
1775                                                                                         // symbol table entry is an import entry (usually it is a local symbol 
1777                                                                                         if ( context
.verboseWarnings 
&& !alreadyWarned 
) { 
1778                                                                                                 dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n", 
1779                                                                                                                 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]); 
1780                                                                                                 alreadyWarned 
= true; 
1786                                                                 const ImageLoader
* image 
= NULL
; 
1787                                                                 // let weak definitions resolve to themselves, later coalescing may overwrite them 
1788                                                                 bool dontCoalesce 
= true; 
1789                                                                 if ( bindLazys 
&& isLazySymbol 
) { 
1790                                                                         // if this is something normally lazy bound, but we are forcing 
1791                                                                         // it to be bound now, do coalescing 
1792                                                                         dontCoalesce 
= false; 
1794                                                                 if ( symbolIsWeakReference(sym
) ) {  
1795                                                                         // when weakbind() is run on a classic mach-o encoding, it won't try 
1796                                                                         // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted 
1797                                                                         // range of global symbols.  To handle that case we do the coalesing now. 
1798                                                                         dontCoalesce 
= false; 
1800                                                                 uintptr_t symbolAddr 
= resolveUndefined(context
, sym
, twoLevel
, dontCoalesce
, false, &image
); 
1802                                                                 symbolAddr 
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
,  context
); 
1804                                                                 ++fgTotalBindFixups
; 
1811                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1818 void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext
& context
) 
1820         if ( ! this->usablePrebinding(context
) ) { 
1821                 // reset all "fast" stubs 
1822                 const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1823                 const uint32_t cmd_count 
= mh
->ncmds
; 
1824                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1825                 const struct load_command
* cmd 
= cmds
; 
1826                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1828                                 case LC_SEGMENT_COMMAND
: 
1830                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1831                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1832                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1833                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1834                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1835                                                 if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
1836                                                         // reset each jmp entry in this section 
1837                                                         const uint32_t indirectTableOffset 
= sect
->reserved1
; 
1838                                                         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
1839                                                         uint8_t* start 
= (uint8_t*)(sect
->addr 
+ this->fSlide
); 
1840                                                         uint8_t* end 
= start 
+ sect
->size
; 
1841                                                         uintptr_t dyldHandler 
= (uintptr_t)&stub_binding_helper_i386_old
; 
1842                                                         uint32_t entryIndex 
= 0; 
1843                                                         for (uint8_t* entry 
= start
; entry 
< end
; entry 
+= 5, ++entryIndex
) { 
1844                                                                 bool installLazyHandler 
= true; 
1845                                                                 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes 
1846                                                                 // if the instruction is updated by one thread while being executed by another 
1847                                                                 if ( ((uint32_t)entry 
& 0xFFFFFFC0) != ((uint32_t)entry
+4 & 0xFFFFFFC0) ) { 
1848                                                                         // need to bind this now to avoid a potential problem if bound lazily 
1849                                                                         uint32_t symbolIndex 
= indirectTable
[indirectTableOffset 
+ entryIndex
]; 
1850                                                                         // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used 
1851                                                                         if ( symbolIndex 
!= INDIRECT_SYMBOL_ABS 
) { 
1852                                                                                 const char* symbolName 
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
]; 
1853                                                                                 const ImageLoader
* image 
= NULL
; 
1855                                                                                         uintptr_t symbolAddr 
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], this->usesTwoLevelNameSpace(), false, false, &image
); 
1856                                                                                         symbolAddr 
= this->bindIndirectSymbol((uintptr_t*)entry
, sect
, symbolName
, symbolAddr
, image
, context
); 
1857                                                                                         ++fgTotalBindFixups
; 
1858                                                                                         uint32_t rel32 
= symbolAddr 
- (((uint32_t)entry
)+5); 
1859                                                                                         entry
[0] = 0xE9; // JMP rel32 
1860                                                                                         entry
[1] = rel32 
& 0xFF; 
1861                                                                                         entry
[2] = (rel32 
>> 8) & 0xFF; 
1862                                                                                         entry
[3] = (rel32 
>> 16) & 0xFF; 
1863                                                                                         entry
[4] = (rel32 
>> 24) & 0xFF; 
1864                                                                                         installLazyHandler 
= false; 
1866                                                                                 catch (const char* msg
) { 
1867                                                                                         // ignore errors when binding symbols early 
1868                                                                                         // maybe the function is never called, and therefore erroring out now would be a regression 
1872                                                                 if ( installLazyHandler 
) { 
1873                                                                         uint32_t rel32 
= dyldHandler 
- (((uint32_t)entry
)+5); 
1874                                                                         entry
[0] = 0xE8; // CALL rel32 
1875                                                                         entry
[1] = rel32 
& 0xFF; 
1876                                                                         entry
[2] = (rel32 
>> 8) & 0xFF; 
1877                                                                         entry
[3] = (rel32 
>> 16) & 0xFF; 
1878                                                                         entry
[4] = (rel32 
>> 24) & 0xFF; 
1885                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1892 void ImageLoaderMachOClassic::doBind(const LinkContext
& context
, bool forceLazysBound
) 
1894         CRSetCrashLogMessage2(this->getPath()); 
1896         this->initializeLazyStubs(context
); 
1899         // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 
1900         // note: flat-namespace binaries need to have imports rebound (even if correctly prebound) 
1901         if ( this->usablePrebinding(context
) ) { 
1902                 // binding already up to date 
1905                 // no valid prebinding, so bind symbols. 
1906                 // values bound by name are stored two different ways in classic mach-o: 
1908         #if TEXT_RELOC_SUPPORT 
1909                 // if there are __TEXT fixups, temporarily make __TEXT writable 
1910                 if ( fTextSegmentBinds 
)  
1911                         this->makeTextSegmentWritable(context
, true); 
1914                 // 1) external relocations are used for data initialized to external symbols 
1915                 this->doBindExternalRelocations(context
); 
1917                 // 2) "indirect symbols" are used for code references to external symbols 
1918                 // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now 
1919                 this->bindIndirectSymbolPointers(context
, true, forceLazysBound 
|| fInSharedCache
); 
1921         #if TEXT_RELOC_SUPPORT 
1922                 // if there were __TEXT fixups, restore write protection 
1923                 if ( fTextSegmentBinds 
)  
1924                         this->makeTextSegmentWritable(context
, false); 
1928         // set up dyld entry points in image 
1929         this->setupLazyPointerHandler(context
); 
1931         CRSetCrashLogMessage2(NULL
); 
1934 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext
& context
) 
1936         // some API called requested that all lazy pointers in this image be force bound 
1937         this->bindIndirectSymbolPointers(context
, false, true); 
1940 void ImageLoaderMachOClassic::doInterpose(const LinkContext
& context
) 
1942         if ( context
.verboseInterposing 
) 
1943                 dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples
.size(), this->getPath()); 
1945         // scan indirect symbols 
1946         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1947         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1948         const struct load_command
* cmd 
= cmds
; 
1949         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1951                         case LC_SEGMENT_COMMAND
: 
1953                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1954                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1955                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1956                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1957                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1958                                                 if ( (type 
== S_NON_LAZY_SYMBOL_POINTERS
) || (type 
== S_LAZY_SYMBOL_POINTERS
) ) { 
1959                                                         const size_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
1960                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1961                                                         for (size_t pointerIndex
=0; pointerIndex 
< pointerCount
; ++pointerIndex
) { 
1962                                                                 uintptr_t newValue 
= interposedAddress(context
, symbolPointers
[pointerIndex
], this); 
1963                                                                 if ( newValue 
!= symbolPointers
[pointerIndex
] ) 
1964                                                                         symbolPointers
[pointerIndex
] = newValue
; 
1968                                                 // i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking 
1969                                                 else if ( (type 
== S_SYMBOL_STUBS
) && ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2 
== 5) ) { 
1970                                                         // check each jmp entry in this section 
1971                                                         uint8_t* start 
= (uint8_t*)(sect
->addr 
+ this->fSlide
); 
1972                                                         uint8_t* end 
= start 
+ sect
->size
; 
1973                                                         for (uint8_t* entry 
= start
; entry 
< end
; entry 
+= 5) { 
1974                                                                 if ( entry
[0] == 0xE9 ) { // 0xE9 == JMP  
1975                                                                         uint32_t rel32 
= *((uint32_t*)&entry
[1]); // assume unaligned load of uint32_t is ok 
1976                                                                         uint32_t target 
= (uint32_t)&entry
[5] + rel32
; 
1977                                                                         uint32_t newTarget 
= interposedAddress(context
, target
, this); 
1978                                                                         if ( newTarget 
!= target 
) { 
1979                                                                                 uint32_t newRel32 
= newTarget 
- (uint32_t)&entry
[5]; 
1980                                                                                 *((uint32_t*)&entry
[1]) = newRel32
; // assume unaligned store of uint32_t is ok 
1990                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1993         // scan external relocations  
1994         const uintptr_t relocBase 
= this->getRelocBase(); 
1995         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
1996         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
1997         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1998                 if (reloc
->r_length 
== RELOC_SIZE
) { 
1999                         switch(reloc
->r_type
) { 
2002                                                 uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
2003                                                 uintptr_t value 
= *location
; 
2004                                                 uintptr_t newValue 
= interposedAddress(context
, value
, this); 
2005                                                 if ( newValue 
!= value 
) 
2006                                                         *location 
= newValue
; 
2014 void ImageLoaderMachOClassic::dynamicInterpose(const LinkContext
& context
)  
2016         if ( context
.verboseInterposing 
) 
2017                 dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context
.dynamicInterposeCount
, this->getPath()); 
2019         // scan indirect symbols 
2020         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2021         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2022         const struct load_command
* cmd 
= cmds
; 
2023         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2025                         case LC_SEGMENT_COMMAND
: 
2027                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2028                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2029                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2030                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2031                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2032                                                 if ( (type 
== S_NON_LAZY_SYMBOL_POINTERS
) || (type 
== S_LAZY_SYMBOL_POINTERS
) ) { 
2033                                                         const size_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
2034                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
2035                                                         for (size_t pointerIndex
=0; pointerIndex 
< pointerCount
; ++pointerIndex
) { 
2036                                                                 for(size_t j
=0; j 
< context
.dynamicInterposeCount
; ++j
) { 
2037                                                                         // replace all references to 'replacee' with 'replacement' 
2038                                                                         if ( symbolPointers
[pointerIndex
] == (uintptr_t)context
.dynamicInterposeArray
[j
].replacee 
) { 
2039                                                                                 if ( context
.verboseInterposing 
) { 
2040                                                                                         dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",  
2041                                                                                                 &symbolPointers
[pointerIndex
], context
.dynamicInterposeArray
[j
].replacee
, context
.dynamicInterposeArray
[j
].replacement
, this->getPath()); 
2043                                                                                 symbolPointers
[pointerIndex
] = (uintptr_t)context
.dynamicInterposeArray
[j
].replacement
; 
2052                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2055         // scan external relocations  
2056         const uintptr_t relocBase 
= this->getRelocBase(); 
2057         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
2058         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
2059         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
2060                 if (reloc
->r_length 
== RELOC_SIZE
) { 
2061                         switch(reloc
->r_type
) { 
2064                                                 uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
2065                                                 for(size_t i
=0; i 
< context
.dynamicInterposeCount
; ++i
) { 
2066                                                         // replace all references to 'replacee' with 'replacement' 
2067                                                         if ( *location 
== (uintptr_t)context
.dynamicInterposeArray
[i
].replacee 
) { 
2068                                                                 if ( context
.verboseInterposing 
) { 
2069                                                                         dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n",  
2070                                                                                 location
, context
.dynamicInterposeArray
[i
].replacee
, context
.dynamicInterposeArray
[i
].replacement
, this->getPath()); 
2072                                                                 *location 
= (uintptr_t)context
.dynamicInterposeArray
[i
].replacement
; 
2083 const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr
, const void** closestAddr
) const 
2085         uintptr_t targetAddress 
= (uintptr_t)addr 
- fSlide
; 
2086         const struct macho_nlist
* bestSymbol 
= NULL
; 
2087         // first walk all global symbols 
2088         const struct macho_nlist
* const globalsStart 
= &fSymbolTable
[fDynamicInfo
->iextdefsym
]; 
2089         const struct macho_nlist
* const globalsEnd
= &globalsStart
[fDynamicInfo
->nextdefsym
]; 
2090         for (const struct macho_nlist
* s 
= globalsStart
; s 
< globalsEnd
; ++s
) { 
2091                 if ( (s
->n_type 
& N_TYPE
) == N_SECT 
) { 
2092                         if ( bestSymbol 
== NULL 
) { 
2093                                 if ( s
->n_value 
<= targetAddress 
) 
2096                         else if ( (s
->n_value 
<= targetAddress
) && (bestSymbol
->n_value 
< s
->n_value
) ) { 
2101         // next walk all local symbols 
2102         const struct macho_nlist
* const localsStart 
= &fSymbolTable
[fDynamicInfo
->ilocalsym
]; 
2103         const struct macho_nlist
* const localsEnd
= &localsStart
[fDynamicInfo
->nlocalsym
]; 
2104         for (const struct macho_nlist
* s 
= localsStart
; s 
< localsEnd
; ++s
) { 
2105                 if ( ((s
->n_type 
& N_TYPE
) == N_SECT
) && ((s
->n_type 
& N_STAB
) == 0) ) { 
2106                         if ( bestSymbol 
== NULL 
) { 
2107                                 if ( s
->n_value 
<= targetAddress 
) 
2110                         else if ( (s
->n_value 
<= targetAddress
) && (bestSymbol
->n_value 
< s
->n_value
) ) { 
2115         if ( bestSymbol 
!= NULL 
) { 
2117                 if (bestSymbol
->n_desc 
& N_ARM_THUMB_DEF
) 
2118                         *closestAddr 
= (void*)((bestSymbol
->n_value 
| 1) + fSlide
); 
2120                         *closestAddr 
= (void*)(bestSymbol
->n_value 
+ fSlide
); 
2122                 *closestAddr 
= (void*)(bestSymbol
->n_value 
+ fSlide
); 
2124                 return &fStrings
[bestSymbol
->n_un
.n_strx
];