1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2005 Apple Computer, 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@ 
  27 #include <sys/types.h> 
  30 #include <mach/shared_memory_server.h> 
  31 #include <mach/mach.h> 
  32 #include <mach/thread_status.h> 
  33 #include <mach-o/loader.h>  
  34 #include <mach-o/reloc.h>  
  35 #include <mach-o/nlist.h>  
  36 #include <sys/sysctl.h> 
  37 #include <libkern/OSAtomic.h> 
  38 #if __ppc__ || __ppc64__ 
  39         #include <mach-o/ppc/reloc.h> 
  42         #include <mach-o/x86_64/reloc.h> 
  45 #ifndef S_ATTR_SELF_MODIFYING_CODE 
  46   #define S_ATTR_SELF_MODIFYING_CODE 0x04000000 
  49 #include "ImageLoaderMachO.h" 
  50 #include "mach-o/dyld_gdb.h" 
  52 // no header for this yet, rdar://problem/3850825 
  53 extern "C" void sys_icache_invalidate(void *, size_t); 
  55 // optimize strcmp for ppc 
  57         #include <ppc_intrinsics.h> 
  59         #define astrcmp(a,b) strcmp(a,b) 
  62 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables 
  65         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
  66         #define LC_ROUTINES_COMMAND             LC_ROUTINES_64 
  67         struct macho_header                             
: public mach_header_64  
{}; 
  68         struct macho_segment_command    
: public segment_command_64  
{}; 
  69         struct macho_section                    
: public section_64  
{};         
  70         struct macho_nlist                              
: public nlist_64  
{};   
  71         struct macho_routines_command   
: public routines_command_64  
{};        
  74         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
  75         #define LC_ROUTINES_COMMAND             LC_ROUTINES 
  76         struct macho_header                             
: public mach_header  
{}; 
  77         struct macho_segment_command    
: public segment_command 
{}; 
  78         struct macho_section                    
: public section  
{};    
  79         struct macho_nlist                              
: public nlist  
{};      
  80         struct macho_routines_command   
: public routines_command  
{};   
  84         #define POINTER_RELOC X86_64_RELOC_UNSIGNED 
  86         #define POINTER_RELOC GENERIC_RELOC_VANILLA 
  89 uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs 
= 0; 
  90 uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs 
= 0; 
  91 uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports 
= 0; 
  94 //#define LINKEDIT_USAGE_DEBUG 1 
  96 #if LINKEDIT_USAGE_DEBUG 
  98         static std::set
<uintptr_t> sLinkEditPageBuckets
; 
 101                 extern ImageLoader
*     findImageContainingAddress(const void* addr
); 
 104         static void noteAccessedLinkEditAddress(const void* addr
) 
 106                 uintptr_t page 
= ((uintptr_t)addr
) & (-4096); 
 107                 sLinkEditPageBuckets
.insert(page
); 
 108                 fprintf(stderr
, "dyld: accessing page 0x%08lX in __LINKEDIT of %s\n", page
, dyld::findImageContainingAddress(addr
)->getPath()); 
 112 // only way to share initialization in C++ 
 113 void ImageLoaderMachO::init() 
 116         fLinkEditBase   
= NULL
; 
 122         fHasSubLibraries
= false; 
 123         fHasSubUmbrella 
= false; 
 125         fModInitSection 
= NULL
; 
 126         fModTermSection 
= NULL
; 
 128         fImageNotifySection     
= NULL
; 
 129         fTwoLevelHints  
= NULL
; 
 131         fReExportThruFramework  
= NULL
; 
 132         fTextSegmentWithFixups 
= NULL
; 
 135 // create image by copying an in-memory mach-o file 
 136 ImageLoaderMachO::ImageLoaderMachO(const char* moduleName
, const struct mach_header
* mh
, uint64_t len
, const LinkContext
& context
) 
 137  : ImageLoader(moduleName
) 
 142         // temporary use this buffer until TEXT is mapped in 
 143         fMachOData 
= (const uint8_t*)mh
; 
 146         this->instantiateSegments((const uint8_t*)mh
); 
 149         if ( mh
->filetype 
!= MH_EXECUTE 
) 
 150                 ImageLoader::mapSegments((const void*)mh
, len
, context
); 
 152         // get pointers to interesting things  
 153         this->parseLoadCmds(); 
 157 // create image by mapping in a mach-o file 
 158 ImageLoaderMachO::ImageLoaderMachO(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,  
 159                                                                         uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
) 
 160  : ImageLoader(path
, offsetInFat
, info
) 
 165         // read load commands 
 166         const unsigned int dataSize 
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
; 
 167         uint8_t buffer
[dataSize
]; 
 168         const uint8_t* fileData 
= firstPage
; 
 169         if ( dataSize 
> 4096 ) { 
 170                 // only read more if cmds take up more space than first page 
 172                 memcpy(buffer
, firstPage
, 4096); 
 173                 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096); 
 176         // temporary use this buffer until TEXT is mapped in 
 177         fMachOData 
= fileData
; 
 179         // the meaning of many fields changes in split seg mach-o files 
 180         fIsSplitSeg 
= ((((macho_header
*)fileData
)->flags 
& MH_SPLIT_SEGS
) != 0) && (((macho_header
*)fileData
)->filetype 
== MH_DYLIB
);    
 183         this->instantiateSegments(fileData
); 
 185         // map segments, except for main executable which is already mapped in by kernel 
 186         if ( ((macho_header
*)fileData
)->filetype 
!= MH_EXECUTE 
) 
 187                 this->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
); 
 189         // get pointers to interesting things  
 190         this->parseLoadCmds(); 
 193 ImageLoaderMachO::~ImageLoaderMachO() 
 195         // keep count of images with weak exports 
 196         if ( this->hasCoalescedExports() ) 
 197                 --fgCountOfImagesWithWeakExports
; 
 202 void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData
) 
 204         const uint32_t cmd_count 
= ((macho_header
*)fileData
)->ncmds
; 
 205         const struct load_command
* const cmds 
= (struct load_command
*)&fileData
[sizeof(macho_header
)]; 
 207         // construct Segment object for each LC_SEGMENT cmd and add to list 
 208         const struct load_command
* cmd 
= cmds
; 
 209         for (unsigned long i 
= 0; i 
< cmd_count
; ++i
) { 
 210                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 211                         if ( (((struct macho_segment_command
*)cmd
)->vmsize 
!= 0) || !fIsSplitSeg 
) 
 212                                 fSegments
.push_back(new SegmentMachO((struct macho_segment_command
*)cmd
, this, fileData
)); 
 214                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 220 bool ImageLoaderMachO::segmentsMustSlideTogether() const  
 225 bool ImageLoaderMachO::segmentsCanSlide() const  
 227         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 228         return ( (mh
->filetype 
== MH_DYLIB
) || (mh
->filetype 
== MH_BUNDLE
) ); 
 231 bool ImageLoaderMachO::isBundle() const  
 233         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 234         return ( mh
->filetype 
== MH_BUNDLE 
); 
 237 bool ImageLoaderMachO::isDylib() const  
 239         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 240         return ( mh
->filetype 
== MH_DYLIB 
); 
 243 bool ImageLoaderMachO::forceFlat() const  
 245         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 246         return ( (mh
->flags 
& MH_FORCE_FLAT
) != 0 ); 
 249 bool ImageLoaderMachO::usesTwoLevelNameSpace() const 
 251         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 252         return ( (mh
->flags 
& MH_TWOLEVEL
) != 0 ); 
 255 bool ImageLoaderMachO::isPrebindable() const  
 257         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 258         return ( (mh
->flags 
& MH_PREBOUND
) != 0 ); 
 261 bool ImageLoaderMachO::hasCoalescedExports() const  
 263         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 264         return ( (mh
->flags 
& MH_WEAK_DEFINES
) != 0 ); 
 267 bool ImageLoaderMachO::needsCoalescing() const  
 269         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 270         return ( (mh
->flags 
& MH_BINDS_TO_WEAK
) != 0 ); 
 273 #if !__LP64__   // split segs not supported for 64-bits 
 275 #if 1 // hack until kernel headers and glue are in system 
 276 struct _shared_region_mapping_np 
{ 
 277     mach_vm_address_t   address
; 
 279     mach_vm_offset_t    file_offset
; 
 280         vm_prot_t               max_prot
;   /* read/write/execute/COW/ZF */ 
 281         vm_prot_t               init_prot
;  /* read/write/execute/COW/ZF */ 
 283 struct _shared_region_range_np 
{ 
 284     mach_vm_address_t   address
; 
 289 // Requests the kernel to map a number of regions from the fd into the 
 290 // shared sections address range (0x90000000-0xAFFFFFFF). 
 291 // If shared_region_make_private_np() has not been called by this process,  
 292 // the file mapped in is seen in the address space of all processes that 
 293 // participate in using the shared region.  
 294 // If shared_region_make_private_np() _has_ been called by this process,  
 295 // the file mapped in is only seen by this process. 
 296 // If the slide parameter is not NULL and then regions cannot be mapped 
 297 // as requested, the kernel will try to map the file in at a different 
 298 // address in the shared region and return the distance slid.  
 299 // If the mapping requesting cannot be fulfilled, returns non-zero. 
 301 _shared_region_map_file_np( 
 302         int fd
,                                                 // file descriptor to map into shared region 
 303         unsigned int regionCount
,               // number of entres in array of regions 
 304         const _shared_region_mapping_np regions
[],      // the array of regions to map 
 305         uint64_t* slide
)                                        // the amount all regions were slid,  NULL means don't attempt to slide 
 307         //fprintf(stderr, "%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide); 
 308         //for ( unsigned int i=0; i < regionCount; ++i) { 
 309         //      fprintf(stderr, "\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size); 
 311         int r 
= syscall(299, fd
, regionCount
, regions
, slide
); 
 313 //              fprintf(stderr, "%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno)); 
 316 // Called by dyld if shared_region_map_file() fails. 
 317 // Requests the kernel to take this process out of using the shared region. 
 318 // The specified ranges are created as private copies from the shared region for this process. 
 320 _shared_region_make_private_np( 
 321         unsigned int rangeCount
,                                // number of entres in array of msrp_range 
 322         const _shared_region_range_np ranges
[]) // the array of shared regions to make private 
 324         //fprintf(stderr, "%s(%u, %8p)\n", __func__, rangeCount, ranges); 
 325         int r 
= syscall(300, rangeCount
, ranges
); 
 327 //              fprintf(stderr, "%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno)); 
 330 #define KERN_SHREG_PRIVATIZABLE 54 
 331 #endif // hack until kernel headers and glue are in system 
 333 static uintptr_t sNextAltLoadAddress 
 
 341 _shared_region_map_file_with_mmap( 
 342         int fd
,                                                 // file descriptor to map into shared region 
 343         unsigned int regionCount
,               // number of entres in array of regions 
 344         const _shared_region_mapping_np regions
[])      // the array of regions to map 
 346         // map in each region 
 347         for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 348                 void* mmapAddress 
= (void*)(uintptr_t)(regions
[i
].address
); 
 349                 size_t size 
= regions
[i
].size
; 
 350                 if ( (regions
[i
].init_prot 
& VM_PROT_ZF
) != 0 ) { 
 351                         // do nothing already vm_allocate() which zero fills 
 355                         if ( regions
[i
].init_prot 
& VM_PROT_EXECUTE 
) 
 356                                 protection   
|= PROT_EXEC
; 
 357                         if ( regions
[i
].init_prot 
& VM_PROT_READ 
) 
 358                                 protection   
|= PROT_READ
; 
 359                         if ( regions
[i
].init_prot 
& VM_PROT_WRITE 
) 
 360                                 protection   
|= PROT_WRITE
; 
 361                         off_t offset 
= regions
[i
].file_offset
; 
 362                         //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath); 
 363                         mmapAddress 
= mmap(mmapAddress
, size
, protection
, MAP_FILE 
| MAP_FIXED 
| MAP_PRIVATE
, fd
, offset
); 
 364                         if ( mmapAddress 
== ((void*)(-1)) ) 
 375 hasSharedRegionMapFile(void) 
 377         int     mib
[CTL_MAXNAME
]; 
 382         mib
[1] = KERN_SHREG_PRIVATIZABLE
; 
 384         if (sysctl(mib
, 2, &value
, &size
, NULL
, 0) != 0) { 
 392 ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd
, 
 393                                                                                                         uint64_t offsetInFat
, 
 396                                                                                                         const LinkContext
& context
) 
 398         const unsigned int segmentCount 
= fSegments
.size(); 
 399         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 400         const unsigned int regionCount 
= segmentCount
+extraZeroFillEntries
; 
 401         _shared_region_mapping_np regions
[regionCount
]; 
 402         initMappingTable(offsetInFat
, regions
); 
 404                 // find space somewhere to allocate split seg 
 405                 bool foundRoom 
= false; 
 406                 vm_size_t biggestDiff 
= 0; 
 407                 while ( ! foundRoom 
) { 
 409                         for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 410                                 vm_address_t addr 
= sNextAltLoadAddress 
+ regions
[i
].address 
- regions
[0].address
; 
 411                                 vm_size_t size 
= regions
[i
].size 
; 
 412                                 r 
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/); 
 414                                         // no room here, deallocate what has succeeded so far 
 415                                         for(unsigned int j
=0; j 
< i
; ++j
) { 
 416                                                 vm_address_t addr 
= sNextAltLoadAddress 
+ regions
[j
].address 
- regions
[0].address
; 
 417                                                 vm_size_t size 
= regions
[j
].size 
; 
 418                                                 (void)vm_deallocate(mach_task_self(), addr
, size
); 
 420                                         sNextAltLoadAddress 
+= 0x00100000;  // skip ahead 1MB and try again 
 421                                         if ( (sNextAltLoadAddress 
& 0xF0000000) == 0x90000000 ) 
 422                                                 sNextAltLoadAddress 
= 0xB0000000; 
 423                                         if ( (sNextAltLoadAddress 
& 0xF0000000) == 0xF0000000 ) 
 424                                                 throw "can't map split seg anywhere"; 
 428                                 vm_size_t high 
= (regions
[i
].address 
+ size 
- regions
[0].address
) & 0x0FFFFFFF; 
 429                                 if ( high 
> biggestDiff 
) 
 434                 // map in each region 
 435                 uintptr_t slide 
= sNextAltLoadAddress 
- regions
[0].address
; 
 436                 this->setSlide(slide
); 
 437                 for(unsigned int i
=0; i 
< regionCount
; ++i
) { 
 438                         if ( (regions
[i
].init_prot 
& VM_PROT_ZF
) != 0 ) { 
 439                                 // do nothing vm_allocate() zero-fills by default 
 442                                 void* mmapAddress 
= (void*)(uintptr_t)(regions
[i
].address 
+ slide
); 
 443                                 size_t size 
= regions
[i
].size
; 
 445                                 if ( regions
[i
].init_prot 
& VM_PROT_EXECUTE 
) 
 446                                         protection   
|= PROT_EXEC
; 
 447                                 if ( regions
[i
].init_prot 
& VM_PROT_READ 
) 
 448                                         protection   
|= PROT_READ
; 
 449                                 if ( regions
[i
].init_prot 
& VM_PROT_WRITE 
) 
 450                                         protection   
|= PROT_WRITE
; 
 451                                 off_t offset 
= regions
[i
].file_offset
; 
 452                                 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath); 
 453                                 mmapAddress 
= mmap(mmapAddress
, size
, protection
, MAP_FILE 
| MAP_FIXED 
| MAP_PRIVATE
, fd
, offset
); 
 454                                 if ( mmapAddress 
== ((void*)(-1)) ) 
 458                 // set so next maps right after this one 
 459                 sNextAltLoadAddress 
+= biggestDiff
;  
 460                 sNextAltLoadAddress 
= (sNextAltLoadAddress 
+ 4095) & (-4096); 
 463                 if ( context
.verboseMapping 
) { 
 464                         fprintf(stderr
, "dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath()); 
 465                         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 466                                 Segment
* seg 
= fSegments
[segIndex
]; 
 467                                 const _shared_region_mapping_np
* entry 
= ®ions
[entryIndex
]; 
 468                                 if ( (entry
->init_prot 
& VM_PROT_ZF
) == 0 )  
 469                                         fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n", 
 470                                                         seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1); 
 471                                 if ( entryIndex 
< (regionCount
-1) ) { 
 472                                         const _shared_region_mapping_np
* nextEntry 
= ®ions
[entryIndex
+1]; 
 473                                         if ( (nextEntry
->init_prot 
& VM_PROT_ZF
) != 0 ) { 
 474                                                 uint64_t segOffset 
= nextEntry
->address 
- entry
->address
; 
 475                                                 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n", 
 476                                                                 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset 
+ nextEntry
->size 
- 1)); 
 487 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
) 
 489         enum SharedRegionState
 
 491                 kSharedRegionStartState 
= 0, 
 492                 kSharedRegionLoadFileState
, 
 493                 kSharedRegionMapFileState
, 
 494                 kSharedRegionMapFilePrivateState
, 
 495                 kSharedRegionMapFilePrivateMMapState
, 
 496                 kSharedRegionMapFilePrivateOutsideState
, 
 498         static SharedRegionState sSharedRegionState 
= kSharedRegionStartState
; 
 500         // non-split segment libraries handled by super class 
 502                 return ImageLoader::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
); 
 504         if ( kSharedRegionStartState 
== sSharedRegionState 
) { 
 505                 if ( hasSharedRegionMapFile() ) { 
 506                         if ( context
.slideAndPackDylibs 
) {  
 507                                 sharedRegionMakePrivate(context
); 
 508                                 // remove underlying submap and block out 0x90000000 to 0xAFFFFFFF 
 509                                 vm_address_t addr 
= (vm_address_t
)0x90000000; 
 510                                 vm_deallocate(mach_task_self(), addr
, 0x20000000); 
 511                                 vm_allocate(mach_task_self(), &addr
, 0x20000000, false); 
 512                                 sSharedRegionState 
= kSharedRegionMapFilePrivateMMapState
; 
 514                         else if ( context
.sharedRegionMode 
== kUsePrivateSharedRegion 
) {  
 515                                 sharedRegionMakePrivate(context
); 
 516                                 sSharedRegionState 
= kSharedRegionMapFilePrivateState
; 
 518                         else if ( context
.sharedRegionMode 
== kDontUseSharedRegion 
) { 
 519                                 sSharedRegionState 
= kSharedRegionMapFilePrivateOutsideState
; 
 522                                 sSharedRegionState 
= kSharedRegionMapFileState
; 
 526                         sSharedRegionState 
= kSharedRegionLoadFileState
; 
 530         if ( kSharedRegionLoadFileState 
== sSharedRegionState 
) { 
 531                 if ( 0 != sharedRegionLoadFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) { 
 532                         sSharedRegionState 
= kSharedRegionMapFilePrivateOutsideState
; 
 536         if ( kSharedRegionMapFileState 
== sSharedRegionState 
) { 
 537                 if ( 0 != sharedRegionMapFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) { 
 538                         sharedRegionMakePrivate(context
); 
 539                         sSharedRegionState 
= kSharedRegionMapFilePrivateState
; 
 543         if ( (kSharedRegionMapFilePrivateState 
== sSharedRegionState
) || (kSharedRegionMapFilePrivateMMapState 
== sSharedRegionState
) ) { 
 544                 if ( 0 != sharedRegionMapFilePrivate(fd
, offsetInFat
, lenInFat
, fileLen
, context
, (kSharedRegionMapFilePrivateMMapState 
== sSharedRegionState
)) ) { 
 545                         sSharedRegionState 
= kSharedRegionMapFilePrivateOutsideState
; 
 549         if ( kSharedRegionMapFilePrivateOutsideState 
== sSharedRegionState 
) { 
 550                 if ( 0 != sharedRegionMapFilePrivateOutside(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) { 
 551                         throw "mapping error"; 
 557 ImageLoaderMachO::getExtraZeroFillEntriesCount() 
 559         // calculate mapping entries 
 560         const unsigned int segmentCount 
= fSegments
.size(); 
 561         unsigned int extraZeroFillEntries 
= 0; 
 562         for(unsigned int i
=0; i 
< segmentCount
; ++i
){ 
 563                 Segment
* seg 
= fSegments
[i
]; 
 564                 if ( seg
->hasTrailingZeroFill() ) 
 565                         ++extraZeroFillEntries
; 
 568         return extraZeroFillEntries
; 
 572 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
, 
 573                                                                    _shared_region_mapping_np 
*mappingTable
) 
 575         unsigned int segmentCount 
= fSegments
.size(); 
 576         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 577                 Segment
* seg 
= fSegments
[segIndex
]; 
 578                 _shared_region_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 579                 entry
->address                  
= seg
->getActualLoadAddress(); 
 580                 entry
->size                             
= seg
->getFileSize(); 
 581                 entry
->file_offset              
= seg
->getFileOffset() + offsetInFat
; 
 582                 entry
->init_prot                
= VM_PROT_NONE
; 
 583                 if ( !seg
->unaccessible() ) { 
 584                         if ( seg
->executable() ) 
 585                                 entry
->init_prot   
|= VM_PROT_EXECUTE
; 
 586                         if ( seg
->readable() ) 
 587                                 entry
->init_prot   
|= VM_PROT_READ
; 
 588                         if ( seg
->writeable() ) 
 589                                 entry
->init_prot   
|= VM_PROT_WRITE 
| VM_PROT_COW
; 
 591                 entry
->max_prot                 
= entry
->init_prot
; 
 592                 if ( seg
->hasTrailingZeroFill() ) { 
 593                         _shared_region_mapping_np
* zfentry 
= &mappingTable
[++entryIndex
]; 
 594                         zfentry
->address                
= entry
->address 
+ seg
->getFileSize(); 
 595                         zfentry
->size                   
= seg
->getSize() - seg
->getFileSize(); 
 596                         zfentry
->file_offset    
= 0; 
 597                         zfentry
->init_prot              
= entry
->init_prot 
| VM_PROT_COW 
| VM_PROT_ZF
; 
 598                         zfentry
->max_prot               
= zfentry
->init_prot
; 
 604 ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext
& context
) 
 606         if ( context
.verboseMapping 
) 
 607                 fprintf(stderr
, "dyld: making shared regions private\n"); 
 609         // shared mapping failed, so make private copy of shared region and try mapping private 
 610         RegionsVector allRegions
; 
 611         context
.getAllMappedRegions(allRegions
); 
 612         std::vector
<_shared_region_range_np
> splitSegRegions
; 
 613         const unsigned int allRegiontCount 
= allRegions
.size(); 
 614         for(unsigned int i
=0; i 
< allRegiontCount
; ++i
){ 
 615                 MappedRegion region 
= allRegions
[i
]; 
 616                 uint8_t highByte 
= region
.address 
>> 28; 
 617                 if ( (highByte 
== 9) || (highByte 
== 0xA) ) { 
 618                         _shared_region_range_np splitRegion
; 
 619                         splitRegion
.address 
= region
.address
; 
 620                         splitRegion
.size 
= region
.size
; 
 621                         splitSegRegions
.push_back(splitRegion
); 
 624         int result 
= _shared_region_make_private_np(splitSegRegions
.size(), &splitSegRegions
[0]); 
 625         // notify gdb or other lurkers that this process is no longer using the shared region 
 626         dyld_all_image_infos
.processDetachedFromSharedRegion 
= true; 
 631 ImageLoaderMachO::sharedRegionMapFile(int fd
, 
 632                                          uint64_t offsetInFat
, 
 635                                          const LinkContext
& context
) 
 637         // build table of segments to map 
 638         const unsigned int segmentCount 
= fSegments
.size(); 
 639         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 640         const unsigned int mappingTableCount 
= segmentCount
+extraZeroFillEntries
; 
 641         _shared_region_mapping_np mappingTable
[mappingTableCount
]; 
 642         initMappingTable(offsetInFat
, mappingTable
); 
 644         uint64_t *slidep 
= NULL
; 
 646         // try to map it in shared 
 647         int r 
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, slidep
); 
 649                 if(NULL 
!= slidep 
&& 0 != *slidep
) { 
 650                         // update with actual load addresses 
 652                 if ( context
.verboseMapping 
) { 
 653                         fprintf(stderr
, "dyld: Mapping split-seg shared %s\n", this->getPath()); 
 654                         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 655                                 Segment
* seg 
= fSegments
[segIndex
]; 
 656                                 const _shared_region_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 657                                 if ( (entry
->init_prot 
& VM_PROT_ZF
) == 0 )  
 658                                         fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n", 
 659                                                         seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1); 
 660                                 if ( entryIndex 
< (mappingTableCount
-1) ) { 
 661                                         const _shared_region_mapping_np
* nextEntry 
= &mappingTable
[entryIndex
+1]; 
 662                                         if ( (nextEntry
->init_prot 
& VM_PROT_ZF
) != 0 ) { 
 663                                                 uint64_t segOffset 
= nextEntry
->address 
- entry
->address
; 
 664                                                 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n", 
 665                                                                 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset 
+ nextEntry
->size 
- 1)); 
 677 ImageLoaderMachO::sharedRegionMapFilePrivate(int fd
, 
 678                                                                                          uint64_t offsetInFat
, 
 681                                                                                          const LinkContext
& context
, 
 684         const unsigned int segmentCount 
= fSegments
.size(); 
 686         // adjust base address of segments to pack next to last dylib 
 687         if ( context
.slideAndPackDylibs 
) { 
 688                 uintptr_t lowestReadOnly 
= (uintptr_t)(-1); 
 689                 uintptr_t lowestWritable 
= (uintptr_t)(-1); 
 690                 for(unsigned int segIndex
=0; segIndex 
< segmentCount
; ++segIndex
){ 
 691                         Segment
* seg 
= fSegments
[segIndex
]; 
 692                         uintptr_t segEnd 
= seg
->getActualLoadAddress(); 
 693                         if ( seg
->writeable() ) { 
 694                                 if ( segEnd 
< lowestWritable 
) 
 695                                         lowestWritable 
= segEnd
; 
 698                                 if ( segEnd 
< lowestReadOnly 
) 
 699                                         lowestReadOnly 
= segEnd
; 
 702                 uintptr_t baseAddress
; 
 703                 if ( lowestWritable 
- 256*1024*1024 < lowestReadOnly 
) 
 704                         baseAddress 
= lowestWritable 
- 256*1024*1024; 
 706                         baseAddress 
= lowestReadOnly
; 
 707                 // record that we want dylb slid to fgNextSplitSegAddress 
 708                 this->setSlide(fgNextSplitSegAddress 
- baseAddress
); 
 711         // build table of segments to map 
 712         const unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 713         const unsigned int mappingTableCount 
= segmentCount
+extraZeroFillEntries
; 
 714         _shared_region_mapping_np mappingTable
[mappingTableCount
]; 
 715         initMappingTable(offsetInFat
, mappingTable
); 
 718         // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs) 
 721                 r 
= _shared_region_map_file_with_mmap(fd
, mappingTableCount
, mappingTable
); 
 723                 r 
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, context
.slideAndPackDylibs 
? NULL 
: &slide
); 
 726                         slide 
= (slide
) & (-4096); // round down to page boundary 
 727                         this->setSlide(slide
); 
 729                 if ( context
.verboseMapping 
) { 
 731                                 fprintf(stderr
, "dyld: Mapping split-seg un-shared %s\n", this->getPath()); 
 733                                 fprintf(stderr
, "dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide
, this->getPath()); 
 734                         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 735                                 Segment
* seg 
= fSegments
[segIndex
]; 
 736                                 const _shared_region_mapping_np
* entry 
= &mappingTable
[entryIndex
]; 
 737                                 if ( (entry
->init_prot 
& VM_PROT_ZF
) == 0 )  
 738                                         fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n", 
 739                                                         seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1); 
 740                                 if ( entryIndex 
< (mappingTableCount
-1) ) { 
 741                                         const _shared_region_mapping_np
* nextEntry 
= &mappingTable
[entryIndex
+1]; 
 742                                         if ( (nextEntry
->init_prot 
& VM_PROT_ZF
) != 0 ) { 
 743                                                 uint64_t segOffset 
= nextEntry
->address 
- entry
->address
; 
 744                                                 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n", 
 745                                                                 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset 
+ nextEntry
->size 
- 1)); 
 751                 if ( context
.slideAndPackDylibs 
) { 
 752                         // calculate where next split-seg dylib can load 
 753                         uintptr_t largestReadOnly 
= 0; 
 754                         uintptr_t largestWritable 
= 0; 
 755                         for (unsigned int segIndex
=0; segIndex 
< segmentCount
; ++segIndex
) { 
 756                                 Segment
* seg 
= fSegments
[segIndex
]; 
 757                                 uintptr_t segEnd 
= seg
->getActualLoadAddress()+seg
->getSize(); 
 758                                 segEnd 
= (segEnd
+4095) & (-4096); // page align 
 759                                 if ( seg
->writeable() ) { 
 760                                         if ( segEnd 
> largestWritable 
) 
 761                                                 largestWritable 
= segEnd
; 
 764                                         if ( segEnd 
> largestReadOnly 
) 
 765                                                 largestReadOnly 
= segEnd
; 
 768                         if ( largestWritable 
- 256*1024*1024 > largestReadOnly 
) 
 769                                 fgNextSplitSegAddress 
= largestWritable 
- 256*1024*1024; 
 771                                 fgNextSplitSegAddress 
= largestReadOnly
; 
 774         if ( context
.slideAndPackDylibs 
&& (r 
!= 0) ) 
 775                 throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r
); 
 782 ImageLoaderMachO::sharedRegionLoadFile(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
) 
 785         // map in split segment file at random address, then tell kernel to share it 
 786         void* loadAddress 
= 0; 
 787         loadAddress 
= mmap(NULL
, fileLen
, PROT_READ
, MAP_FILE
, fd
, 0); 
 788         if ( loadAddress 
== ((void*)(-1)) ) 
 791         // calculate mapping entries 
 792         const unsigned int segmentCount 
= fSegments
.size(); 
 793         unsigned int extraZeroFillEntries 
= getExtraZeroFillEntriesCount(); 
 795         // build table of segments to map 
 796         const unsigned int mappingTableCount 
= segmentCount
+extraZeroFillEntries
; 
 797         const uintptr_t baseAddress 
= fSegments
[0]->getPreferredLoadAddress(); 
 798         sf_mapping mappingTable
[mappingTableCount
]; 
 799         initMappingTable(offsetInFat
, mappingTable
, baseAddress
); 
 802         // use load_shared_file() to map all segments at once 
 803         int flags 
= 0; // might need to set NEW_LOCAL_SHARED_REGIONS on first use 
 804         static bool firstTime 
= true; 
 806                 // when NEW_LOCAL_SHARED_REGIONS bit is set, this process will get is own shared region 
 807                 // this is used by Xcode to prevent development libraries from polluting the global shared segment 
 808                 if ( context
.sharedRegionMode 
== kUsePrivateSharedRegion 
) 
 809                         flags 
|= NEW_LOCAL_SHARED_REGIONS
; 
 813         caddr_t base_address 
= (caddr_t
)baseAddress
; 
 815         r 
= load_shared_file(   (char*)fPath
,           // path of file to map shared 
 816                                                         (char*)loadAddress
, // beginning of local copy of sharable pages in file 
 817                                                         fileLen
,                        // end of shareable pages in file 
 818                                                         &base_address
,          // beginning of address range to map 
 819                                                         mappingTableCount
,  // number of entres in array of sf_mapping 
 820                                                         mappingTable
,           // the array of sf_mapping 
 821                                                         &flags
);                        // in/out flags 
 823                 // try again but tell kernel it is ok to slide 
 824                 flags 
|= ALTERNATE_LOAD_SITE
; 
 825                 r 
= load_shared_file((char*)fPath
,(char*)loadAddress
, fileLen
, &base_address
,    
 826                                                         mappingTableCount
, mappingTable
, &flags
); 
 829         // unmap file from random address now that they are (hopefully) mapped into the shared region 
 830         munmap(loadAddress
, fileLen
); 
 833                 if ( base_address 
!= (caddr_t
)baseAddress 
) 
 834                         this->setSlide((uintptr_t)base_address 
- baseAddress
); 
 835                 if ( context
.verboseMapping 
) { 
 836                         if ( base_address 
!= (caddr_t
)baseAddress 
) 
 837                                 fprintf(stderr
, "dyld: Mapping split-seg load_shared_alt_region %s\n", this->getPath()); 
 839                                 fprintf(stderr
, "dyld: Mapping split-seg load_shared %s\n", this->getPath()); 
 840                         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 841                                 Segment
* seg 
= fSegments
[segIndex
]; 
 842                                 const sf_mapping
* entry 
= &mappingTable
[entryIndex
]; 
 843                                 if ( (entry
->protection 
& VM_PROT_ZF
) == 0 ) 
 844                                         fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n", 
 845                                                         seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1); 
 846                                 if ( entryIndex 
< (mappingTableCount
-1) ) { 
 847                                         const sf_mapping
* nextEntry 
= &mappingTable
[entryIndex
+1]; 
 848                                         if ( (nextEntry
->protection 
& VM_PROT_ZF
) != 0 ) { 
 849                                                 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n", 
 850                                                         seg
->getName(), (uintptr_t)(nextEntry
->mapping_offset 
+ base_address
), (uintptr_t)(nextEntry
->mapping_offset 
+ base_address 
+ nextEntry
->size 
- 1)); 
 860 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
, 
 861                                                                    sf_mapping 
*mappingTable
, 
 862                                                                    uintptr_t baseAddress
) 
 864         unsigned int segmentCount 
= fSegments
.size(); 
 865         for(unsigned int segIndex
=0,entryIndex
=0; segIndex 
< segmentCount
; ++segIndex
, ++entryIndex
){ 
 866                 Segment
* seg 
= fSegments
[segIndex
]; 
 867                 sf_mapping
* entry 
= &mappingTable
[entryIndex
]; 
 868                 entry
->mapping_offset   
= seg
->getPreferredLoadAddress() - baseAddress
; 
 869                 entry
->size                             
= seg
->getFileSize(); 
 870                 entry
->file_offset              
= seg
->getFileOffset() + offsetInFat
; 
 871                 entry
->protection               
= VM_PROT_NONE
; 
 872                 if ( !seg
->unaccessible() ) { 
 873                         if ( seg
->executable() ) 
 874                                 entry
->protection   
|= VM_PROT_EXECUTE
; 
 875                         if ( seg
->readable() ) 
 876                                 entry
->protection   
|= VM_PROT_READ
; 
 877                         if ( seg
->writeable() ) 
 878                                 entry
->protection   
|= VM_PROT_WRITE 
| VM_PROT_COW
; 
 882                 if ( seg
->hasTrailingZeroFill() ) { 
 883                         sf_mapping
* zfentry 
= &mappingTable
[++entryIndex
]; 
 884                         zfentry
->mapping_offset 
= entry
->mapping_offset 
+ seg
->getFileSize(); 
 885                         zfentry
->size                   
= seg
->getSize() - seg
->getFileSize(); 
 886                         zfentry
->file_offset    
= 0; 
 887                         zfentry
->protection             
= entry
->protection 
| VM_PROT_COW 
| VM_PROT_ZF
; 
 893 #endif //  !__LP64__  split segs not supported for 64-bits 
 896 void ImageLoaderMachO::setSlide(intptr_t slide
) 
 901 void ImageLoaderMachO::parseLoadCmds() 
 903         // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 
 904         const unsigned int segmentCount 
= fSegments
.size(); 
 905         for(unsigned int i
=0; i 
< segmentCount
; ++i
){ 
 906                 Segment
* seg 
= fSegments
[i
]; 
 907                 // set up pointer to __LINKEDIT segment 
 908                 if ( strcmp(seg
->getName(),"__LINKEDIT") == 0 )  
 909                         fLinkEditBase 
= (uint8_t*)(seg
->getActualLoadAddress() - seg
->getFileOffset()); 
 910                 // __TEXT segment always starts at beginning of file and contains mach_header and load commands 
 911                 if ( strcmp(seg
->getName(),"__TEXT") == 0 ) { 
 912                         if ( seg
->hasFixUps() ) 
 913                                 fTextSegmentWithFixups 
= (SegmentMachO
*)seg
; 
 915                 // some segment always starts at beginning of file and contains mach_header and load commands 
 916                 if ( (seg
->getFileOffset() == 0) && (seg
->getFileSize() != 0) ) { 
 917                         fMachOData 
= (uint8_t*)(seg
->getActualLoadAddress()); 
 921         // keep count of prebound images with weak exports 
 922         if ( this->hasCoalescedExports() ) 
 923                 ++fgCountOfImagesWithWeakExports
; 
 925         // walk load commands (mapped in at start of __TEXT segment) 
 926         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 927         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 928         const struct load_command
* cmd 
= cmds
; 
 929         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 933                                         const struct symtab_command
* symtab 
= (struct symtab_command
*)cmd
; 
 934                                         fStrings 
= (const char*)&fLinkEditBase
[symtab
->stroff
]; 
 935                                         fSymbolTable 
= (struct macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]); 
 939                                 fDynamicInfo 
= (struct dysymtab_command
*)cmd
; 
 941                         case LC_SUB_UMBRELLA
: 
 942                                 fHasSubUmbrella 
= true; 
 944                         case LC_SUB_FRAMEWORK
: 
 946                                         const struct sub_framework_command
* subf 
= (struct sub_framework_command
*)cmd
; 
 947                                         fReExportThruFramework 
= (char*)cmd 
+ subf
->umbrella
.offset
; 
 951                                 fHasSubLibraries 
= true; 
 953                         case LC_ROUTINES_COMMAND
: 
 954                                 fDashInit 
= (struct macho_routines_command
*)cmd
; 
 956                         case LC_SEGMENT_COMMAND
: 
 958                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
 959                                         const bool isDataSeg 
= (strcmp(seg
->segname
, "__DATA") == 0); 
 960                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
 961                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 962                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 963                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
 964                                                 if ( type 
== S_MOD_INIT_FUNC_POINTERS 
) 
 965                                                         fModInitSection 
= sect
; 
 966                                                 else if ( type 
== S_MOD_TERM_FUNC_POINTERS 
) 
 967                                                         fModTermSection 
= sect
; 
 968                                                 else if ( isDataSeg 
&& (strcmp(sect
->sectname
, "__dyld") == 0) ) { 
 971                                                 else if ( isDataSeg 
&& (strcmp(sect
->sectname
, "__image_notify") == 0) ) 
 972                                                         fImageNotifySection 
= sect
; 
 976                         case LC_TWOLEVEL_HINTS
: 
 977                                 fTwoLevelHints 
= (struct twolevel_hints_command
*)cmd
; 
 981                                         fDylibID 
= (struct dylib_command
*)cmd
; 
 984                         case LC_LOAD_WEAK_DYLIB
: 
 985                                 // do nothing, just prevent LC_REQ_DYLD exception from occuring 
 988                                 if ( (cmd
->cmd 
& LC_REQ_DYLD
) != 0 ) 
 989                                         throwf("unknown required load command 0x%08X", cmd
->cmd
); 
 991                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 998 const char* ImageLoaderMachO::getInstallPath() const 
1000         if ( fDylibID 
!= NULL 
) { 
1001                 return (char*)fDylibID 
+ fDylibID
->dylib
.name
.offset
; 
1006 // test if this image is re-exported through parent (the image that loaded this one) 
1007 bool ImageLoaderMachO::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const 
1009         if ( fReExportThruFramework 
!= NULL 
) { 
1010                 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent... 
1011                 const char* parentInstallPath 
= parent
->getInstallPath(); 
1012                 if ( parentInstallPath 
!= NULL 
) { 
1013                         const char* lastSlash 
= strrchr(parentInstallPath
, '/'); 
1014                         if ( lastSlash 
!= NULL 
) { 
1015                                 if ( strcmp(&lastSlash
[1], fReExportThruFramework
) == 0 ) 
1017                                 if ( context
.imageSuffix 
!= NULL 
) { 
1018                                         // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 
1019                                         char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(fReExportThruFramework
)+1]; 
1020                                         strcpy(reexportAndSuffix
, fReExportThruFramework
); 
1021                                         strcat(reexportAndSuffix
, context
.imageSuffix
); 
1022                                         if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 ) 
1031 // test if child is re-exported  
1032 bool ImageLoaderMachO::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const 
1034         if ( fHasSubLibraries 
) { 
1035                 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child... 
1036                 const char* childInstallPath 
= child
->getInstallPath(); 
1037                 if ( childInstallPath 
!= NULL 
) { 
1038                         const char* lastSlash 
= strrchr(childInstallPath
, '/'); 
1039                         if ( lastSlash 
!= NULL 
) { 
1040                                 const char* firstDot 
= strchr(lastSlash
, '.'); 
1042                                 if ( firstDot 
== NULL 
) 
1043                                         len 
= strlen(lastSlash
); 
1045                                         len 
= firstDot
-lastSlash
-1; 
1046                                 char childLeafName
[len
+1]; 
1047                                 strncpy(childLeafName
, &lastSlash
[1], len
); 
1048                                 childLeafName
[len
] = '\0'; 
1049                                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1050                                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1051                                 const struct load_command
* cmd 
= cmds
; 
1052                                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1054                                                 case LC_SUB_LIBRARY
: 
1056                                                                 const struct sub_library_command
* lib 
= (struct sub_library_command
*)cmd
; 
1057                                                                 const char* aSubLibName 
= (char*)cmd 
+ lib
->sub_library
.offset
; 
1058                                                                 if ( strcmp(aSubLibName
, childLeafName
) == 0 ) 
1060                                                                 if ( context
.imageSuffix 
!= NULL 
) { 
1061                                                                         // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end 
1062                                                                         char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1]; 
1063                                                                         strcpy(aSubLibNameAndSuffix
, aSubLibName
); 
1064                                                                         strcat(aSubLibNameAndSuffix
, context
.imageSuffix
); 
1065                                                                         if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 ) 
1071                                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1076         if ( fHasSubUmbrella 
) { 
1077                 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child... 
1078                 const char* childInstallPath 
= child
->getInstallPath(); 
1079                 if ( childInstallPath 
!= NULL 
) { 
1080                         const char* lastSlash 
= strrchr(childInstallPath
, '/'); 
1081                         if ( lastSlash 
!= NULL 
) { 
1082                                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1083                                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1084                                 const struct load_command
* cmd 
= cmds
; 
1085                                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1087                                                 case LC_SUB_UMBRELLA
: 
1089                                                                 const struct sub_umbrella_command
* um 
= (struct sub_umbrella_command
*)cmd
; 
1090                                                                 const char* aSubUmbrellaName 
= (char*)cmd 
+ um
->sub_umbrella
.offset
; 
1091                                                                 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 ) 
1093                                                                 if ( context
.imageSuffix 
!= NULL 
) { 
1094                                                                         // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 
1095                                                                         char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1]; 
1096                                                                         strcpy(umbrellaAndSuffix
, aSubUmbrellaName
); 
1097                                                                         strcat(umbrellaAndSuffix
, context
.imageSuffix
); 
1098                                                                         if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 ) 
1104                                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1113 void* ImageLoaderMachO::getMain() const 
1115         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1116         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1117         const struct load_command
* cmd 
= cmds
; 
1118         for (unsigned long i 
= 0; i 
< cmd_count
; ++i
) { 
1123                                 const ppc_thread_state_t
* registers 
= (ppc_thread_state_t
*)(((char*)cmd
) + 16); 
1124                                 return (void*)registers
->srr0
; 
1126                                 const ppc_thread_state64_t
* registers 
= (ppc_thread_state64_t
*)(((char*)cmd
) + 16); 
1127                                 return (void*)registers
->srr0
; 
1129                                 const i386_thread_state_t
* registers 
= (i386_thread_state_t
*)(((char*)cmd
) + 16); 
1130                                 return (void*)registers
->eip
; 
1132                                 const x86_thread_state64_t
* registers 
= (x86_thread_state64_t
*)(((char*)cmd
) + 16); 
1133                                 return (void*)registers
->rip
; 
1135                                 #warning need processor specific code 
1140                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1146 uint32_t ImageLoaderMachO::doGetDependentLibraryCount() 
1148         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1149         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1151         const struct load_command
* cmd 
= cmds
; 
1152         for (unsigned long i 
= 0; i 
< cmd_count
; ++i
) { 
1155                         case LC_LOAD_WEAK_DYLIB
: 
1159                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1164 void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs
[]) 
1167         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1168         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1169         const struct load_command
* cmd 
= cmds
; 
1170         for (unsigned long i 
= 0; i 
< cmd_count
; ++i
) { 
1173                         case LC_LOAD_WEAK_DYLIB
: 
1175                                 const struct dylib_command
* dylib 
= (struct dylib_command
*)cmd
; 
1176                                 DependentLibrary
* lib 
= &libs
[index
++]; 
1177                                 lib
->name 
= (char*)cmd 
+ dylib
->dylib
.name
.offset
; 
1178                                 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset); 
1180                                 lib
->info
.checksum 
= dylib
->dylib
.timestamp
; 
1181                                 lib
->info
.minVersion 
= dylib
->dylib
.compatibility_version
; 
1182                                 lib
->info
.maxVersion 
= dylib
->dylib
.current_version
; 
1183                                 lib
->required 
= (cmd
->cmd 
== LC_LOAD_DYLIB
); 
1184                                 lib
->checksumMatches 
= false; 
1185                                 lib
->isReExported 
= false; 
1189                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1193 ImageLoader::LibraryInfo 
ImageLoaderMachO::doGetLibraryInfo() 
1196         if ( fDylibID 
!= NULL 
) { 
1197                 info
.minVersion 
= fDylibID
->dylib
.compatibility_version
; 
1198                 info
.maxVersion 
= fDylibID
->dylib
.current_version
; 
1199                 info
.checksum 
= fDylibID
->dylib
.timestamp
; 
1202                 info
.minVersion 
= 0; 
1203                 info
.maxVersion 
= 0;             
1209 uintptr_t ImageLoaderMachO::getFirstWritableSegmentAddress() 
1211         // in split segment libraries r_address is offset from first writable segment 
1212         for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it 
!= fSegments
.end(); ++it
) { 
1213                 if ( (*it
)->writeable() ) { 
1214                         return (*it
)->getActualLoadAddress(); 
1217         throw "no writable segment"; 
1220 uintptr_t ImageLoaderMachO::getRelocBase() 
1223         // r_address is offset from first writable segment 
1224         return getFirstWritableSegmentAddress(); 
1226 #if __ppc__ || __i386__ 
1227         if ( fIsSplitSeg 
) { 
1228                 // in split segment libraries r_address is offset from first writable segment 
1229                 return getFirstWritableSegmentAddress(); 
1233         // in non-split segment libraries r_address is offset from first segment 
1234         return fSegments
[0]->getActualLoadAddress(); 
1238 static inline void otherRelocsPPC(uintptr_t* locationToFix
, uint8_t relocationType
, uint16_t otherHalf
, uintptr_t slide
) 
1240         // low 16 bits of 32-bit ppc instructions need fixing 
1241         struct ppcInstruction 
{ uint16_t opcode
; int16_t immediateValue
; }; 
1242         ppcInstruction
* instruction 
= (ppcInstruction
*)locationToFix
; 
1243         //uint32_t before = *((uint32_t*)locationToFix); 
1244         switch ( relocationType 
) 
1246                 case PPC_RELOC_LO16
:  
1247                         instruction
->immediateValue 
= ((otherHalf 
<< 16) | instruction
->immediateValue
) + slide
; 
1249                 case PPC_RELOC_HI16
:  
1250                         instruction
->immediateValue 
= ((((instruction
->immediateValue 
<< 16) | otherHalf
) + slide
) >> 16); 
1252                 case PPC_RELOC_HA16
:  
1253                         int16_t signedOtherHalf 
= (int16_t)(otherHalf 
& 0xffff); 
1254                         uint32_t temp 
= (instruction
->immediateValue 
<< 16) + signedOtherHalf 
+ slide
; 
1255                         if ( (temp 
& 0x00008000) != 0 ) 
1257                         instruction
->immediateValue 
= temp 
>> 16; 
1259         //uint32_t after = *((uint32_t*)locationToFix); 
1260         //fprintf(stderr, "dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after); 
1264 #if __ppc__ || __i386__ 
1265 void ImageLoaderMachO::resetPreboundLazyPointers(const LinkContext
& context
, uintptr_t relocBase
) 
1267         // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values 
1268         register const uintptr_t slide 
= this->fSlide
; 
1269         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]); 
1270         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nlocrel
]; 
1271         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1272                 if ( (reloc
->r_address 
& R_SCATTERED
) != 0 ) { 
1273                         const struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
1274                         if (sreloc
->r_length 
== RELOC_SIZE
) { 
1275                                 uintptr_t* locationToFix 
= (uintptr_t*)(sreloc
->r_address 
+ relocBase
); 
1276                                 switch(sreloc
->r_type
) { 
1278                                         case PPC_RELOC_PB_LA_PTR
: 
1279                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
1283                                         case GENERIC_RELOC_PB_LA_PTR
: 
1284                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
1294 void ImageLoaderMachO::doRebase(const LinkContext
& context
) 
1296         // if prebound and loaded at prebound address, then no need to rebase 
1297         if ( this->usablePrebinding(context
) ) { 
1298                 // skip rebasing cause prebound and prebinding not disabled 
1299                 ++fgImagesWithUsedPrebinding
; // bump totals for statistics 
1303         // <rdar://problem/5146059> update_prebinding fails if a prebound dylib depends on a non-prebound dylib 
1304         // In the unusual case that we find a prebound dylib dependent on un-prebound dylib and we are running 
1305         // update_prebinding, we want the link of the prebound dylib to fail so that it will be excluded from  
1306         // the list of dylibs to be re-written. 
1307         if ( context
.prebinding 
&& !this->isPrebindable() ) 
1308                 throwf("dylib not prebound: %s", this->getPath()); 
1310         // print why prebinding was not used 
1311         if ( context
.verbosePrebinding 
) { 
1312                 if ( !this->isPrebindable() ) { 
1313                         fprintf(stderr
, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath()); 
1315                 else if ( fSlide 
!= 0 ) { 
1316                         fprintf(stderr
, "dyld: image slid, so could not use prebinding in %s\n", this->getPath()); 
1318                 else if ( !this->allDependentLibrariesAsWhenPreBound() ) { 
1319                         fprintf(stderr
, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath()); 
1321                 else if ( !this->usesTwoLevelNameSpace() ){ 
1322                         fprintf(stderr
, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath()); 
1325                         fprintf(stderr
, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath()); 
1329         // cache values that are used in the following loop 
1330         const uintptr_t relocBase 
= this->getRelocBase(); 
1331         register const uintptr_t slide 
= this->fSlide
; 
1333 #if __ppc__ || __i386__ 
1334         // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers 
1335         if ( this->isPrebindable() ) 
1336                 this->resetPreboundLazyPointers(context
, relocBase
); 
1339         // if loaded at preferred address, no rebasing necessary 
1343         // if there are __TEXT fixups, temporarily make __TEXT writable 
1344         if ( fTextSegmentWithFixups 
!= NULL 
)  
1345                 fTextSegmentWithFixups
->tempWritable(); 
1347         // loop through all local (internal) relocation records 
1348         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]); 
1349         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nlocrel
]; 
1350         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1352                 // only one kind of local relocation supported for x86_64 
1353                 if ( reloc
->r_length 
!= 3 )  
1354                         throw "bad local relocation length"; 
1355                 if ( reloc
->r_type 
!= X86_64_RELOC_UNSIGNED 
)  
1356                         throw "unknown local relocation type"; 
1357                 if ( reloc
->r_pcrel 
!= 0 )  
1358                         throw "bad local relocation pc_rel"; 
1359                 if ( reloc
->r_extern 
!= 0 )  
1360                         throw "extern relocation found with local relocations"; 
1361                 *((uintptr_t*)(reloc
->r_address 
+ relocBase
)) += slide
; 
1363         #if __ppc__ || __ppc64__ || __i386__ 
1364                 if ( (reloc
->r_address 
& R_SCATTERED
) == 0 ) { 
1365                         if ( reloc
->r_symbolnum 
== R_ABS 
) { 
1366                                 // ignore absolute relocations 
1368                         else if (reloc
->r_length 
== RELOC_SIZE
) { 
1369                                 switch(reloc
->r_type
) { 
1370                                         case GENERIC_RELOC_VANILLA
: 
1371                                                 *((uintptr_t*)(reloc
->r_address 
+ relocBase
)) += slide
; 
1374                                         case PPC_RELOC_HI16
:  
1375                                         case PPC_RELOC_LO16
:  
1376                                         case PPC_RELOC_HA16
:  
1377                                                 // some tools leave object file relocations in linked images 
1378                                                 otherRelocsPPC((uintptr_t*)(reloc
->r_address 
+ relocBase
), reloc
->r_type
, reloc
[1].r_address
, slide
); 
1379                                                 ++reloc
; // these relocations come in pairs, skip next 
1383                                                 throw "unknown local relocation type"; 
1387                                 throw "bad local relocation length"; 
1391                         const struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
1392                         if (sreloc
->r_length 
== RELOC_SIZE
) { 
1393                                 uintptr_t* locationToFix 
= (uintptr_t*)(sreloc
->r_address 
+ relocBase
); 
1394                                 switch(sreloc
->r_type
) { 
1395                                         case GENERIC_RELOC_VANILLA
: 
1396                                                 *locationToFix 
+= slide
; 
1399                                         case PPC_RELOC_HI16
:  
1400                                         case PPC_RELOC_LO16
:  
1401                                         case PPC_RELOC_HA16
:  
1402                                                 // Metrowerks compiler sometimes leaves object file relocations in linked images??? 
1403                                                 ++reloc
; // these relocations come in pairs, get next one 
1404                                                 otherRelocsPPC(locationToFix
, sreloc
->r_type
, reloc
->r_address
, slide
); 
1408                                         case PPC_RELOC_PB_LA_PTR
: 
1412                                         case PPC_RELOC_PB_LA_PTR
: 
1413                                                 // these should never exist in ppc64, but the first ld64 had a bug and created them 
1414                                                 *locationToFix 
= sreloc
->r_value 
+ slide
; 
1417                                         case GENERIC_RELOC_PB_LA_PTR
: 
1422                                                 throw "unknown local scattered relocation type"; 
1426                                 throw "bad local scattered relocation length"; 
1432         // if there were __TEXT fixups, restore write protection 
1433         if ( fTextSegmentWithFixups 
!= NULL 
) { 
1434                 fTextSegmentWithFixups
->setPermissions(); 
1435                 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize()); 
1439         fgTotalRebaseFixups 
+= fDynamicInfo
->nlocrel
; 
1443 const struct macho_nlist
* ImageLoaderMachO::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],  
1444                                                                                                 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
) 
1446         int32_t high 
= symbolCount
-1; 
1447         int32_t mid 
= hintIndex
; 
1449         // handle out of range hint 
1450         if ( mid 
>= (int32_t)symbolCount 
) { 
1451                 mid 
= symbolCount
/2; 
1452                 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
; 
1455                 ++ImageLoaderMachO::fgHintedBinaryTreeSearchs
; 
1458         for (int32_t low 
= 0; low 
<= high
; mid 
= (low
+high
)/2) { 
1459                 const uint32_t index 
= toc
[mid
].symbol_index
; 
1460                 const struct macho_nlist
* pivot 
= &symbols
[index
]; 
1461                 const char* pivotStr 
= &stringPool
[pivot
->n_un
.n_strx
]; 
1462 #if LINKEDIT_USAGE_DEBUG 
1463                 noteAccessedLinkEditAddress(&toc
[mid
]); 
1464                 noteAccessedLinkEditAddress(pivot
); 
1465                 noteAccessedLinkEditAddress(pivotStr
); 
1467                 int cmp 
= astrcmp(key
, pivotStr
); 
1482 const struct macho_nlist
* ImageLoaderMachO::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
) 
1484         ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
; 
1485         const struct macho_nlist
* base 
= symbols
; 
1486         for (uint32_t n 
= symbolCount
; n 
> 0; n 
/= 2) { 
1487                 const struct macho_nlist
* pivot 
= &base
[n
/2]; 
1488                 const char* pivotStr 
= &stringPool
[pivot
->n_un
.n_strx
]; 
1489 #if LINKEDIT_USAGE_DEBUG 
1490                 noteAccessedLinkEditAddress(pivot
); 
1491                 noteAccessedLinkEditAddress(pivotStr
); 
1493                 int cmp 
= astrcmp(key
, pivotStr
); 
1498                         // move base to symbol after pivot 
1510 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, const void* hint
, bool searchReExports
, ImageLoader
** foundIn
) const 
1512         const struct macho_nlist
* sym 
= NULL
; 
1513         const struct twolevel_hint
* theHint 
= (struct twolevel_hint
*)hint
; 
1514         if ( fDynamicInfo
->tocoff 
== 0 ) 
1515                 sym 
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
); 
1517                 uint32_t start 
= fDynamicInfo
->nextdefsym
; 
1518                 if ( theHint 
!= NULL 
) 
1519                          start 
= theHint
->itoc
; 
1520                 if ( (theHint 
== NULL
) || (theHint
->isub_image 
== 0) ) { 
1521                         sym 
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],  
1522                                                                                 fDynamicInfo
->ntoc
, start
); 
1525         if ( sym 
!= NULL 
) { 
1526                 if ( foundIn 
!= NULL 
) 
1527                         *foundIn 
= (ImageLoader
*)this;           
1529                 return (const Symbol
*)sym
; 
1532         if ( searchReExports 
) { 
1533                 // hint might tell us to try a particular subimage 
1534                 if ( (theHint 
!= NULL
) && (theHint
->isub_image 
> 0) && (theHint
->isub_image 
<= fLibrariesCount
) ) { 
1535                         // isub_image is an index into a list that is sorted non-rexported images first 
1537                         ImageLoader
* target 
= NULL
; 
1538                         // pass one, only look at sub-frameworks 
1539                         for (uint32_t i
=0; i 
< fLibrariesCount
; ++i
) { 
1540                                 DependentLibrary
& libInfo 
=  fLibraries
[i
]; 
1541                                 if ( libInfo
.isSubFramework 
&& (libInfo
.image 
!= NULL
)) { 
1542                                         if ( ++index 
== theHint
->isub_image 
) { 
1543                                                 target 
= libInfo
.image
; 
1548                         if (target 
!= NULL
) { 
1549                                 // pass two, only look at non-sub-framework-reexports 
1550                                 for (uint32_t i
=0; i 
< fLibrariesCount
; ++i
) { 
1551                                         DependentLibrary
& libInfo 
=  fLibraries
[i
]; 
1552                                         if ( libInfo
.isReExported 
&& !libInfo
.isSubFramework 
&& (libInfo
.image 
!= NULL
) ) { 
1553                                                 if ( ++index 
== theHint
->isub_image 
) { 
1554                                                         target 
= libInfo
.image
; 
1560                         if (target 
!= NULL
) { 
1561                                 const Symbol
* result 
= target
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
); 
1562                                 if ( result 
!= NULL 
) 
1567                 // hint failed, try all sub images 
1568                 // pass one, only look at sub-frameworks 
1569                 for(unsigned int i
=0; i 
< fLibrariesCount
; ++i
){ 
1570                         DependentLibrary
& libInfo 
=  fLibraries
[i
]; 
1571                         if ( (libInfo
.image 
!= NULL
) && libInfo
.isSubFramework 
) { 
1572                                 const Symbol
* result 
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
); 
1573                                 if ( result 
!= NULL 
) 
1577                 // pass two, only look at non-sub-framework-reexports 
1578                 for(unsigned int i
=0; i 
< fLibrariesCount
; ++i
){ 
1579                         DependentLibrary
& libInfo 
=  fLibraries
[i
]; 
1580                         if ( (libInfo
.image 
!= NULL
) && libInfo
.isReExported 
&& !libInfo
.isSubFramework 
) { 
1581                                 const Symbol
* result 
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
); 
1582                                 if ( result 
!= NULL 
) 
1588         // last change: the hint is wrong (non-zero but actually in this image) 
1589         if ( (theHint 
!= NULL
) && (theHint
->isub_image 
!= 0) ) { 
1590                 sym 
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],  
1591                                                                                 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
); 
1592                 if ( sym 
!= NULL 
) { 
1593                         if ( foundIn 
!= NULL 
)  
1594                                 *foundIn 
= (ImageLoader
*)this; 
1595                         return (const Symbol
*)sym
; 
1604 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
) const 
1606         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)sym
; 
1607         return nlistSym
->n_value 
+ fSlide
; 
1610 ImageLoader::DefinitionFlags 
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const 
1612         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)sym
; 
1613         if ( (nlistSym
->n_desc 
& N_WEAK_DEF
) != 0 ) 
1614                 return kWeakDefinition
; 
1615         return kNoDefinitionOptions
; 
1618 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const 
1620         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)sym
; 
1621         return &fStrings
[nlistSym
->n_un
.n_strx
]; 
1624 uint32_t ImageLoaderMachO::getExportedSymbolCount() const 
1626         return fDynamicInfo
->nextdefsym
; 
1630 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const 
1632         if ( index 
< fDynamicInfo
->nextdefsym 
) { 
1633                 const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iextdefsym 
+ index
]; 
1634                 return (const ImageLoader::Symbol
*)sym
; 
1640 uint32_t ImageLoaderMachO::getImportedSymbolCount() const 
1642         return fDynamicInfo
->nundefsym
; 
1646 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const 
1648         if ( index 
< fDynamicInfo
->nundefsym 
) { 
1649                 const struct macho_nlist
* sym 
= &fSymbolTable
[fDynamicInfo
->iundefsym 
+ index
]; 
1650                 return (const ImageLoader::Symbol
*)sym
; 
1656 ImageLoader::ReferenceFlags 
ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const 
1658         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)sym
; 
1659         ImageLoader::ReferenceFlags flags 
= kNoReferenceOptions
; 
1660         if ( ((nlistSym
->n_type 
& N_TYPE
) == N_UNDF
) && (nlistSym
->n_value 
!= 0) ) 
1661                 flags 
|= ImageLoader::kTentativeDefinition
; 
1662         if ( (nlistSym
->n_desc 
& N_WEAK_REF
) != 0 ) 
1663                 flags 
|= ImageLoader::kWeakReference
; 
1668 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const 
1670         const struct macho_nlist
* nlistSym 
= (const struct macho_nlist
*)sym
; 
1671         return &fStrings
[nlistSym
->n_un
.n_strx
]; 
1675 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
) 
1677         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1678         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1679         const struct load_command
* cmd 
= cmds
; 
1680         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1682                         case LC_SEGMENT_COMMAND
: 
1684                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1685                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1686                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1687                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1688                                                 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) { 
1689                                                         *start 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1690                                                         *length 
= sect
->size
; 
1697                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1703 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
) 
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 uintptr_t unslidInteriorAddress 
= (uintptr_t)imageInterior 
- this->getSlide(); 
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                                         if ( (unslidInteriorAddress 
>= seg
->vmaddr
) && (unslidInteriorAddress 
< (seg
->vmaddr
+seg
->vmsize
)) ) { 
1715                                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1716                                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1717                                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1718                                                         if ((sect
->addr 
<= unslidInteriorAddress
) && (unslidInteriorAddress 
< (sect
->addr
+sect
->size
))) { 
1719                                                                 if ( segmentName 
!= NULL 
) 
1720                                                                         *segmentName 
= sect
->segname
; 
1721                                                                 if ( sectionName 
!= NULL 
) 
1722                                                                         *sectionName 
= sect
->sectname
; 
1723                                                                 if ( sectionOffset 
!= NULL 
) 
1724                                                                         *sectionOffset 
= unslidInteriorAddress 
- sect
->addr
; 
1732                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1738 bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist
* symbol
) 
1740         // if a define and weak ==> coalesced  
1741         if ( ((symbol
->n_type 
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc 
& N_WEAK_DEF
) != 0) )  
1743         // if an undefine and not referencing a weak symbol ==> coalesced 
1744         if ( ((symbol
->n_type 
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc 
& N_REF_TO_WEAK
) != 0) ) 
1752 static void __attribute__((noreturn
)) throwSymbolNotFound(const char* symbol
, const char* referencedFrom
, const char* expectedIn
) 
1754         const char* formatString 
= "Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n"; 
1755         char buf
[strlen(symbol
)+strlen(referencedFrom
)+strlen(expectedIn
)+strlen(formatString
)]; 
1756         sprintf(buf
, formatString
, symbol
, referencedFrom
, expectedIn
); 
1757         throw strdup(buf
);  // this is a leak if exception doesn't halt program 
1760 uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
, bool twoLevel
, ImageLoader
** foundIn
) 
1762         const char* symbolName 
= &fStrings
[undefinedSymbol
->n_un
.n_strx
]; 
1764         if ( context
.bindFlat 
|| !twoLevel 
) { 
1766                 if ( ((undefinedSymbol
->n_type 
& N_PEXT
) != 0) && ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) ) { 
1767                         // is a multi-module private_extern internal reference that the linker did not optimize away 
1768                         uintptr_t addr 
= undefinedSymbol
->n_value 
+ this->fSlide
; 
1773                 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1774                         return (*foundIn
)->getExportedSymbolAddress(sym
); 
1775                 // if a bundle is loaded privately the above will not find its exports 
1776                 if ( this->isBundle() && this->hasHiddenExports() ) { 
1777                         // look in self for needed symbol 
1778                         sym 
= this->findExportedSymbol(symbolName
, NULL
, false, foundIn
); 
1780                                 return (*foundIn
)->getExportedSymbolAddress(sym
); 
1782                 if ( (undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0 ) { 
1783                         // definition can't be found anywhere 
1784                         // if reference is weak_import, then it is ok, just return 0 
1787                 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace"); 
1790                 // symbol requires searching images with coalesced symbols 
1791                 if ( !context
.prebinding 
&& this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol
) ) { 
1793                         if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) ) 
1794                                 return (*foundIn
)->getExportedSymbolAddress(sym
); 
1795                         //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace"); 
1796                         //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName); 
1801                 ImageLoader
* target 
= NULL
; 
1802                 uint8_t ord 
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
); 
1803                 if ( ord 
== EXECUTABLE_ORDINAL 
) { 
1804                         target 
= context
.mainExecutable
; 
1806                 else if ( ord 
== SELF_LIBRARY_ORDINAL 
) { 
1809                 else if ( ord 
== DYNAMIC_LOOKUP_ORDINAL 
) { 
1810                         // rnielsen: HACKHACK 
1813                         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1814                                 return (*foundIn
)->getExportedSymbolAddress(sym
); 
1815                         // no image has exports this symbol 
1816                         // either report error or hope ZeroLink can just-in-time load an image 
1817                         context
.undefinedHandler(symbolName
); 
1818                         // try looking again 
1819                         if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) 
1820                                 return (*foundIn
)->getExportedSymbolAddress(sym
); 
1822                         throwSymbolNotFound(symbolName
, this->getPath(), "dynamic lookup"); 
1824                 else if ( ord 
<= fLibrariesCount 
) { 
1825                         DependentLibrary
& libInfo 
= fLibraries
[ord
-1]; 
1826                         target 
= libInfo
.image
; 
1827                         if ( (target 
== NULL
) && (((undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0) || !libInfo
.required
) ) { 
1828                                 // if target library not loaded and reference is weak or library is weak return 0 
1833                         throw "corrupt binary, library ordinal too big"; 
1836                 if ( target 
== NULL 
) { 
1837                         //fprintf(stderr, "resolveUndefined(%s) in %s\n", symbolName, this->getPath()); 
1838                         throw "symbol not found"; 
1842                 if ( fTwoLevelHints 
!= NULL 
) { 
1843                         uint32_t symIndex 
= undefinedSymbol 
- fSymbolTable
; 
1844                         int32_t undefinedIndex 
= symIndex 
- fDynamicInfo
->iundefsym
; 
1845                         if ( (undefinedIndex 
>= 0) && ((uint32_t)undefinedIndex 
< fDynamicInfo
->nundefsym
) ) { 
1846                                 const struct twolevel_hint
* hints 
= (struct twolevel_hint
*)(&fLinkEditBase
[fTwoLevelHints
->offset
]); 
1847                                 const struct twolevel_hint
* theHint 
= &hints
[undefinedIndex
]; 
1848                                 hint 
= (void*)theHint
; 
1852                 const Symbol
* sym 
= target
->findExportedSymbol(symbolName
, hint
, true, foundIn
); 
1854                         return (*foundIn
)->getExportedSymbolAddress(sym
); 
1856                 else if ( (undefinedSymbol
->n_type 
& N_PEXT
) != 0 ) { 
1857                         // don't know why the static linker did not eliminate the internal reference to a private extern definition 
1859                         return undefinedSymbol
->n_value 
+ fSlide
; 
1861                 else if ( (undefinedSymbol
->n_desc 
& N_WEAK_REF
) != 0 ) { 
1862                         // if definition not found and reference is weak return 0 
1866                 // nowhere to be found 
1867                 throwSymbolNotFound(symbolName
, this->getPath(), target
->getPath()); 
1871 // returns if 'addr' is within the address range of section 'sectionIndex' 
1872 // fSlide is not used.  'addr' is assumed to be a prebound address in this image  
1873 bool ImageLoaderMachO::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
) 
1875         uint8_t currentSectionIndex 
= 1; 
1876         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1877         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1878         const struct load_command
* cmd 
= cmds
; 
1879         for (unsigned long i 
= 0; i 
< cmd_count
; ++i
) { 
1880                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1881                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1882                         if ( (currentSectionIndex 
<= sectionIndex
) && (sectionIndex 
< currentSectionIndex
+seg
->nsects
) ) { 
1883                                 // 'sectionIndex' is in this segment, get section info 
1884                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1885                                 const struct macho_section
* const section 
= §ionsStart
[sectionIndex
-currentSectionIndex
]; 
1886                                 return ( (section
->addr 
<= addr
) && (addr 
< section
->addr
+section
->size
) ); 
1889                                 // 'sectionIndex' not in this segment, skip to next segment 
1890                                 currentSectionIndex 
+= seg
->nsects
; 
1893                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1899 void ImageLoaderMachO::doBindExternalRelocations(const LinkContext
& context
, bool onlyCoalescedSymbols
) 
1901         const uintptr_t relocBase 
= this->getRelocBase(); 
1902         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
1903         const bool prebound 
= this->isPrebindable(); 
1905         // if there are __TEXT fixups, temporarily make __TEXT writable 
1906         if ( fTextSegmentWithFixups 
!= NULL 
)  
1907                 fTextSegmentWithFixups
->tempWritable(); 
1909         // cache last lookup 
1910         const struct macho_nlist
*       lastUndefinedSymbol 
= 0; 
1911         uintptr_t                                       symbolAddr 
= 0; 
1912         ImageLoader
*                            image 
= NULL
; 
1914         // loop through all external relocation records and bind each 
1915         const relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]); 
1916         const relocation_info
* const relocsEnd 
= &relocsStart
[fDynamicInfo
->nextrel
]; 
1917         for (const relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
1918                 if (reloc
->r_length 
== RELOC_SIZE
) { 
1919                         switch(reloc
->r_type
) { 
1922                                                 const struct macho_nlist
* undefinedSymbol 
= &fSymbolTable
[reloc
->r_symbolnum
]; 
1923                                                 // if only processing coalesced symbols and this one does not require coalesceing, skip to next 
1924                                                 if ( onlyCoalescedSymbols 
&& !symbolRequiresCoalescing(undefinedSymbol
) ) 
1926                                                 uintptr_t* location 
= ((uintptr_t*)(reloc
->r_address 
+ relocBase
)); 
1927                                                 uintptr_t value 
= *location
; 
1929                                                 if ( reloc
->r_pcrel 
) { 
1930                                                         value 
+= (uintptr_t)location 
+ 4 - fSlide
; 
1934                                                         // we are doing relocations, so prebinding was not usable 
1935                                                         // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 
1936                                                         // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 
1937                                                         // if mach-o relocation structs had an "addend" field this complication would not be necessary. 
1938                                                         if ( ((undefinedSymbol
->n_type 
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc 
& N_WEAK_DEF
) != 0) ) { 
1939                                                                 // weak symbols need special casing, since *location may have been prebound to a definition in another image. 
1940                                                                 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume  
1941                                                                 // that we can subtract off the weak symbol address to get the addend. 
1942                                                                 // If prebound elsewhere, we've lost the addend and have to assume it is zero. 
1943                                                                 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 
1944                                                                 if ( (value 
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) ) 
1945                                                                         value 
-= undefinedSymbol
->n_value
; 
1950                                                                 // is undefined or non-weak symbol, so do subtraction to get addend 
1951                                                                 value 
-= undefinedSymbol
->n_value
; 
1954                                                 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too 
1955                                                 if ( undefinedSymbol 
!= lastUndefinedSymbol 
) { 
1956                                                         symbolAddr 
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, &image
); 
1957                                                         lastUndefinedSymbol 
= undefinedSymbol
; 
1959                                                 if ( context
.verboseBind 
) { 
1960                                                         const char *path 
= NULL
; 
1962                                                                 path 
= image
->getShortName(); 
1965                                                                 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n", 
1966                                                                                 this->getShortName(), (uintptr_t)location
, 
1967                                                                                 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
); 
1970                                                                 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n", 
1971                                                                                 this->getShortName(), (uintptr_t)location
, 
1972                                                                                 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, value
); 
1975                                                 value 
+= symbolAddr
; 
1977                                                 if ( reloc
->r_pcrel 
) { 
1978                                                         *location 
= value 
- ((uintptr_t)location 
+ 4); 
1981                                                         // don't dirty page if prebound value was correct 
1982                                                         if ( !prebound 
|| (*location 
!= value
) ) 
1986                                                 // don't dirty page if prebound value was correct 
1987                                                 if ( !prebound 
|| (*location 
!= value
) ) 
1993                                         throw "unknown external relocation type"; 
1997                         throw "bad external relocation length"; 
2001         // if there were __TEXT fixups, restore write protection 
2002         if ( fTextSegmentWithFixups 
!= NULL 
) { 
2003                 fTextSegmentWithFixups
->setPermissions(); 
2004                 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize()); 
2008         fgTotalBindFixups 
+= fDynamicInfo
->nextrel
; 
2011 const mach_header
* ImageLoaderMachO::machHeader() const 
2013         return (mach_header
*)fMachOData
; 
2016 uintptr_t ImageLoaderMachO::getSlide() const 
2021 // hmm. maybe this should be up in ImageLoader?? 
2022 const void* ImageLoaderMachO::getBaseAddress() const 
2024         Segment
* seg 
= fSegments
[0]; 
2025         return (const void*)seg
->getActualLoadAddress(); 
2028 uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, ImageLoader
* targetImage
, const LinkContext
& context
) 
2030         if ( context
.verboseBind 
) { 
2031                 const char* path 
= NULL
; 
2032                 if ( targetImage 
!= NULL 
) 
2033                         path 
= targetImage
->getShortName(); 
2034                 fprintf(stderr
, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n", 
2035                                 this->getShortName(), symbolName
, (((sect
->flags 
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"), 
2036                                 path
, symbolName
, (uintptr_t)ptrToBind
, targetAddr
); 
2038         if ( context
.bindingHandler 
!= NULL 
) { 
2039                 const char* path 
= NULL
; 
2040                 if ( targetImage 
!= NULL 
) 
2041                         path 
= targetImage
->getShortName(); 
2042                 targetAddr 
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
); 
2045         // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32" 
2046         if ( ((sect
->flags 
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2 
== 5) ) { 
2047                 uint32_t rel32 
= targetAddr 
- (((uint32_t)ptrToBind
)+5); 
2048                 // re-write instruction in a thread-safe manner 
2049                 // use 8-byte compare-and-swap to alter 5-byte jump table entries 
2050                 // loop is required in case the extra three bytes that cover the next entry are altered by another thread 
2053                         volatile int64_t* jumpPtr 
= (int64_t*)ptrToBind
; 
2055                         // By default the three extra bytes swapped follow the 5-byte JMP. 
2056                         // But, if the 5-byte jump is up against the end of the __IMPORT segment 
2057                         // We don't want to access bytes off the end of the segment, so we shift 
2058                         // the extra bytes to precede the 5-byte JMP. 
2059                         if ( (((uint32_t)ptrToBind 
+ 8) & 0x00000FFC) == 0x00000000 ) { 
2060                                 jumpPtr 
= (int64_t*)((uint32_t)ptrToBind 
- 3); 
2063                         int64_t oldEntry 
= *jumpPtr
; 
2068                         newEntry
.int64 
= oldEntry
; 
2069                         newEntry
.bytes
[pad
+0] = 0xE9; // JMP rel32 
2070                         newEntry
.bytes
[pad
+1] = rel32 
& 0xFF; 
2071                         newEntry
.bytes
[pad
+2] = (rel32 
>> 8) & 0xFF; 
2072                         newEntry
.bytes
[pad
+3] = (rel32 
>> 16) & 0xFF; 
2073                         newEntry
.bytes
[pad
+4] = (rel32 
>> 24) & 0xFF; 
2074                         done 
= OSAtomicCompareAndSwap64Barrier(oldEntry
, newEntry
.int64
, (int64_t*)jumpPtr
); 
2079         *ptrToBind 
= targetAddr
; 
2084 uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
) 
2086         // scan for all non-lazy-pointer sections 
2087         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
2088         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2089         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2090         const struct load_command
* cmd 
= cmds
; 
2091         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
2092         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2094                         case LC_SEGMENT_COMMAND
: 
2096                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2097                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2098                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2099                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2100                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2101                                                 uint32_t symbolIndex 
= INDIRECT_SYMBOL_LOCAL
; 
2102                                                 if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
2103                                                         const uint32_t pointerCount 
= sect
->size 
/ sizeof(uintptr_t); 
2104                                                         uintptr_t* const symbolPointers 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
2105                                                         if ( (lazyPointer 
>= symbolPointers
) && (lazyPointer 
< &symbolPointers
[pointerCount
]) ) { 
2106                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
2107                                                                 const uint32_t lazyIndex 
= lazyPointer 
- symbolPointers
; 
2108                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ lazyIndex
]; 
2112                                                 else if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
2113                                                         // 5 bytes stubs on i386 are new "fast stubs" 
2114                                                         uint8_t* const jmpTableBase 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
2115                                                         uint8_t* const jmpTableEnd 
= jmpTableBase 
+ sect
->size
; 
2116                                                         // initial CALL instruction in jump table leaves pointer to next entry, so back up 
2117                                                         uint8_t* const jmpTableEntryToPatch 
= ((uint8_t*)lazyPointer
) - 5;   
2118                                                         lazyPointer 
= (uintptr_t*)jmpTableEntryToPatch
;  
2119                                                         if ( (jmpTableEntryToPatch 
>= jmpTableBase
) && (jmpTableEntryToPatch 
< jmpTableEnd
) ) { 
2120                                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
2121                                                                 const uint32_t entryIndex 
= (jmpTableEntryToPatch 
- jmpTableBase
)/5; 
2122                                                                 symbolIndex 
= indirectTable
[indirectTableOffset 
+ entryIndex
]; 
2126                                                 if ( symbolIndex 
!= INDIRECT_SYMBOL_ABS 
&& symbolIndex 
!= INDIRECT_SYMBOL_LOCAL 
) { 
2127                                                         const char* symbolName 
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
]; 
2128                                                         ImageLoader
* image 
= NULL
; 
2129                                                         uintptr_t symbolAddr 
= this->resolveUndefined(context
,  &fSymbolTable
[symbolIndex
], twoLevel
, &image
); 
2130                                                         symbolAddr 
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
,  context
); 
2131                                                         ++fgTotalLazyBindFixups
; 
2138                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2140         throw "lazy pointer not found"; 
2146 void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext
& context
, BindingLaziness bindness
, bool onlyCoalescedSymbols
) 
2148         // scan for all non-lazy-pointer sections  
2149         const bool twoLevel 
= this->usesTwoLevelNameSpace(); 
2150         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2151         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2152         const struct load_command
* cmd 
= cmds
; 
2153         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
2154         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2156                         case LC_SEGMENT_COMMAND
: 
2158                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2159                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2160                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2161                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2162                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2163                                                 uint32_t elementSize 
= sizeof(uintptr_t); 
2164                                                 uint32_t elementCount 
= sect
->size 
/ elementSize
; 
2165                                                 if ( type 
== S_NON_LAZY_SYMBOL_POINTERS 
) { 
2166                                                         if ( (bindness 
== kLazyOnly
) || (bindness 
== kLazyOnlyNoDependents
) ) 
2169                                                 else if ( type 
== S_LAZY_SYMBOL_POINTERS 
) { 
2170                                                         // process each symbol pointer in this section 
2171                                                         fgTotalPossibleLazyBindFixups 
+= elementCount
; 
2172                                                         if ( bindness 
== kNonLazyOnly 
) 
2176                                                 else if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
2177                                                         // process each jmp entry in this section 
2178                                                         elementCount 
= sect
->size 
/ 5; 
2180                                                         fgTotalPossibleLazyBindFixups 
+= elementCount
; 
2181                                                         if ( bindness 
== kNonLazyOnly 
) 
2188                                                 const uint32_t indirectTableOffset 
= sect
->reserved1
; 
2189                                                 uint8_t* ptrToBind 
= (uint8_t*)(sect
->addr 
+ fSlide
); 
2190                                                 for (uint32_t j
=0; j 
< elementCount
; ++j
, ptrToBind 
+= elementSize
) { 
2191                                                         uint32_t symbolIndex 
= indirectTable
[indirectTableOffset 
+ j
]; 
2192                                                         if ( symbolIndex 
== INDIRECT_SYMBOL_LOCAL
) { 
2193                                                                 *((uintptr_t*)ptrToBind
) += this->fSlide
; 
2195                                                         else if ( symbolIndex 
== INDIRECT_SYMBOL_ABS
) { 
2196                                                                 // do nothing since already has absolute address 
2199                                                                 const struct macho_nlist
* sym 
= &fSymbolTable
[symbolIndex
]; 
2200                                                                 if ( symbolIndex 
== 0 ) { 
2201                                                                         // This could be rdar://problem/3534709  
2202                                                                         if ( ((const macho_header
*)fMachOData
)->filetype 
== MH_EXECUTE 
) { 
2203                                                                                 static bool alreadyWarned 
= false; 
2204                                                                                 if ( (sym
->n_type 
& N_TYPE
) != N_UNDF 
) { 
2205                                                                                         // The indirect table parallels the (non)lazy pointer sections.  For 
2206                                                                                         // instance, to find info about the fifth lazy pointer you look at the 
2207                                                                                         // fifth entry in the indirect table.  (try otool -Iv on a file). 
2208                                                                                         // The entry in the indirect table contains an index into the symbol table. 
2210                                                                                         // The bug in ld caused the entry in the indirect table to be zero 
2211                                                                                         // (instead of a magic value that means a local symbol).  So, if the 
2212                                                                                         // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid 
2213                                                                                         // symbol table index. The check I put in place is to see if the zero'th 
2214                                                                                         // symbol table entry is an import entry (usually it is a local symbol 
2216                                                                                         if ( context
.verboseWarnings 
&& !alreadyWarned 
) { 
2217                                                                                                 fprintf(stderr
, "dyld: malformed executable '%s', skipping indirect symbol to %s\n", 
2218                                                                                                                 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]); 
2219                                                                                                 alreadyWarned 
= true; 
2225                                                                 ImageLoader 
*image 
= NULL
; 
2226                                                                 // if only processing coalesced symbols and this one does not require coalesceing, skip to next 
2227                                                                 if ( onlyCoalescedSymbols 
&& !symbolRequiresCoalescing(sym
) ) 
2229                                                                 uintptr_t symbolAddr
; 
2230                                                                         symbolAddr 
= resolveUndefined(context
, sym
, twoLevel
, &image
); 
2233                                                                 symbolAddr 
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
,  context
); 
2237                                                 fgTotalBindFixups 
+= elementCount
; 
2242                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2247  * The address of these symbols are written in to the (__DATA,__dyld) section 
2248  * at the following offsets: 
2249  *      at offset 0     stub_binding_helper_interface 
2250  *      at offset 4     _dyld_func_lookup 
2251  *      at offset 8     start_debug_thread 
2252  * The 'C' types (if any) for these symbols are ignored here and all are 
2253  * declared as longs so the assignment of their address in to the section will 
2254  * not require a cast.  stub_binding_helper_interface is really a label in the 
2255  * assembly code interface for the stub binding.  It does not have a meaningful  
2256  * 'C' type.  _dyld_func_lookup is the routine in dyld_libfuncs.c. 
2257  * start_debug_thread is the routine in debug.c. 
2259  * For ppc the image's stub_binding_binding_helper is read from: 
2260  *      at offset 20    the image's stub_binding_binding_helper address 
2261  * and saved into to the image structure. 
2264         void*   dyldLazyBinder
;         // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface 
2265         void*   dyldFuncLookup
;         // filled in at launch by dyld to point into dyld to &_dyld_func_lookup 
2266         void*   startDebugThread
;   // debugger interface ??? 
2267         void*   debugPort
;                      // debugger interface ??? 
2268         void*   debugThread
;            // debugger interface ??? 
2269         void*   stubBindHelper
;         // filled in at static link time to point to stub helper in image 
2270         void*   coreDebug
;                      // ??? 
2273 // These are defined in dyldStartup.s 
2274 extern "C" void stub_binding_helper(); 
2275 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
); 
2276 extern "C" void fast_stub_binding_helper_interface(); 
2279 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
) 
2281         if ( fDATAdyld 
!= NULL 
) { 
2282                 struct DATAdyld
* dd 
= (struct DATAdyld
*)(fDATAdyld
->addr 
+ fSlide
); 
2283                 if ( fDATAdyld
->size 
> offsetof(DATAdyld
, dyldLazyBinder
) ) { 
2284                         if ( dd
->dyldLazyBinder 
!= (void*)&stub_binding_helper 
) 
2285                                 dd
->dyldLazyBinder 
= (void*)&stub_binding_helper
; 
2287                 if ( fDATAdyld
->size 
> offsetof(DATAdyld
, dyldFuncLookup
) ) { 
2288                         if ( dd
->dyldFuncLookup 
!= (void*)&dyld_func_lookup 
) 
2289                                 dd
->dyldFuncLookup 
= (void*)&dyld_func_lookup
; 
2291                 //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) )  
2292                 //      dd->startDebugThread = &start_debug_thread; 
2294                 //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) ) 
2295                 //      save = dd->stubBindHelper;       
2299         if ( ! this->usablePrebinding(context
) || !this->usesTwoLevelNameSpace() ) { 
2300                 // reset all "fast" stubs 
2301                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2302                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2303                 const struct load_command
* cmd 
= cmds
; 
2304                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2306                                 case LC_SEGMENT_COMMAND
: 
2308                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2309                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2310                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2311                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2312                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2313                                                 if ( (type 
== S_SYMBOL_STUBS
) && (sect
->flags 
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2 
== 5) ) { 
2314                                                         // reset each jmp entry in this section 
2315                                                         const uint32_t indirectTableOffset 
= sect
->reserved1
; 
2316                                                         const uint32_t* const indirectTable 
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
]; 
2317                                                         uint8_t* start 
= (uint8_t*)(sect
->addr 
+ this->fSlide
); 
2318                                                         uint8_t* end 
= start 
+ sect
->size
; 
2319                                                         uintptr_t dyldHandler 
= (uintptr_t)&fast_stub_binding_helper_interface
; 
2320                                                         uint32_t entryIndex 
= 0; 
2321                                                         for (uint8_t* entry 
= start
; entry 
< end
; entry 
+= 5, ++entryIndex
) { 
2322                                                                 bool installLazyHandler 
= true; 
2323                                                                 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes 
2324                                                                 // if the instruction is updated by one thread while being executed by another 
2325                                                                 if ( ((uint32_t)entry 
& 0xFFFFFFC0) != ((uint32_t)entry
+4 & 0xFFFFFFC0) ) { 
2326                                                                         // need to bind this now to avoid a potential problem if bound lazily 
2327                                                                         uint32_t symbolIndex 
= indirectTable
[indirectTableOffset 
+ entryIndex
]; 
2328                                                                         // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used 
2329                                                                         if ( symbolIndex 
!= INDIRECT_SYMBOL_ABS 
) { 
2330                                                                                 const char* symbolName 
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
]; 
2331                                                                                 ImageLoader
* image 
= NULL
; 
2333                                                                                         uintptr_t symbolAddr 
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], this->usesTwoLevelNameSpace(), &image
); 
2334                                                                                         symbolAddr 
= this->bindIndirectSymbol((uintptr_t*)entry
, sect
, symbolName
, symbolAddr
, image
, context
); 
2335                                                                                         ++fgTotalBindFixups
; 
2336                                                                                         uint32_t rel32 
= symbolAddr 
- (((uint32_t)entry
)+5); 
2337                                                                                         entry
[0] = 0xE9; // JMP rel32 
2338                                                                                         entry
[1] = rel32 
& 0xFF; 
2339                                                                                         entry
[2] = (rel32 
>> 8) & 0xFF; 
2340                                                                                         entry
[3] = (rel32 
>> 16) & 0xFF; 
2341                                                                                         entry
[4] = (rel32 
>> 24) & 0xFF; 
2342                                                                                         installLazyHandler 
= false; 
2344                                                                                 catch (const char* msg
) { 
2345                                                                                         // ignore errors when binding symbols early 
2346                                                                                         // maybe the function is never called, and therefore erroring out now would be a regression 
2350                                                                 if ( installLazyHandler 
) { 
2351                                                                         uint32_t rel32 
= dyldHandler 
- (((uint32_t)entry
)+5); 
2352                                                                         entry
[0] = 0xE8; // CALL rel32 
2353                                                                         entry
[1] = rel32 
& 0xFF; 
2354                                                                         entry
[2] = (rel32 
>> 8) & 0xFF; 
2355                                                                         entry
[3] = (rel32 
>> 16) & 0xFF; 
2356                                                                         entry
[4] = (rel32 
>> 24) & 0xFF; 
2363                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2369 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const 
2371         // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 
2372         if ( this->isPrebindable()  
2373                 && (this->getSlide() == 0)  
2374                 && (this->usesTwoLevelNameSpace() || context
.prebinding
) 
2375                 && this->allDependentLibrariesAsWhenPreBound() ) { 
2376                 // allow environment variables to disable prebinding 
2377                 if ( context
.bindFlat 
) 
2379                 switch ( context
.prebindUsage 
) { 
2380                         case kUseAllPrebinding
: 
2382                         case kUseSplitSegPrebinding
: 
2383                                 return this->fIsSplitSeg
; 
2384                         case kUseAllButAppPredbinding
: 
2385                                 return (this != context
.mainExecutable
); 
2386                         case kUseNoPrebinding
: 
2393 void ImageLoaderMachO::doBind(const LinkContext
& context
, BindingLaziness bindness
) 
2395         // set dyld entry points in image 
2396         this->setupLazyPointerHandler(context
); 
2398         // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 
2399         // note: flat-namespace binaries need to be imports rebound (even if correctly prebound) 
2400         if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) { 
2401                 // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols 
2402                 if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports 
> 1) ) { 
2403                         this->doBindExternalRelocations(context
, true); 
2404                         this->doBindIndirectSymbolPointers(context
, kLazyAndNonLazy
, true); 
2406                 // skip binding because prebound and prebinding not disabled 
2410         // values bound by name are stored two different ways in mach-o 
2413                 case kLazyAndNonLazy
: 
2414                         // external relocations are used for data initialized to external symbols 
2415                         this->doBindExternalRelocations(context
, false); 
2418                 case kLazyOnlyNoDependents
: 
2421         // "indirect symbols" are used for code references to external symbols 
2422         this->doBindIndirectSymbolPointers(context
, bindness
, false); 
2427 void ImageLoaderMachO::doImageInit(const LinkContext
& context
) 
2429         if ( fDashInit 
!= NULL 
) { 
2430                 Initializer func 
= (Initializer
)(fDashInit
->init_address 
+ fSlide
); 
2431                 if ( context
.verboseInit 
) 
2432                         fprintf(stderr
, "dyld: calling -init function 0x%p in %s\n", func
, this->getPath()); 
2433                 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
); 
2437 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
) 
2439         if ( fModInitSection 
!= NULL 
) { 
2440                 Initializer
* inits 
= (Initializer
*)(fModInitSection
->addr 
+ fSlide
); 
2441                 const uint32_t count 
= fModInitSection
->size 
/ sizeof(uintptr_t); 
2442                 for (uint32_t i
=0; i 
< count
; ++i
) { 
2443                         Initializer func 
= inits
[i
]; 
2444                         if ( context
.verboseInit 
) 
2445                                 fprintf(stderr
, "dyld: calling initializer function %p in %s\n", func
, this->getPath()); 
2446                         func(context
.argc
, context
.argv
, context
.envp
, context
.apple
); 
2452 void ImageLoaderMachO::doInitialization(const LinkContext
& context
) 
2454         // mach-o has -init and static initializers 
2455         doImageInit(context
); 
2456         doModInitFunctions(context
); 
2459 bool ImageLoaderMachO::needsInitialization() 
2461         return ( (fDashInit 
!= NULL
) || (fModInitSection 
!= NULL
) ); 
2465 bool ImageLoaderMachO::needsTermination() 
2467         return ( fModTermSection 
!= NULL 
); 
2470 bool ImageLoaderMachO::hasImageNotification() 
2472         return ( fImageNotifySection 
!= NULL 
); 
2476 void ImageLoaderMachO::doTermination(const LinkContext
& context
) 
2478         if ( fModTermSection 
!= NULL 
) { 
2479                 Terminator
* terms 
= (Terminator
*)(fModTermSection
->addr 
+ fSlide
); 
2480                 const uint32_t count 
= fModTermSection
->size 
/ sizeof(uintptr_t); 
2481                 for (uint32_t i
=count
; i 
> 0; --i
) { 
2482                         Terminator func 
= terms
[i
-1]; 
2483                         if ( context
.verboseInit 
) 
2484                                 fprintf(stderr
, "dyld: calling terminaton function %p in %s\n", func
, this->getPath()); 
2490 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode
, uint32_t infoCount
, const struct dyld_image_info info
[]) 
2492         if ( fImageNotifySection 
!= NULL 
) { 
2493                 dyld_image_notifier
* notes 
= (dyld_image_notifier
*)(fImageNotifySection
->addr 
+ fSlide
); 
2494                 const uint32_t count 
= fImageNotifySection
->size 
/ sizeof(uintptr_t); 
2495                 for (uint32_t i
=count
; i 
> 0; --i
) { 
2496                         dyld_image_notifier func 
= notes
[i
-1]; 
2497                         func(mode
, infoCount
, info
); 
2502 void ImageLoaderMachO::printStatistics(unsigned int imageCount
) 
2504         ImageLoader::printStatistics(imageCount
); 
2505         fprintf(stderr
, "total hinted binary tree searches:    %d\n", fgHintedBinaryTreeSearchs
); 
2506         fprintf(stderr
, "total unhinted binary tree searches:  %d\n", fgUnhintedBinaryTreeSearchs
); 
2507         fprintf(stderr
, "total images with weak exports:  %d\n", fgCountOfImagesWithWeakExports
); 
2509 #if LINKEDIT_USAGE_DEBUG 
2510         fprintf(stderr
, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets
.size()); 
2514 void ImageLoaderMachO::doPrebinding(const LinkContext
& context
, time_t timestamp
, uint8_t* fileToPrebind
) 
2516         // update __DATA segment 
2517         this->applyPrebindingToDATA(fileToPrebind
); 
2519         // update load commands  
2520         this->applyPrebindingToLoadCommands(context
, fileToPrebind
, timestamp
); 
2522         // update symbol table   
2523         this->applyPrebindingToLinkEdit(context
, fileToPrebind
); 
2526 void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind
) 
2528         const unsigned int segmentCount 
= fSegments
.size(); 
2529         for(unsigned int i
=0; i 
< segmentCount
; ++i
) { 
2530                 SegmentMachO
* seg 
= (SegmentMachO
*)fSegments
[i
]; 
2531                 if ( seg
->writeable() ) { 
2532                         memcpy(&fileToPrebind
[seg
->fFileOffset
], (void*)seg
->getActualLoadAddress(), seg
->fFileSize
); 
2537 void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext
& context
, uint8_t* fileToPrebind
, time_t timestamp
) 
2539         macho_header
* mh 
= (macho_header
*)fileToPrebind
; 
2540         const uint32_t cmd_count 
= mh
->ncmds
; 
2541         const struct load_command
* const cmds 
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)]; 
2542         const struct load_command
* cmd 
= cmds
; 
2543         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2546                         case LC_LOAD_WEAK_DYLIB
: 
2548                                         // update each dylib load command with the timestamp of the target dylib 
2549                                         struct dylib_command
* dylib  
= (struct dylib_command
*)cmd
; 
2550                                         const char* name 
= (char*)cmd 
+ dylib
->dylib
.name
.offset
; 
2551                                         for (const DependentLibrary
* dl
=fLibraries
; dl 
< &fLibraries
[fLibrariesCount
]; dl
++) { 
2552                                                 if (strcmp(dl
->name
, name
) == 0 ) { 
2553                                                         // found matching DependentLibrary for this load command 
2554                                                         if ( dl
->image 
== NULL 
) { 
2555                                                                 // missing weak linked dylib 
2556                                                                 dylib
->dylib
.timestamp 
= 0; 
2559                                                                 ImageLoaderMachO
* targetImage 
= (ImageLoaderMachO
*)(dl
->image
); // !!! assume only mach-o images are prebound 
2560                                                                 if ( ! targetImage
->isPrebindable() ) 
2561                                                                         throw "dependent dylib is not prebound"; 
2562                                                                 // if the target is currently being re-prebound then its timestamp will be the same as this one 
2563                                                                 if ( ! targetImage
->usablePrebinding(context
) ) { 
2564                                                                         dylib
->dylib
.timestamp 
= timestamp
; 
2567                                                                         // otherwise dependent library is already correctly prebound, so use its checksum 
2568                                                                         dylib
->dylib
.timestamp 
= targetImage
->doGetLibraryInfo().checksum
; 
2578                                         // update the ID of this library with the new timestamp 
2579                                         struct dylib_command
* dylib  
= (struct dylib_command
*)cmd
; 
2580                                         dylib
->dylib
.timestamp 
= timestamp
; 
2583                         case LC_SEGMENT_COMMAND
: 
2584                                 // if dylib was rebased, update segment commands 
2585                                 if ( fSlide 
!= 0 ) { 
2586                                         struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2587                                         seg
->vmaddr 
+= fSlide
; 
2588                                         struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2589                                         struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2590                                         for (struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2591                                                 sect
->addr 
+= fSlide
; 
2595                         case LC_ROUTINES_COMMAND
: 
2596                                 // if dylib was rebased, update -init command 
2597                                 if ( fSlide 
!= 0 ) { 
2598                                         struct macho_routines_command
* routines 
= (struct macho_routines_command
*)cmd
; 
2599                                         routines
->init_address 
+= fSlide
; 
2603                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2607 void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext
& context
, uint8_t* fileToPrebind
) 
2609         // In prebound images, the n_value of the symbol table entry for is the prebound address 
2610         // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers 
2611         const char* stringPool 
= NULL
; 
2612         struct macho_nlist
* symbolTable 
= NULL
; 
2613         const struct dysymtab_command
* dysymtab 
= NULL
; 
2615         // get symbol table info 
2616         macho_header
* mh 
= (macho_header
*)fileToPrebind
; 
2617         const uint32_t cmd_count 
= mh
->ncmds
; 
2618         const struct load_command
* const cmds 
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)]; 
2619         const struct load_command
* cmd 
= cmds
; 
2620         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2624                                         const struct symtab_command
* symtab 
= (struct symtab_command
*)cmd
; 
2625                                         stringPool 
= (const char*)&fileToPrebind
[symtab
->stroff
]; 
2626                                         symbolTable 
= (struct macho_nlist
*)(&fileToPrebind
[symtab
->symoff
]); 
2630                                 dysymtab 
= (struct dysymtab_command
*)cmd
; 
2633                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2636         // walk all imports and re-resolve their n_value (needed incase prebinding is invalid) 
2637         struct macho_nlist
* lastImport 
= &symbolTable
[dysymtab
->iundefsym
+dysymtab
->nundefsym
]; 
2638         for (struct macho_nlist
* entry 
= &symbolTable
[dysymtab
->iundefsym
]; entry 
< lastImport
; ++entry
) { 
2640                 entry
->n_value 
= this->resolveUndefined(context
, entry
, this->usesTwoLevelNameSpace(), &dummy
); 
2643         // walk all exports and slide their n_value 
2644         struct macho_nlist
* lastExport 
= &symbolTable
[dysymtab
->iextdefsym
+dysymtab
->nextdefsym
]; 
2645         for (struct macho_nlist
* entry 
= &symbolTable
[dysymtab
->iextdefsym
]; entry 
< lastExport
; ++entry
) { 
2646                 if ( (entry
->n_type 
& N_TYPE
) == N_SECT 
) 
2647                         entry
->n_value 
+= fSlide
; 
2650         // walk all local symbols and slide their n_value 
2651         struct macho_nlist
* lastLocal 
= &symbolTable
[dysymtab
->ilocalsym
+dysymtab
->nlocalsym
]; 
2652         for (struct macho_nlist
* entry 
= &symbolTable
[dysymtab
->ilocalsym
]; entry 
< lastLocal
; ++entry
) { 
2653                 if ( entry
->n_sect 
!= NO_SECT 
) 
2654                         entry
->n_value 
+= fSlide
; 
2657         // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value 
2658         relocation_info
* const relocsStart 
= (struct relocation_info
*)(&fileToPrebind
[dysymtab
->locreloff
]); 
2659         relocation_info
* const relocsEnd 
= &relocsStart
[dysymtab
->nlocrel
]; 
2660         for (relocation_info
* reloc
=relocsStart
; reloc 
< relocsEnd
; ++reloc
) { 
2661                 if ( (reloc
->r_address 
& R_SCATTERED
) != 0 ) { 
2662                         struct scattered_relocation_info
* sreloc 
= (struct scattered_relocation_info
*)reloc
; 
2663                         if (sreloc
->r_length 
== RELOC_SIZE
) { 
2664                                 switch(sreloc
->r_type
) { 
2665                 #if __ppc__ || __ppc64__ 
2666                                         case PPC_RELOC_PB_LA_PTR
: 
2667                 #elif __i386__ || __x86_64__ 
2668                                         case GENERIC_RELOC_PB_LA_PTR
: 
2670                         #error unknown architecture 
2672                                                 sreloc
->r_value 
+= fSlide
; 
2679         // if multi-module, fix up objc_addr (10.4 and later runtime does not use this, but we want to keep file checksum consistent) 
2680         if ( dysymtab
->nmodtab 
!= 0 ) { 
2681                 dylib_module
* const modulesStart 
= (struct dylib_module
*)(&fileToPrebind
[dysymtab
->modtaboff
]); 
2682                 dylib_module
* const modulesEnd 
= &modulesStart
[dysymtab
->nmodtab
]; 
2683                 for (dylib_module
* module=modulesStart
; module < modulesEnd
; ++module) { 
2684                         if ( module->objc_module_info_size 
!= 0 ) { 
2685                                 module->objc_module_info_addr 
+= fSlide
; 
2691 // file on disk has been reprebound, but we are still mapped to old file 
2692 void ImageLoaderMachO::prebindUnmap(const LinkContext
& context
) 
2694         // this removes all mappings to the old file, so the kernel will unlink (delete) it. 
2695         //  We need to leave the load commands and __LINKEDIT in place 
2696         for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it 
!= fSegments
.end(); ++it
) { 
2697                 void* segmentAddress 
= (void*)((*it
)->getActualLoadAddress()); 
2698                 uintptr_t segmentSize 
= (*it
)->getSize(); 
2699                 //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath()); 
2700                 // save load commands at beginning of __TEXT segment 
2701                 if ( segmentAddress 
== fMachOData 
) { 
2702                         // typically load commands are one or two pages in size, so ok to alloc on stack 
2703                         uint32_t loadCmdSize 
= sizeof(macho_header
) + ((macho_header
*)fMachOData
)->sizeofcmds
; 
2704                         uint32_t loadCmdPages 
= (loadCmdSize
+4095) & (-4096); 
2705                         uint8_t loadcommands
[loadCmdPages
]; 
2706                         memcpy(loadcommands
, fMachOData
, loadCmdPages
); 
2707                         // unmap whole __TEXT segment 
2708                         munmap((void*)(fMachOData
), segmentSize
); 
2709                         // allocate and copy back mach_header and load commands 
2710                         vm_address_t addr 
= (vm_address_t
)fMachOData
; 
2711                         int r2 
= vm_allocate(mach_task_self(), &addr
, loadCmdPages
, false /*at this address*/); 
2713                                 fprintf(stderr
, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages
); 
2714                         memcpy((void*)fMachOData
, loadcommands
, loadCmdPages
); 
2715                         //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath()); 
2717                 else if ( strcmp((*it
)->getName(), "__LINKEDIT") == 0 ) { 
2718                         uint32_t linkEditSize 
= segmentSize
; 
2719                         uint32_t linkEditPages 
= (linkEditSize
+4095) & (-4096); 
2720                         void* linkEditTmp 
= malloc(linkEditPages
); 
2721                         memcpy(linkEditTmp
, segmentAddress
, linkEditPages
); 
2722                         // unmap whole __LINKEDIT segment 
2723                         munmap(segmentAddress
, segmentSize
); 
2724                         vm_address_t addr 
= (vm_address_t
)segmentAddress
; 
2725                         int r2 
= vm_allocate(mach_task_self(), &addr
, linkEditPages
, false /*at this address*/); 
2727                                 fprintf(stderr
, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages
); 
2728                         memcpy(segmentAddress
, linkEditTmp
, linkEditPages
); 
2729                         //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath()); 
2733                         // unmap any other segment 
2734                         munmap((void*)(segmentAddress
), (*it
)->getSize()); 
2741 SegmentMachO::SegmentMachO(const struct macho_segment_command
* cmd
, ImageLoaderMachO
* image
, const uint8_t* fileData
) 
2742  : fImage(image
), fSize(cmd
->vmsize
), fFileSize(cmd
->filesize
), fFileOffset(cmd
->fileoff
), fPreferredLoadAddress(cmd
->vmaddr
),  
2743         fVMProtection(cmd
->initprot
), fHasFixUps(false), fUnMapOnDestruction(false) 
2745         strncpy(fName
, cmd
->segname
, 16); 
2747         // scan sections for fix-up bit 
2748         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)cmd 
+ sizeof(struct macho_segment_command
)); 
2749         const struct macho_section
* const sectionsEnd 
= §ionsStart
[cmd
->nsects
]; 
2750         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2751                 if ( (sect
->flags 
& (S_ATTR_EXT_RELOC 
| S_ATTR_LOC_RELOC
)) != 0 ) 
2756 SegmentMachO::~SegmentMachO() 
2758         if ( fUnMapOnDestruction 
) { 
2759                 //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress()); 
2760                 munmap((void*)(this->getActualLoadAddress()), this->getSize()); 
2764 const ImageLoader
* SegmentMachO::getImage() 
2769 const char* SegmentMachO::getName() 
2774 uintptr_t SegmentMachO::getSize() 
2779 uintptr_t SegmentMachO::getFileSize() 
2784 uintptr_t SegmentMachO::getFileOffset() 
2789 bool SegmentMachO::readable() 
2791         return ( (fVMProtection 
& VM_PROT_READ
) != 0); 
2794 bool SegmentMachO::writeable() 
2796         return ((fVMProtection 
& VM_PROT_WRITE
) != 0); 
2799 bool SegmentMachO::executable() 
2801         return ((fVMProtection 
& VM_PROT_EXECUTE
) != 0); 
2804 bool SegmentMachO::unaccessible() 
2806         return (fVMProtection 
== 0); 
2809 bool SegmentMachO::hasFixUps() 
2814 uintptr_t SegmentMachO::getActualLoadAddress() 
2816         return fPreferredLoadAddress 
+ fImage
->fSlide
; 
2819 uintptr_t SegmentMachO::getPreferredLoadAddress() 
2821         return fPreferredLoadAddress
; 
2824 bool SegmentMachO::hasPreferredLoadAddress() 
2826         return (fPreferredLoadAddress 
!= 0); 
2829 void SegmentMachO::setUnMapWhenDestructed(bool unmap
) 
2831         fUnMapOnDestruction 
= unmap
; 
2834 static uint32_t *buildCRCTable(void) 
2836         uint32_t *table 
= new uint32_t[256]; 
2837         uint32_t p 
= 0xedb88320UL
;  // standard CRC-32 polynomial 
2839         for (unsigned int i 
= 0; i 
< 256; i
++) { 
2841                 for (unsigned int j 
= 0; j 
< 8; j
++) { 
2842                         if ( c 
& 1 ) c 
= p 
^ (c 
>> 1); 
2851 uint32_t SegmentMachO::crc32() 
2853         if ( !readable() ) return 0; 
2855         static uint32_t *crcTable 
= NULL
; 
2856         if ( !crcTable 
) crcTable 
= buildCRCTable(); 
2858         uint32_t crc 
= ~(uint32_t)0; 
2859         uint8_t *p 
= (uint8_t *)getActualLoadAddress();  
2860         uint8_t *end 
= p 
+ getSize(); 
2862                 crc 
= crcTable
[(crc 
& 0xff) ^ (*p
++)] ^ (crc 
>> 8); 
2864         return crc 
^ ~(uint32_t)0;