1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2010 Apple Inc. All rights reserved. 
   5  * @APPLE_LICENSE_HEADER_START@ 
   7  * This file contains Original Code and/or Modifications of Original Code 
   8  * as defined in and that are subject to the Apple Public Source License 
   9  * Version 2.0 (the 'License'). You may not use this file except in 
  10  * compliance with the License. Please obtain a copy of the License at 
  11  * http://www.opensource.apple.com/apsl/ and read it before using this 
  14  * The Original Code and all software distributed under the License are 
  15  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  16  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  17  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  18  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  19  * Please see the License for the specific language governing rights and 
  20  * limitations under the License. 
  22  * @APPLE_LICENSE_HEADER_END@ 
  25 // work around until conformance work is complete rdar://problem/4508801 
  30 #define __STDC_LIMIT_MACROS 
  34 #include <sys/types.h> 
  35 #include <sys/fcntl.h> 
  38 #include <mach/mach.h> 
  39 #include <mach/thread_status.h> 
  40 #include <mach-o/loader.h>  
  41 #include <mach-o/nlist.h>  
  42 #include <sys/sysctl.h> 
  43 #include <sys/syscall.h> 
  44 #include <libkern/OSAtomic.h> 
  45 #include <libkern/OSCacheControl.h> 
  47 #include <System/sys/codesign.h> 
  49 #include "ImageLoaderMachO.h" 
  50 #include "ImageLoaderMachOCompressed.h" 
  51 #if SUPPORT_CLASSIC_MACHO 
  52 #include "ImageLoaderMachOClassic.h" 
  54 #include "mach-o/dyld_images.h" 
  56 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs 
  57 extern "C" long __stack_chk_guard
; 
  59 #ifndef LC_LOAD_UPWARD_DYLIB 
  60         #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */ 
  63 #ifndef LC_VERSION_MIN_TVOS 
  64         #define LC_VERSION_MIN_TVOS 0x2F 
  67 #ifndef LC_VERSION_MIN_WATCHOS 
  68         #define LC_VERSION_MIN_WATCHOS 0x30 
  72 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables 
  74         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
  75         #define LC_ROUTINES_COMMAND             LC_ROUTINES_64 
  76         #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT 
  77         struct macho_segment_command    
: public segment_command_64  
{}; 
  78         struct macho_section                    
: public section_64  
{};         
  79         struct macho_routines_command   
: public routines_command_64  
{};        
  81         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
  82         #define LC_ROUTINES_COMMAND             LC_ROUTINES 
  83         #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64 
  84         struct macho_segment_command    
: public segment_command 
{}; 
  85         struct macho_section                    
: public section  
{};    
  86         struct macho_routines_command   
: public routines_command  
{};   
  89 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs 
= 0; 
  90 uint32_t ImageLoaderMachO::fgSymbolTrieSearchs 
= 0; 
  93 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,  
  94                                                                                                                                 uint32_t segOffsets
[], unsigned int libCount
) 
  95  : ImageLoader(path
, libCount
), fCoveredCodeLength(0), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0), 
  96         fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),  
  97 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false), 
  98 #if TEXT_RELOC_SUPPORT 
  99         fTextSegmentRebases(false), 
 100         fTextSegmentBinds(false), 
 103         fReadOnlyImportSegment(false), 
 105         fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false), 
 106         fHasInitializers(false), fHasTerminators(false), fRegisteredAsRequiresCoalescing(false) 
 108         fIsSplitSeg 
= ((mh
->flags 
& MH_SPLIT_SEGS
) != 0);         
 110         // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put  
 111         // each SegmentMachO object in array at end of ImageLoaderMachO object 
 112         const uint32_t cmd_count 
= mh
->ncmds
; 
 113         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 114         const struct load_command
* cmd 
= cmds
; 
 115         for (uint32_t i 
= 0, segIndex
=0; i 
< cmd_count
; ++i
) { 
 116                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 117                         const struct macho_segment_command
* segCmd 
= (struct macho_segment_command
*)cmd
; 
 118                         // ignore zero-sized segments 
 119                         if ( segCmd
->vmsize 
!= 0 ) { 
 120                                 // record offset of load command 
 121                                 segOffsets
[segIndex
++] = (uint32_t)((uint8_t*)segCmd 
- fMachOData
); 
 124                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 130 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has 
 131 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool inCache
, bool* compressed
, 
 132                                                                                         unsigned int* segCount
, unsigned int* libCount
, const LinkContext
& context
, 
 133                                                                                         const linkedit_data_command
** codeSigCmd
, 
 134                                                                                         const encryption_info_command
** encryptCmd
) 
 142         const uint32_t cmd_count 
= mh
->ncmds
; 
 143         const struct load_command
* const startCmds    
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
)); 
 144         const struct load_command
* const endCmds 
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
); 
 145         const struct load_command
* cmd 
= startCmds
; 
 146         bool foundLoadCommandSegment 
= false; 
 147         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 148                 uint32_t cmdLength 
= cmd
->cmdsize
; 
 149                 struct macho_segment_command
* segCmd
; 
 150                 if ( cmdLength 
< 8 ) { 
 151                         dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s", 
 154                 const struct load_command
* const nextCmd 
= (const struct load_command
*)(((char*)cmd
)+cmdLength
); 
 155                 if ( (nextCmd 
> endCmds
) || (nextCmd 
< cmd
) ) { 
 156                         dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s", 
 157                                                                                            i
, cmdLength
, mh
->sizeofcmds
, path
); 
 161                         case LC_DYLD_INFO_ONLY
: 
 164                         case LC_SEGMENT_COMMAND
: 
 165                                 segCmd 
= (struct macho_segment_command
*)cmd
; 
 166 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
 167                                 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS) 
 168                                 if ( (segCmd
->filesize 
> segCmd
->vmsize
) && (segCmd
->vmsize 
!= 0) ) 
 170                                 if ( segCmd
->filesize 
> segCmd
->vmsize 
) 
 172                                     dyld::throwf("malformed mach-o image: segment load command %s filesize is larger than vmsize", segCmd
->segname
); 
 173                                 // ignore zero-sized segments 
 174                                 if ( segCmd
->vmsize 
!= 0 ) 
 176                                 if ( context
.codeSigningEnforced 
) { 
 177                                         uintptr_t vmStart   
= segCmd
->vmaddr
; 
 178                                         uintptr_t vmSize    
= segCmd
->vmsize
; 
 179                                         uintptr_t vmEnd     
= vmStart 
+ vmSize
; 
 180                                         uintptr_t fileStart 
= segCmd
->fileoff
; 
 181                                         uintptr_t fileSize  
= segCmd
->filesize
; 
 182                                         if ( (intptr_t)(vmEnd
) < 0) 
 183                                                 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large", segCmd
->segname
); 
 184                                         if ( vmStart 
> vmEnd 
) 
 185                                                 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd
->segname
); 
 186                                         if ( vmSize 
!= fileSize 
) { 
 187                                                 if ( (segCmd
->initprot 
== 0) && (fileSize 
!= 0) ) 
 188                                                         dyld::throwf("malformed mach-o image: unaccessable segment %s has filesize != 0", segCmd
->segname
); 
 189                                                 else if ( vmSize 
< fileSize 
) 
 190                                                         dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd
->segname
); 
 193                                                 if ( (fileSize 
!= 0) && (segCmd
->initprot 
== (VM_PROT_READ 
| VM_PROT_EXECUTE
)) ) { 
 194                                                         if ( foundLoadCommandSegment 
) 
 195                                                                 throw "load commands in multiple segments"; 
 196                                                         foundLoadCommandSegment 
= true; 
 199                                         else if ( (fileStart 
< mh
->sizeofcmds
) && (fileSize 
!= 0) ) { 
 200                                                 // <rdar://problem/7942521> all load commands must be in an executable segment 
 201                                                 if ( (fileStart 
!= 0) || (fileSize 
< (mh
->sizeofcmds
+sizeof(macho_header
))) ) 
 202                                                         dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd
->segname
);  
 203                                                 if ( segCmd
->initprot 
!= (VM_PROT_READ 
| VM_PROT_EXECUTE
) )  
 204                                                         dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd
->segname
);  
 205                                                 if ( foundLoadCommandSegment 
) 
 206                                                         throw "load commands in multiple segments"; 
 207                                                 foundLoadCommandSegment 
= true; 
 210                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)segCmd 
+ sizeof(struct macho_segment_command
)); 
 211                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[segCmd
->nsects
]; 
 212                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 213                                                 if (!inCache 
&& sect
->offset 
!= 0 && ((sect
->offset 
+ sect
->size
) > (segCmd
->fileoff 
+ segCmd
->filesize
))) 
 214                                                         dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect
->segname
, sect
->sectname
, path
, segCmd
->segname
); 
 218                         case LC_SEGMENT_COMMAND_WRONG
: 
 219                                 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");  
 222                         case LC_LOAD_WEAK_DYLIB
: 
 223                         case LC_REEXPORT_DYLIB
: 
 224                         case LC_LOAD_UPWARD_DYLIB
: 
 227                         case LC_CODE_SIGNATURE
: 
 228                                 *codeSigCmd 
= (struct linkedit_data_command
*)cmd
; // only support one LC_CODE_SIGNATURE per image 
 230                         case LC_ENCRYPTION_INFO
: 
 231                         case LC_ENCRYPTION_INFO_64
: 
 232                                 *encryptCmd 
= (struct encryption_info_command
*)cmd
; // only support one LC_ENCRYPTION_INFO[_64] per image 
 238         if ( context
.codeSigningEnforced 
&& !foundLoadCommandSegment 
) 
 239                 throw "load commands not in a segment"; 
 241         // <rdar://problem/13145644> verify every segment does not overlap another segment 
 242         if ( context
.codeSigningEnforced 
) { 
 243                 uintptr_t lastFileStart 
= 0; 
 244                 uintptr_t linkeditFileStart 
= 0; 
 245                 const struct load_command
* cmd1 
= startCmds
; 
 246                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 247                         if ( cmd1
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 248                                 struct macho_segment_command
* segCmd1 
= (struct macho_segment_command
*)cmd1
; 
 249                                 uintptr_t vmStart1   
= segCmd1
->vmaddr
; 
 250                                 uintptr_t vmEnd1     
= segCmd1
->vmaddr 
+ segCmd1
->vmsize
; 
 251                                 uintptr_t fileStart1 
= segCmd1
->fileoff
; 
 252                                 uintptr_t fileEnd1   
= segCmd1
->fileoff 
+ segCmd1
->filesize
; 
 254                                 if (fileStart1 
> lastFileStart
) 
 255                                         lastFileStart 
= fileStart1
; 
 257                                 if ( strcmp(&segCmd1
->segname
[0], "__LINKEDIT") == 0 ) { 
 258                                         linkeditFileStart 
= fileStart1
; 
 261                                 const struct load_command
* cmd2 
= startCmds
; 
 262                                 for (uint32_t j 
= 0; j 
< cmd_count
; ++j
) { 
 265                                         if ( cmd2
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 266                                                 struct macho_segment_command
* segCmd2 
= (struct macho_segment_command
*)cmd2
; 
 267                                                 uintptr_t vmStart2   
= segCmd2
->vmaddr
; 
 268                                                 uintptr_t vmEnd2     
= segCmd2
->vmaddr 
+ segCmd2
->vmsize
; 
 269                                                 uintptr_t fileStart2 
= segCmd2
->fileoff
; 
 270                                                 uintptr_t fileEnd2   
= segCmd2
->fileoff 
+ segCmd2
->filesize
; 
 271                                                 if ( ((vmStart2 
<= vmStart1
) && (vmEnd2 
> vmStart1
) && (vmEnd1 
> vmStart1
))  
 272                                                 || ((vmStart2 
>= vmStart1
) && (vmStart2 
< vmEnd1
) && (vmEnd2 
> vmStart2
)) ) 
 273                                                         dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
); 
 274                                                 if ( ((fileStart2 
<= fileStart1
) && (fileEnd2 
> fileStart1
) && (fileEnd1 
> fileStart1
)) 
 275                                                   || ((fileStart2 
>= fileStart1
) && (fileStart2 
< fileEnd1
) && (fileEnd2 
> fileStart2
)) ) 
 276                                                         dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);  
 278                                         cmd2 
= (const struct load_command
*)(((char*)cmd2
)+cmd2
->cmdsize
); 
 281                         cmd1 
= (const struct load_command
*)(((char*)cmd1
)+cmd1
->cmdsize
); 
 284                 if (lastFileStart 
!= linkeditFileStart
) 
 285                         dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment"); 
 288         // fSegmentsArrayCount is only 8-bits 
 289         if ( *segCount 
> 255 ) 
 290                 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
); 
 292         // fSegmentsArrayCount is only 8-bits 
 293         if ( *libCount 
> 4095 ) 
 294                 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
); 
 296         if ( needsAddedLibSystemDepency(*libCount
, mh
) ) 
 302 // create image for main executable 
 303 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
) 
 305         //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n", 
 306         //      sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed)); 
 308         unsigned int segCount
; 
 309         unsigned int libCount
; 
 310         const linkedit_data_command
* codeSigCmd
; 
 311         const encryption_info_command
* encryptCmd
; 
 312         sniffLoadCommands(mh
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
); 
 313         // instantiate concrete class based on content of load commands 
 315                 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
); 
 317 #if SUPPORT_CLASSIC_MACHO 
 318                 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
); 
 320                 throw "missing LC_DYLD_INFO load command"; 
 325 // create image by mapping in a mach-o file 
 326 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,  
 327                                                                         uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
) 
 330         const unsigned int dataSize 
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
; 
 331         uint8_t buffer
[dataSize
]; 
 332         const uint8_t* fileData 
= firstPage
; 
 333         if ( dataSize 
> 4096 ) { 
 334                 // only read more if cmds take up more space than first page 
 336                 memcpy(buffer
, firstPage
, 4096); 
 337                 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096); 
 341         unsigned int segCount
; 
 342         unsigned int libCount
; 
 343         const linkedit_data_command
* codeSigCmd
; 
 344         const encryption_info_command
* encryptCmd
; 
 345         sniffLoadCommands((const macho_header
*)fileData
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
); 
 346         // instantiate concrete class based on content of load commands 
 348                 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, fileData
, dataSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, encryptCmd
, context
); 
 350 #if SUPPORT_CLASSIC_MACHO 
 351                 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, fileData
, dataSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
); 
 353                 throw "missing LC_DYLD_INFO load command"; 
 357 // create image by using cached mach-o file 
 358 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
) 
 360         // instantiate right concrete class 
 362         unsigned int segCount
; 
 363         unsigned int libCount
; 
 364         const linkedit_data_command
* codeSigCmd
; 
 365         const encryption_info_command
* encryptCmd
; 
 366         sniffLoadCommands(mh
, path
, true, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
); 
 367         // instantiate concrete class based on content of load commands 
 369                 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
); 
 371 #if SUPPORT_CLASSIC_MACHO 
 372                 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
); 
 374                 throw "missing LC_DYLD_INFO load command"; 
 378 // create image by copying an in-memory mach-o file 
 379 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
) 
 382         unsigned int segCount
; 
 383         unsigned int libCount
; 
 384         const linkedit_data_command
* sigcmd
; 
 385         const encryption_info_command
* encryptCmd
; 
 386         sniffLoadCommands(mh
, moduleName
, false, &compressed
, &segCount
, &libCount
, context
, &sigcmd
, &encryptCmd
); 
 387         // instantiate concrete class based on content of load commands 
 389                 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
); 
 391 #if SUPPORT_CLASSIC_MACHO 
 392                 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
); 
 394                 throw "missing LC_DYLD_INFO load command"; 
 399 int ImageLoaderMachO::crashIfInvalidCodeSignature() 
 401         // Now that segments are mapped in, try reading from first executable segment. 
 402         // If code signing is enabled the kernel will validate the code signature 
 403         // when paging in, and kill the process if invalid. 
 404         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 405                 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) { 
 406                         // return read value to ensure compiler does not optimize away load 
 407                         int* p 
= (int*)segActualLoadAddress(i
); 
 415 void ImageLoaderMachO::parseLoadCmds(const LinkContext
& context
) 
 417         // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 
 418         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 419                 // set up pointer to __LINKEDIT segment 
 420                 if ( strcmp(segName(i
),"__LINKEDIT") == 0 ) { 
 421                         if ( context
.codeSigningEnforced 
&& (segFileOffset(i
) > fCoveredCodeLength
)) 
 422                                 dyld::throwf("cannot load '%s' (segment outside of code signature)", this->getShortName()); 
 423                         fLinkEditBase 
= (uint8_t*)(segActualLoadAddress(i
) - segFileOffset(i
)); 
 425 #if TEXT_RELOC_SUPPORT 
 426                 // __TEXT segment always starts at beginning of file and contains mach_header and load commands 
 427                 if ( segExecutable(i
) ) { 
 428                         if ( segHasRebaseFixUps(i
) && (fSlide 
!= 0) ) 
 429                                 fTextSegmentRebases 
= true; 
 430                         if ( segHasBindFixUps(i
) ) 
 431                                 fTextSegmentBinds 
= true; 
 435                 if ( segIsReadOnlyImport(i
) ) 
 436                         fReadOnlyImportSegment 
= true; 
 438                 // some segment always starts at beginning of file and contains mach_header and load commands 
 439                 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) { 
 440                         fMachOData 
= (uint8_t*)(segActualLoadAddress(i
)); 
 444         // keep count of prebound images with weak exports 
 445         if ( this->participatesInCoalescing() ) { 
 446                 ++fgImagesRequiringCoalescing
; 
 447                 fRegisteredAsRequiresCoalescing 
= true; 
 448                 if ( this->hasCoalescedExports() )  
 449                         ++fgImagesHasWeakDefinitions
; 
 452         // keep count of images used in shared cache 
 453         if ( fInSharedCache 
) 
 454                 ++fgImagesUsedFromSharedCache
; 
 456         // walk load commands (mapped in at start of __TEXT segment) 
 457         const dyld_info_command
* dyldInfo 
= NULL
; 
 458         const macho_nlist
* symbolTable 
= NULL
; 
 459         const char* symbolTableStrings 
= NULL
; 
 460         const struct load_command
* firstUnknownCmd 
= NULL
; 
 461         const struct version_min_command
* minOSVersionCmd 
= NULL
; 
 462         const dysymtab_command
* dynSymbolTable 
= NULL
; 
 463         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 464         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 465         const struct load_command
* cmd 
= cmds
; 
 466         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 470                                         const struct symtab_command
* symtab 
= (struct symtab_command
*)cmd
; 
 471                                         symbolTableStrings 
= (const char*)&fLinkEditBase
[symtab
->stroff
]; 
 472                                         symbolTable 
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]); 
 476                                 dynSymbolTable 
= (struct dysymtab_command
*)cmd
; 
 478                         case LC_SUB_UMBRELLA
: 
 479                                 fHasSubUmbrella 
= true; 
 481                         case LC_SUB_FRAMEWORK
: 
 485                                 fHasSubLibraries 
= true; 
 487                         case LC_ROUTINES_COMMAND
: 
 491                         case LC_DYLD_INFO_ONLY
: 
 492                                 dyldInfo 
= (struct dyld_info_command
*)cmd
; 
 494                         case LC_SEGMENT_COMMAND
: 
 496                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
 497                                         const bool isTextSeg 
= (strcmp(seg
->segname
, "__TEXT") == 0); 
 498                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
 499                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 500                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 501                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
 502                                                 if ( type 
== S_MOD_INIT_FUNC_POINTERS 
) 
 503                                                         fHasInitializers 
= true; 
 504                                                 else if ( type 
== S_MOD_TERM_FUNC_POINTERS 
) 
 505                                                         fHasTerminators 
= true; 
 506                                                 else if ( type 
== S_DTRACE_DOF 
) 
 507                                                         fHasDOFSections 
= true; 
 508                                                 else if ( isTextSeg 
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) ) 
 509                                                         fEHFrameSectionOffset 
= (uint32_t)((uint8_t*)sect 
- fMachOData
); 
 510                                                 else if ( isTextSeg 
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) ) 
 511                                                         fUnwindInfoSectionOffset 
= (uint32_t)((uint8_t*)sect 
- fMachOData
); 
 515                         case LC_TWOLEVEL_HINTS
: 
 516                                 // no longer supported 
 520                                         fDylibIDOffset 
= (uint32_t)((uint8_t*)cmd 
- fMachOData
); 
 524                         case LC_LOAD_WEAK_DYLIB
: 
 525                     case LC_REEXPORT_DYLIB
: 
 526                         case LC_LOAD_UPWARD_DYLIB
: 
 528                                 // do nothing, just prevent LC_REQ_DYLD exception from occuring 
 530                         case LC_VERSION_MIN_MACOSX
: 
 531                         case LC_VERSION_MIN_IPHONEOS
: 
 532                         case LC_VERSION_MIN_TVOS
: 
 533                         case LC_VERSION_MIN_WATCHOS
: 
 534                                 minOSVersionCmd 
= (version_min_command
*)cmd
; 
 537                                 if ( (cmd
->cmd 
& LC_REQ_DYLD
) != 0 ) { 
 538                                         if ( firstUnknownCmd 
== NULL 
) 
 539                                                 firstUnknownCmd 
= cmd
; 
 543                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 545         if ( firstUnknownCmd 
!= NULL 
) { 
 546                 if ( minOSVersionCmd 
!= NULL 
)  { 
 547                         dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",  
 548                                                  this->getShortName(), 
 549                                                  minOSVersionCmd
->version 
>> 16, ((minOSVersionCmd
->version 
>> 8) & 0xff),  
 550                                                  firstUnknownCmd
->cmd
); 
 553                         dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd
->cmd
); 
 558         if ( dyldInfo 
!= NULL 
) 
 559                 this->setDyldInfo(dyldInfo
); 
 560         if ( symbolTable 
!= NULL
) 
 561                 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
); 
 565 // don't do this work in destructor because we need object to be full subclass 
 566 // for UnmapSegments() to work 
 567 void ImageLoaderMachO::destroy() 
 569         // update count of images with weak exports 
 570         if ( fRegisteredAsRequiresCoalescing 
) { 
 571                 --fgImagesRequiringCoalescing
; 
 572                 if ( this->hasCoalescedExports() )  
 573                         --fgImagesHasWeakDefinitions
; 
 576         // keep count of images used in shared cache 
 577         if ( fInSharedCache 
) 
 578                 --fgImagesUsedFromSharedCache
; 
 580         // unmap image when done 
 585 unsigned int ImageLoaderMachO::segmentCount() const 
 587         return fSegmentsCount
; 
 591 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const 
 593         uint32_t* lcOffsets 
= this->segmentCommandOffsets(); 
 594         uint32_t lcOffset 
=     lcOffsets
[segIndex
]; 
 595         return (macho_segment_command
*)(&fMachOData
[lcOffset
]); 
 598 const char*     ImageLoaderMachO::segName(unsigned int segIndex
) const 
 600         return segLoadCommand(segIndex
)->segname
; 
 604 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const 
 606         return segLoadCommand(segIndex
)->vmsize
; 
 610 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const 
 612         return segLoadCommand(segIndex
)->filesize
; 
 616 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
) 
 618         return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) ); 
 622 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const 
 624         return segLoadCommand(segIndex
)->fileoff
; 
 628 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const 
 630         return ( (segLoadCommand(segIndex
)->initprot 
& VM_PROT_READ
) != 0); 
 634 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const 
 636         return ( (segLoadCommand(segIndex
)->initprot 
& VM_PROT_WRITE
) != 0); 
 640 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const 
 642         return ( (segLoadCommand(segIndex
)->initprot 
& VM_PROT_EXECUTE
) != 0); 
 646 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const 
 648         return (segLoadCommand(segIndex
)->initprot 
== 0); 
 651 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const 
 653         return (segLoadCommand(segIndex
)->vmaddr 
!= 0); 
 656 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const 
 658         return segLoadCommand(segIndex
)->vmaddr
; 
 661 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const 
 663         return segLoadCommand(segIndex
)->vmaddr 
+ fSlide
; 
 667 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const 
 669         return segActualLoadAddress(segIndex
) + segSize(segIndex
); 
 672 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const 
 674 #if TEXT_RELOC_SUPPORT 
 675         // scan sections for fix-up bit 
 676         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
 677         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)segCmd 
+ sizeof(struct macho_segment_command
)); 
 678         const struct macho_section
* const sectionsEnd 
= §ionsStart
[segCmd
->nsects
]; 
 679         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 680                 if ( (sect
->flags 
& S_ATTR_LOC_RELOC
) != 0 ) 
 687 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const 
 689 #if TEXT_RELOC_SUPPORT 
 690         // scan sections for fix-up bit 
 691         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
 692         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)segCmd 
+ sizeof(struct macho_segment_command
)); 
 693         const struct macho_section
* const sectionsEnd 
= §ionsStart
[segCmd
->nsects
]; 
 694         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 695                 if ( (sect
->flags 
& S_ATTR_EXT_RELOC
) != 0 ) 
 703 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const 
 705         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
 706         return (    (segCmd
->initprot 
& VM_PROT_EXECUTE
)  
 707                         && ((segCmd
->initprot 
& VM_PROT_WRITE
) == 0)  
 708                         && (strcmp(segCmd
->segname
, "__IMPORT") == 0) ); 
 713 void ImageLoaderMachO::UnmapSegments() 
 715         // usually unmap image when done 
 716         if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) { 
 717                 // unmap TEXT segment last because it contains load command being inspected 
 718                 unsigned int textSegmentIndex 
= 0; 
 719                 for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 720                         //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this)); 
 721                         if ( strcmp(segName(i
), "__TEXT") == 0 ) { 
 722                                 textSegmentIndex 
= i
; 
 726                                 --ImageLoader::fgTotalSegmentsMapped
; 
 727                                 ImageLoader::fgTotalBytesMapped 
-= segSize(i
); 
 728                                 munmap((void*)segActualLoadAddress(i
), segSize(i
)); 
 732                 --ImageLoader::fgTotalSegmentsMapped
; 
 733                 ImageLoader::fgTotalBytesMapped 
-= segSize(textSegmentIndex
); 
 734                 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
)); 
 739 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code 
 740 void ImageLoaderMachO::preFetchDATA(int fd
, uint64_t offsetInFat
, const LinkContext
& context
) 
 742         if ( context
.linkingMainExecutable 
) { 
 743                 for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
 744                         if ( segWriteable(i
) && (segFileSize(i
) > 0) ) { 
 745                                 // prefetch writable segment that have mmap'ed regions 
 747                                 advice
.ra_offset 
= offsetInFat 
+ segFileOffset(i
); 
 748                                 advice
.ra_count 
= (int)segFileSize(i
); 
 749                                 // limit prefetch to 1MB (256 pages) 
 750                                 if ( advice
.ra_count 
> 1024*1024 ) 
 751                                         advice
.ra_count 
= 1024*1024; 
 752                                 // don't prefetch single pages, let them fault in 
 753                                 fgTotalBytesPreFetched 
+= advice
.ra_count
; 
 754                                 fcntl(fd
, F_RDADVISE
, &advice
); 
 755                                 if ( context
.verboseMapping 
) { 
 756                                         dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",  
 757                                                 segName(i
), segActualLoadAddress(i
), segActualLoadAddress(i
)+advice
.ra_count
-1); 
 765 bool ImageLoaderMachO::segmentsMustSlideTogether() const  
 770 bool ImageLoaderMachO::segmentsCanSlide() const  
 772         return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable()); 
 775 bool ImageLoaderMachO::isBundle() const  
 777         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 778         return ( mh
->filetype 
== MH_BUNDLE 
); 
 781 bool ImageLoaderMachO::isDylib() const  
 783         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 784         return ( mh
->filetype 
== MH_DYLIB 
); 
 787 bool ImageLoaderMachO::isExecutable() const  
 789         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 790         return ( mh
->filetype 
== MH_EXECUTE 
); 
 793 bool ImageLoaderMachO::isPositionIndependentExecutable() const  
 795         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 796         return ( (mh
->filetype 
== MH_EXECUTE
) && ((mh
->flags 
& MH_PIE
) != 0) ); 
 800 bool ImageLoaderMachO::forceFlat() const  
 802         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 803         return ( (mh
->flags 
& MH_FORCE_FLAT
) != 0 ); 
 806 bool ImageLoaderMachO::usesTwoLevelNameSpace() const 
 808         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 809         return ( (mh
->flags 
& MH_TWOLEVEL
) != 0 ); 
 812 bool ImageLoaderMachO::isPrebindable() const  
 814         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 815         return ( (mh
->flags 
& MH_PREBOUND
) != 0 ); 
 818 bool ImageLoaderMachO::hasCoalescedExports() const  
 820         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 821         return ( (mh
->flags 
& MH_WEAK_DEFINES
) != 0 ); 
 824 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const  
 826         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 827         return ( (mh
->flags 
& MH_BINDS_TO_WEAK
) != 0 ); 
 830 bool ImageLoaderMachO::participatesInCoalescing() const  
 832         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
 833         // if image is loaded with RTLD_LOCAL, then its symbols' visibility 
 834         // is reduced and it can't coalesce with other images 
 835         if ( this->hasHiddenExports() ) 
 837         return ( (mh
->flags 
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 ); 
 842 void ImageLoaderMachO::setSlide(intptr_t slide
) 
 847 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
,  uint64_t offsetInFatFile
, const LinkContext
& context
) 
 849         // if dylib being loaded has no code signature load command 
 850         if ( codeSigCmd 
== NULL 
) { 
 851 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
 852                 bool codeSigningEnforced 
= context
.codeSigningEnforced
; 
 853                 if ( context
.mainExecutableCodeSigned 
&& !codeSigningEnforced 
) { 
 854                         static bool codeSignEnforcementDynamicallyEnabled 
= false; 
 855                         if ( !codeSignEnforcementDynamicallyEnabled 
) { 
 857                                 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) { 
 858                                         if ( flags 
& CS_ENFORCEMENT 
) { 
 859                                                 codeSignEnforcementDynamicallyEnabled 
= true; 
 863                         codeSigningEnforced 
= codeSignEnforcementDynamicallyEnabled
; 
 865                 // if we require dylibs to be code signed 
 866                 if ( codeSigningEnforced  
) { 
 867                         // if there is a non-load command based code signature, use it 
 868                         off_t offset 
= (off_t
)offsetInFatFile
; 
 869                         if ( fcntl(fd
, F_FINDSIGS
, &offset
, sizeof(offset
)) != -1 ) 
 871                         // otherwise gracefully return from dlopen() 
 872                         dyld::throwf("required code signature missing for '%s'\n", this->getPath()); 
 875                 //Since we don't have a range for the signature we have to assume full coverage 
 876                 fCoveredCodeLength 
= UINT64_MAX
; 
 879 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
 880                 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools 
 881                 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9 
) { 
 885                 fsignatures_t siginfo
; 
 886                 siginfo
.fs_file_start
=offsetInFatFile
;                          // start of mach-o slice in fat file  
 887                 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
);       // start of CD in mach-o file 
 888                 siginfo
.fs_blob_size
=codeSigCmd
->datasize
;                      // size of CD 
 889                 int result 
= fcntl(fd
, F_ADDFILESIGS_RETURN
, &siginfo
); 
 891 #if TARGET_IPHONE_SIMULATOR 
 892                 // rdar://problem/18759224> check range covered by the code directory after loading 
 893                 // Attempt to fallback only if we are in the simulator 
 895                 if ( result 
== -1 ) { 
 896                         result 
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
); 
 897                         siginfo
.fs_file_start 
= codeSigCmd
->dataoff
; 
 901                 if ( result 
== -1 ) { 
 902                         if ( (errno 
== EPERM
) || (errno 
== EBADEXEC
) ) 
 903                                 dyld::throwf("code signature invalid for '%s'\n", this->getPath()); 
 904                         if ( context
.verboseCodeSignatures 
)  
 905                                 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno
); 
 906                         siginfo
.fs_file_start 
= UINT64_MAX
; 
 907                 } else if ( context
.verboseCodeSignatures 
)  { 
 908                         dyld::log("dyld: Registered code signature for %s\n", this->getPath()); 
 910                 fCoveredCodeLength 
= siginfo
.fs_file_start
; 
 914 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command
* codeSigCmd
, int fd
, const uint8_t *fileData
, size_t lenFileData
, off_t offsetInFat
, const LinkContext
& context
) 
 916 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
 917         // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure 
 918         // We need to ignore older code signatures because they will be bad. 
 919         if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9 
) { 
 923         if (codeSigCmd 
!= NULL
) { 
 924                 if ( context
.verboseMapping 
) 
 925                         dyld::log("dyld: validate pages: %llu\n", (unsigned long long)offsetInFat
); 
 927                 void *fdata 
= xmmap(NULL
, lenFileData
, PROT_READ 
| PROT_EXEC
, MAP_SHARED
, fd
, offsetInFat
); 
 928                 if ( fdata 
== MAP_FAILED 
) { 
 929                         if ( context
.processRequiresLibraryValidation 
) 
 930                                 dyld::throwf("cannot load image with wrong team ID in process using Library Validation"); 
 932                                 dyld::throwf("mmap() errno=%d validating first page of '%s'", errno
, getInstallPath()); 
 934                 if ( memcmp(fdata
, fileData
, lenFileData
) != 0 ) 
 935                         dyld::throwf("mmap() page compare failed for '%s'", getInstallPath()); 
 936                 munmap(fdata
, lenFileData
); 
 941 const char* ImageLoaderMachO::getInstallPath() const 
 943         if ( fDylibIDOffset 
!= 0 ) { 
 944                 const dylib_command
* dylibID 
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]); 
 945                 return (char*)dylibID 
+ dylibID
->dylib
.name
.offset
; 
 950 void ImageLoaderMachO::registerInterposing() 
 952         // mach-o files advertise interposing by having a __DATA __interpose section 
 953         struct InterposeData 
{ uintptr_t replacement
; uintptr_t replacee
; }; 
 954         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 955         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 956         const struct load_command
* cmd 
= cmds
; 
 957         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 959                         case LC_SEGMENT_COMMAND
: 
 961                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
 962                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
 963                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 964                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 965                                                 if ( ((sect
->flags 
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) { 
 966                                                         const InterposeData
* interposeArray 
= (InterposeData
*)(sect
->addr 
+ fSlide
); 
 967                                                         const size_t count 
= sect
->size 
/ sizeof(InterposeData
); 
 968                                                         for (size_t i
=0; i 
< count
; ++i
) { 
 969                                                                 ImageLoader::InterposeTuple tuple
; 
 970                                                                 tuple
.replacement               
= interposeArray
[i
].replacement
; 
 971                                                                 tuple
.neverImage                
= this; 
 972                                                                 tuple
.onlyImage             
= NULL
; 
 973                                                                 tuple
.replacee                  
= interposeArray
[i
].replacee
; 
 974                                                                 // <rdar://problem/7937695> verify that replacement is in this image 
 975                                                                 if ( this->containsAddress((void*)tuple
.replacement
) ) { 
 976                                                                         // chain to any existing interpositions 
 977                                                                         for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
 978                                                                                 if ( it
->replacee 
== tuple
.replacee 
) { 
 979                                                                                         tuple
.replacee 
= it
->replacement
; 
 982                                                                         ImageLoader::fgInterposingTuples
.push_back(tuple
); 
 990                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 994 uint32_t ImageLoaderMachO::sdkVersion() const 
 996         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 997         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 998         const struct load_command
* cmd 
= cmds
; 
 999         const struct version_min_command
* versCmd
; 
1000         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1001                 switch ( cmd
->cmd 
) { 
1002                         case LC_VERSION_MIN_MACOSX
: 
1003                         case LC_VERSION_MIN_IPHONEOS
: 
1004                         case LC_VERSION_MIN_TVOS
: 
1005                         case LC_VERSION_MIN_WATCHOS
: 
1006                                 versCmd 
= (version_min_command
*)cmd
; 
1007                                 return versCmd
->sdk
; 
1009                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1014 uint32_t ImageLoaderMachO::minOSVersion(const mach_header
* mh
) 
1016         const uint32_t cmd_count 
= mh
->ncmds
; 
1017         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
)); 
1018         const struct load_command
* cmd 
= cmds
; 
1019         const struct version_min_command
* versCmd
; 
1020         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1021                 switch ( cmd
->cmd 
) { 
1022                         case LC_VERSION_MIN_MACOSX
: 
1023                         case LC_VERSION_MIN_IPHONEOS
: 
1024                         case LC_VERSION_MIN_TVOS
: 
1025                         case LC_VERSION_MIN_WATCHOS
: 
1026                                 versCmd 
= (version_min_command
*)cmd
; 
1027                                 return versCmd
->version
; 
1029                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1034 uint32_t ImageLoaderMachO::minOSVersion() const 
1036         return ImageLoaderMachO::minOSVersion(machHeader()); 
1040 void* ImageLoaderMachO::getThreadPC() const 
1042         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1043         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1044         const struct load_command
* cmd 
= cmds
; 
1045         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1046                 if ( cmd
->cmd 
== LC_MAIN 
) { 
1047                         entry_point_command
* mainCmd 
= (entry_point_command
*)cmd
; 
1048                         void* entry 
= (void*)(mainCmd
->entryoff 
+ (char*)fMachOData
); 
1049                         // <rdar://problem/8543820&9228031> verify entry point is in image 
1050                         if ( this->containsAddress(entry
) ) 
1053                                 throw "LC_MAIN entryoff is out of range"; 
1055                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1061 void* ImageLoaderMachO::getMain() const 
1063         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1064         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1065         const struct load_command
* cmd 
= cmds
; 
1066         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1071                                 const i386_thread_state_t
* registers 
= (i386_thread_state_t
*)(((char*)cmd
) + 16); 
1072                                 void* entry 
= (void*)(registers
->eip 
+ fSlide
); 
1074                                 const x86_thread_state64_t
* registers 
= (x86_thread_state64_t
*)(((char*)cmd
) + 16); 
1075                                 void* entry 
= (void*)(registers
->rip 
+ fSlide
); 
1077                                 const arm_thread_state_t
* registers 
= (arm_thread_state_t
*)(((char*)cmd
) + 16); 
1078                                 void* entry 
= (void*)(registers
->__pc 
+ fSlide
); 
1080                                 const arm_thread_state64_t
* registers 
= (arm_thread_state64_t
*)(((char*)cmd
) + 16); 
1081                                 void* entry 
= (void*)(registers
->__pc 
+ fSlide
); 
1083                                 #warning need processor specific code 
1085                                 // <rdar://problem/8543820&9228031> verify entry point is in image 
1086                                 if ( this->containsAddress(entry
) ) { 
1092                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1094         throw "no valid entry point"; 
1097 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
) 
1099         // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem 
1103         // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind 
1104         if ( mh
->filetype 
== MH_EXECUTE 
)  
1107         bool isNonOSdylib 
= false; 
1108         const uint32_t cmd_count 
= mh
->ncmds
; 
1109         const struct load_command
* const cmds 
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
)); 
1110         const struct load_command
* cmd 
= cmds
; 
1111         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1114                         case LC_LOAD_WEAK_DYLIB
: 
1115                         case LC_REEXPORT_DYLIB
: 
1116                         case LC_LOAD_UPWARD_DYLIB
: 
1120                                 const dylib_command
* dylibID 
= (dylib_command
*)cmd
; 
1121                                 const char* installPath 
= (char*)cmd 
+ dylibID
->dylib
.name
.offset
; 
1122                                 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents 
1123                                 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first 
1124                                 // <rdar://problem/6497528> rosetta circular dependency spew 
1125                                 isNonOSdylib 
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/usr/libexec/oah/Shims", 9) != 0) ); 
1129                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1131         return isNonOSdylib
; 
1135 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[]) 
1137         if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) { 
1138                 DependentLibraryInfo
* lib 
= &libs
[0]; 
1139                 lib
->name 
= "/usr/lib/libSystem.B.dylib"; 
1140                 lib
->info
.checksum 
= 0; 
1141                 lib
->info
.minVersion 
= 0; 
1142                 lib
->info
.maxVersion 
= 0; 
1143                 lib
->required 
= false; 
1144                 lib
->reExported 
= false; 
1145                 lib
->upward 
= false; 
1149                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1150                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1151                 const struct load_command
* cmd 
= cmds
; 
1152                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1155                                 case LC_LOAD_WEAK_DYLIB
: 
1156                                 case LC_REEXPORT_DYLIB
: 
1157                                 case LC_LOAD_UPWARD_DYLIB
: 
1159                                         const struct dylib_command
* dylib 
= (struct dylib_command
*)cmd
; 
1160                                         DependentLibraryInfo
* lib 
= &libs
[index
++]; 
1161                                         lib
->name 
= (char*)cmd 
+ dylib
->dylib
.name
.offset
; 
1162                                         //lib->name = strdup((char*)cmd + dylib->dylib.name.offset); 
1163                                         lib
->info
.checksum 
= dylib
->dylib
.timestamp
; 
1164                                         lib
->info
.minVersion 
= dylib
->dylib
.compatibility_version
; 
1165                                         lib
->info
.maxVersion 
= dylib
->dylib
.current_version
; 
1166                                         lib
->required 
= (cmd
->cmd 
!= LC_LOAD_WEAK_DYLIB
); 
1167                                         lib
->reExported 
= (cmd
->cmd 
== LC_REEXPORT_DYLIB
); 
1168                                         lib
->upward 
= (cmd
->cmd 
== LC_LOAD_UPWARD_DYLIB
); 
1172                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1177 ImageLoader::LibraryInfo 
ImageLoaderMachO::doGetLibraryInfo() 
1180         if ( fDylibIDOffset 
!= 0 ) { 
1181                 const dylib_command
* dylibID 
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]); 
1182                 info
.minVersion 
= dylibID
->dylib
.compatibility_version
; 
1183                 info
.maxVersion 
= dylibID
->dylib
.current_version
; 
1184                 info
.checksum 
= dylibID
->dylib
.timestamp
; 
1187                 info
.minVersion 
= 0; 
1188                 info
.maxVersion 
= 0;             
1194 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const 
1196         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1197         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1198         const struct load_command
* cmd 
= cmds
; 
1199         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1202                                 const char* pathToAdd 
= NULL
; 
1203                                 const char* path 
= (char*)cmd 
+ ((struct rpath_command
*)cmd
)->path
.offset
; 
1204                                 if ( (strncmp(path
, "@loader_path", 12) == 0) && ((path
[12] == '/') || (path
[12] == '\0')) ) { 
1205                                         if ( context
.processIsRestricted 
&& !context
.processRequiresLibraryValidation 
&& (context
.mainExecutable 
== this) ) { 
1206                                                 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path
, this->getPath()); 
1209                                         char resolvedPath
[PATH_MAX
]; 
1210                                         if ( realpath(this->getPath(), resolvedPath
) != NULL 
) { 
1211                                                 char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
1212                                                 strcpy(newRealPath
, resolvedPath
); 
1213                                                 char* addPoint 
= strrchr(newRealPath
,'/'); 
1214                                                 if ( addPoint 
!= NULL 
) { 
1215                                                         strcpy(addPoint
, &path
[12]); 
1216                                                         pathToAdd 
= strdup(newRealPath
); 
1220                                 else if ( (strncmp(path
, "@executable_path", 16) == 0) && ((path
[16] == '/') || (path
[16] == '\0')) ) { 
1221                                         if ( context
.processIsRestricted 
&& !context
.processRequiresLibraryValidation 
) { 
1222                                                 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path
, this->getPath()); 
1225                                         char resolvedPath
[PATH_MAX
]; 
1226                                         if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL 
) { 
1227                                                 char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
1228                                                 strcpy(newRealPath
, resolvedPath
); 
1229                                                 char* addPoint 
= strrchr(newRealPath
,'/'); 
1230                                                 if ( addPoint 
!= NULL 
) { 
1231                                                         strcpy(addPoint
, &path
[16]); 
1232                                                         pathToAdd 
= strdup(newRealPath
); 
1236                                 else if ( (path
[0] != '/') && context
.processIsRestricted 
&& !context
.processRequiresLibraryValidation 
) { 
1237                                         dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath()); 
1240                                 else if ( (path
[0] == '/') && (context
.rootPaths 
!= NULL
) ) { 
1241                                         // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths 
1242                                         // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists 
1244                                         for(const char** rp 
= context
.rootPaths
; *rp 
!= NULL
; ++rp
) { 
1245                                                 char newPath
[PATH_MAX
]; 
1246                                                 strlcpy(newPath
, *rp
, PATH_MAX
); 
1247                                                 strlcat(newPath
, path
, PATH_MAX
); 
1248                                                 struct stat stat_buf
; 
1249                                                 if ( stat(newPath
, &stat_buf
) != -1 ) { 
1250                                                         //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath); 
1251                                                         pathToAdd 
= strdup(newPath
); 
1257                                                 // make copy so that all elements of 'paths' can be freed 
1258                                                 pathToAdd 
= strdup(path
); 
1262                                         // make copy so that all elements of 'paths' can be freed 
1263                                         pathToAdd 
= strdup(path
); 
1265                                 if ( pathToAdd 
!= NULL 
) 
1266                                         paths
.push_back(pathToAdd
); 
1269                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1274 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const 
1276         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1277         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1278         const struct load_command
* cmd 
= cmds
; 
1279         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1282                                 uuid_command
* uc 
= (uuid_command
*)cmd
; 
1283                                 memcpy(uuid
, uc
->uuid
, 16); 
1286                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1292 void ImageLoaderMachO::doRebase(const LinkContext
& context
) 
1294         // if prebound and loaded at prebound address, then no need to rebase 
1295         if ( this->usablePrebinding(context
) ) { 
1296                 // skip rebasing because prebinding is valid 
1297                 ++fgImagesWithUsedPrebinding
; // bump totals for statistics 
1301         // print why prebinding was not used 
1302         if ( context
.verbosePrebinding 
) { 
1303                 if ( !this->isPrebindable() ) { 
1304                         dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath()); 
1306                 else if ( fSlide 
!= 0 ) { 
1307                         dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath()); 
1309                 else if ( !this->allDependentLibrariesAsWhenPreBound() ) { 
1310                         dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath()); 
1312                 else if ( !this->usesTwoLevelNameSpace() ){ 
1313                         dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath()); 
1316                         dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath()); 
1320         //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath()); 
1322 #if PREBOUND_IMAGE_SUPPORT 
1323         // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers 
1324         // if this image is in the shared cache, do not reset, they will be bound in doBind() 
1325         if ( this->isPrebindable() && !fInSharedCache 
) 
1326                 this->resetPreboundLazyPointers(context
); 
1329         // if loaded at preferred address, no rebasing necessary 
1330         if ( this->fSlide 
== 0 )  
1333 #if TEXT_RELOC_SUPPORT 
1334         // if there are __TEXT fixups, temporarily make __TEXT writable 
1335         if ( fTextSegmentRebases 
)  
1336                 this->makeTextSegmentWritable(context
, true); 
1339         // do actual rebasing 
1340         this->rebase(context
); 
1342 #if TEXT_RELOC_SUPPORT 
1343         // if there were __TEXT fixups, restore write protection 
1344         if ( fTextSegmentRebases 
)  
1345                 this->makeTextSegmentWritable(context
, false); 
1350 #if TEXT_RELOC_SUPPORT 
1351 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
) 
1353         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
1354                 if ( segExecutable(i
) ) { 
1356                                 segMakeWritable(i
, context
); 
1359                         #if !__i386__ && !__x86_64__ 
1360                                 // some processors require range to be invalidated before it is made executable 
1361                                 sys_icache_invalidate((void*)segActualLoadAddress(i
), segSize(textSegmentIndex
)); 
1363                                 segProtect(i
, context
); 
1371 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const ImageLoader
** foundIn
) const 
1373         // look in this image first 
1374         const ImageLoader::Symbol
* result 
= this->findExportedSymbol(name
, foundIn
); 
1375         if ( result 
!= NULL 
) 
1378         if ( searchReExports 
) { 
1379                 for(unsigned int i
=0; i 
< libraryCount(); ++i
){ 
1380                         if ( libReExported(i
) ) { 
1381                                 ImageLoader
* image 
= libImage(i
); 
1382                                 if ( image 
!= NULL 
) { 
1383                                         const Symbol
* result 
= image
->findExportedSymbol(name
, searchReExports
, foundIn
); 
1384                                         if ( result 
!= NULL 
) 
1397 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,  
1398                                                                                         const ImageLoader
* requestor
, bool runResolver
) const 
1400         return this->getSymbolAddress(sym
, requestor
, context
, runResolver
); 
1403 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,  
1404                                                                                                 const LinkContext
& context
, bool runResolver
) const 
1406         uintptr_t result 
= exportedSymbolAddress(context
, sym
, requestor
, runResolver
); 
1407         // check for interposing overrides 
1408         result 
= interposedAddress(context
, result
, requestor
); 
1412 ImageLoader::DefinitionFlags 
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const 
1414         if ( exportedSymbolIsWeakDefintion(sym
) ) 
1415                 return kWeakDefinition
; 
1417                 return kNoDefinitionOptions
; 
1420 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const 
1422         return exportedSymbolName(sym
); 
1425 uint32_t ImageLoaderMachO::getExportedSymbolCount() const 
1427         return exportedSymbolCount(); 
1431 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const 
1433         return exportedSymbolIndexed(index
); 
1437 uint32_t ImageLoaderMachO::getImportedSymbolCount() const 
1439         return importedSymbolCount(); 
1443 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const 
1445         return importedSymbolIndexed(index
); 
1449 ImageLoader::ReferenceFlags 
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const 
1451         ImageLoader::ReferenceFlags flags 
= kNoReferenceOptions
; 
1456 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const 
1458         return importedSymbolName(sym
); 
1462 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
) 
1464         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1465         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1466         const struct load_command
* cmd 
= cmds
; 
1467         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1469                         case LC_SEGMENT_COMMAND
: 
1471                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1472                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1473                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1474                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1475                                                 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) { 
1476                                                         *start 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1477                                                         *length 
= sect
->size
; 
1484                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1491 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
) 
1493         info
->mh 
= this->machHeader(); 
1494         info
->dwarf_section 
= 0; 
1495         info
->dwarf_section_length 
= 0; 
1496         info
->compact_unwind_section 
= 0; 
1497         info
->compact_unwind_section_length 
= 0; 
1498         if ( fEHFrameSectionOffset 
!= 0 ) { 
1499                 const macho_section
* sect 
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
]; 
1500                 info
->dwarf_section 
= (void*)(sect
->addr 
+ fSlide
); 
1501                 info
->dwarf_section_length 
= sect
->size
; 
1503         if ( fUnwindInfoSectionOffset 
!= 0 ) { 
1504                 const macho_section
* sect 
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
]; 
1505                 info
->compact_unwind_section 
= (void*)(sect
->addr 
+ fSlide
); 
1506                 info
->compact_unwind_section_length 
= sect
->size
; 
1511 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
) 
1513         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1514         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1515         const struct load_command
* cmd 
= cmds
; 
1516         const uintptr_t unslidInteriorAddress 
= (uintptr_t)imageInterior 
- this->getSlide(); 
1517         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1519                         case LC_SEGMENT_COMMAND
: 
1521                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1522                                         if ( (unslidInteriorAddress 
>= seg
->vmaddr
) && (unslidInteriorAddress 
< (seg
->vmaddr
+seg
->vmsize
)) ) { 
1523                                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1524                                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1525                                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1526                                                         if ((sect
->addr 
<= unslidInteriorAddress
) && (unslidInteriorAddress 
< (sect
->addr
+sect
->size
))) { 
1527                                                                 if ( segmentName 
!= NULL 
) 
1528                                                                         *segmentName 
= sect
->segname
; 
1529                                                                 if ( sectionName 
!= NULL 
) 
1530                                                                         *sectionName 
= sect
->sectname
; 
1531                                                                 if ( sectionOffset 
!= NULL 
) 
1532                                                                         *sectionOffset 
= unslidInteriorAddress 
- sect
->addr
; 
1540                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1546 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,  
1547                                                                                                                                         const char* referencedFrom
, const char* fromVersMismatch
, 
1548                                                                                                                                         const char* expectedIn
) 
1550         // record values for possible use by CrashReporter or Finder 
1551         (*context
.setErrorStrings
)(dyld_error_kind_symbol_missing
, referencedFrom
, expectedIn
, symbol
); 
1552         dyld::throwf("Symbol not found: %s\n  Referenced from: %s%s\n  Expected in: %s\n", 
1553                                         symbol
, referencedFrom
, fromVersMismatch
, expectedIn
); 
1556 const mach_header
* ImageLoaderMachO::machHeader() const 
1558         return (mach_header
*)fMachOData
; 
1561 uintptr_t ImageLoaderMachO::getSlide() const 
1566 // hmm. maybe this should be up in ImageLoader?? 
1567 const void* ImageLoaderMachO::getEnd() const 
1569         uintptr_t lastAddress 
= 0; 
1570         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
1571                 uintptr_t segEnd 
= segActualEndAddress(i
); 
1572                 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) { 
1573                         if ( segEnd 
> lastAddress 
) 
1574                                 lastAddress 
= segEnd
; 
1577         return (const void*)lastAddress
; 
1581 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t location
, uintptr_t value
,  
1582                                                                                 const ImageLoader
* targetImage
, uint8_t type
, const char* symbolName
,  
1583                                                                                 intptr_t addend
, const char* msg
) 
1586         if ( context
.verboseBind 
) { 
1588                         dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n", 
1589                                                 msg
, this->getShortName(), (uintptr_t)location
, 
1590                                                 ((targetImage 
!= NULL
) ? targetImage
->getShortName() : "<weak_import-missing>"), 
1591                                                 symbolName
, (uintptr_t)location
, value
, addend
); 
1593                         dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n", 
1594                                                 msg
, this->getShortName(), (uintptr_t)location
, 
1595                                                 ((targetImage 
!= NULL
) ? targetImage
->getShortName() : "<weak>import-missing>"), 
1596                                                  symbolName
, (uintptr_t)location
, value
); 
1599 //      dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName); 
1603         uintptr_t* locationToFix 
= (uintptr_t*)location
; 
1605         uintptr_t newValue 
= value
+addend
; 
1608                 case BIND_TYPE_POINTER
: 
1609                         // test first so we don't needless dirty pages 
1610                         if ( *locationToFix 
!= newValue 
) 
1611                                 *locationToFix 
= newValue
; 
1613                 case BIND_TYPE_TEXT_ABSOLUTE32
: 
1614                         loc32 
= (uint32_t*)locationToFix
; 
1615                         value32 
= (uint32_t)newValue
; 
1616                         if ( *loc32 
!= value32 
) 
1619                 case BIND_TYPE_TEXT_PCREL32
: 
1620                         loc32 
= (uint32_t*)locationToFix
; 
1621                         value32 
= (uint32_t)(newValue 
- (((uintptr_t)locationToFix
) + 4)); 
1622                         if ( *loc32 
!= value32 
) 
1626                         dyld::throwf("bad bind type %d", type
); 
1629         // update statistics 
1630         ++fgTotalBindFixups
; 
1639 #if SUPPORT_OLD_CRT_INITIALIZATION 
1640 // first 16 bytes of "start" in crt1.o 
1642         static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 }; 
1647         void*                   dyldLazyBinder
;         // filled in at launch by dyld to point into dyld to &stub_binding_helper 
1648         void*                   dyldFuncLookup
;         // filled in at launch by dyld to point into dyld to &_dyld_func_lookup 
1649         // the following only exist in main executables built for 10.5 or later 
1653 // These are defined in dyldStartup.s 
1654 extern "C" void stub_binding_helper(); 
1657 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
) 
1659         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1660         const uint32_t cmd_count 
= mh
->ncmds
; 
1661         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1662         const struct load_command
* cmd
; 
1663         // There used to be some optimizations to skip this section scan, but we need to handle the  
1664         // __dyld section in libdyld.dylib, so everything needs to be scanned for now. 
1665         // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv 
1668                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1669                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1670                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1671                                 if ( strncmp(seg
->segname
, "__DATA", 6) == 0 ) { 
1672                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1673                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1674                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1675                                                 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) { 
1676                                                         struct DATAdyld
* dd 
= (struct DATAdyld
*)(sect
->addr 
+ fSlide
); 
1677                                 #if !__arm64__ && !__ARM_ARCH_7K__ 
1678                                                         if ( sect
->size 
> offsetof(DATAdyld
, dyldLazyBinder
) ) { 
1679                                                                 if ( dd
->dyldLazyBinder 
!= (void*)&stub_binding_helper 
) 
1680                                                                         dd
->dyldLazyBinder 
= (void*)&stub_binding_helper
; 
1682                                 #endif // !__arm64__ 
1683                                                         if ( sect
->size 
> offsetof(DATAdyld
, dyldFuncLookup
) ) { 
1684                                                                 if ( dd
->dyldFuncLookup 
!= (void*)&_dyld_func_lookup 
) 
1685                                                                         dd
->dyldFuncLookup 
= (void*)&_dyld_func_lookup
; 
1687                                                         if ( mh
->filetype 
== MH_EXECUTE 
) { 
1688                                                                 // there are two ways to get the program variables 
1689                                                                 if ( (sect
->size 
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh 
== mh
) ) { 
1690                                                                         // some really old binaries have space for vars, but it is zero filled 
1691                                                                         // main executable has 10.5 style __dyld section that has program variable pointers 
1692                                                                         context
.setNewProgramVars(dd
->vars
); 
1695                                                                         // main executable is pre-10.5 and requires the symbols names to be looked up 
1696                                                                         this->lookupProgramVars(context
); 
1697                                 #if SUPPORT_OLD_CRT_INITIALIZATION 
1698                                                                         // If the first 16 bytes of the entry point's instructions do not  
1699                                                                         // match what crt1.o supplies, then the program has a custom entry point. 
1700                                                                         // This means it might be doing something that needs to be executed before  
1701                                                                         // initializers are run.  
1702                                                                         if ( memcmp(this->getMain(), sStandardEntryPointInstructions
, 16) != 0 ) { 
1703                                                                                 if ( context
.verboseInit 
) 
1704                                                                                         dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n"); 
1705                                                                                 context
.setRunInitialzersOldWay(); 
1710                                                         else if ( mh
->filetype 
== MH_DYLIB 
) { 
1711                                                                 const char* installPath 
= this->getInstallPath(); 
1712                                                                 if ( (installPath 
!= NULL
) && (strncmp(installPath
, "/usr/lib/", 9) == 0) ) { 
1713                                                                         if ( sect
->size 
> offsetof(DATAdyld
, vars
) ) { 
1714                                                                                 // use ProgramVars from libdyld.dylib but tweak mh field to correct value 
1715                                                                                 dd
->vars
.mh 
= context
.mainExecutable
->machHeader(); 
1716                                                                                 context
.setNewProgramVars(dd
->vars
); 
1721                                                 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype 
== MH_EXECUTE
) ) { 
1722                                                         // this is a Mac OS X 10.6 or later main executable  
1723                                                         struct ProgramVars
* pv 
= (struct ProgramVars
*)(sect
->addr 
+ fSlide
); 
1724                                                         context
.setNewProgramVars(*pv
); 
1729                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1735 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const 
1737         ProgramVars vars 
= context
.programVars
; 
1738         const ImageLoader::Symbol
* sym
; 
1740         // get mach header directly 
1741         vars
.mh 
= (macho_header
*)fMachOData
; 
1744         sym 
= this->findExportedSymbol("_NXArgc", false, NULL
); 
1746                 vars
.NXArgcPtr 
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false); 
1749         sym 
= this->findExportedSymbol("_NXArgv", false, NULL
); 
1751                 vars
.NXArgvPtr 
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false); 
1754         sym 
= this->findExportedSymbol("_environ", false, NULL
); 
1756                 vars
.environPtr 
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false); 
1758         // lookup __progname 
1759         sym 
= this->findExportedSymbol("___progname", false, NULL
); 
1761                 vars
.__prognamePtr 
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false); 
1763         context
.setNewProgramVars(vars
); 
1767 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const 
1769         // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 
1770         if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache
) 
1771                 && this->usesTwoLevelNameSpace() 
1772                 && this->allDependentLibrariesAsWhenPreBound() ) { 
1773                 // allow environment variables to disable prebinding 
1774                 if ( context
.bindFlat 
) 
1776                 switch ( context
.prebindUsage 
) { 
1777                         case kUseAllPrebinding
: 
1779                         case kUseSplitSegPrebinding
: 
1780                                 return this->fIsSplitSeg
; 
1781                         case kUseAllButAppPredbinding
: 
1782                                 return (this != context
.mainExecutable
); 
1783                         case kUseNoPrebinding
: 
1791 void ImageLoaderMachO::doImageInit(const LinkContext
& context
) 
1793         if ( fHasDashInit 
) { 
1794                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1795                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1796                 const struct load_command
* cmd 
= cmds
; 
1797                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1799                                 case LC_ROUTINES_COMMAND
: 
1800                                         Initializer func 
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address 
+ fSlide
); 
1801                                         // <rdar://problem/8543820&9228031> verify initializers are in image 
1802                                         if ( ! this->containsAddress((void*)func
) ) { 
1803                                                 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath()); 
1805                                         if ( context
.verboseInit 
) 
1806                                                 dyld::log("dyld: calling -init function %p in %s\n", func
, this->getPath()); 
1807                                         func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
); 
1810                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1815 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
) 
1817         if ( fHasInitializers 
) { 
1818                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1819                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1820                 const struct load_command
* cmd 
= cmds
; 
1821                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1822                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1823                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1824                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1825                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1826                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1827                                         const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1828                                         if ( type 
== S_MOD_INIT_FUNC_POINTERS 
) { 
1829                                                 Initializer
* inits 
= (Initializer
*)(sect
->addr 
+ fSlide
); 
1830                                                 const size_t count 
= sect
->size 
/ sizeof(uintptr_t); 
1831                                                 for (size_t i
=0; i 
< count
; ++i
) { 
1832                                                         Initializer func 
= inits
[i
]; 
1833                                                         // <rdar://problem/8543820&9228031> verify initializers are in image 
1834                                                         if ( ! this->containsAddress((void*)func
) ) { 
1835                                                                 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath()); 
1837                                                         if ( context
.verboseInit 
) 
1838                                                                 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath()); 
1839                                                         func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
); 
1844                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1854 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
) 
1856         if ( fHasDOFSections 
) { 
1857                 // walk load commands (mapped in at start of __TEXT segment) 
1858                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1859                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1860                 const struct load_command
* cmd 
= cmds
; 
1861                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1863                                 case LC_SEGMENT_COMMAND
: 
1865                                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1866                                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1867                                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1868                                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1869                                                         if ( (sect
->flags 
& SECTION_TYPE
) == S_DTRACE_DOF 
) { 
1870                                                                 ImageLoader::DOFInfo info
; 
1871                                                                 info
.dof                        
= (void*)(sect
->addr 
+ fSlide
); 
1872                                                                 info
.imageHeader        
= this->machHeader(); 
1873                                                                 info
.imageShortName 
= this->getShortName(); 
1874                                                                 dofs
.push_back(info
); 
1880                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1886 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
) 
1888         CRSetCrashLogMessage2(this->getPath()); 
1890         // mach-o has -init and static initializers 
1891         doImageInit(context
); 
1892         doModInitFunctions(context
); 
1894         CRSetCrashLogMessage2(NULL
); 
1896         return (fHasDashInit 
|| fHasInitializers
); 
1899 bool ImageLoaderMachO::needsInitialization() 
1901         return ( fHasDashInit 
|| fHasInitializers 
); 
1905 bool ImageLoaderMachO::needsTermination() 
1907         return fHasTerminators
; 
1911 void ImageLoaderMachO::doTermination(const LinkContext
& context
) 
1913         if ( fHasTerminators 
) { 
1914                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1915                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1916                 const struct load_command
* cmd 
= cmds
; 
1917                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1918                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1919                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1920                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1921                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1922                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1923                                         const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
1924                                         if ( type 
== S_MOD_TERM_FUNC_POINTERS 
) { 
1925                                                 Terminator
* terms 
= (Terminator
*)(sect
->addr 
+ fSlide
); 
1926                                                 const size_t count 
= sect
->size 
/ sizeof(uintptr_t); 
1927                                                 for (size_t i
=count
; i 
> 0; --i
) { 
1928                                                         Terminator func 
= terms
[i
-1]; 
1929                                                         // <rdar://problem/8543820&9228031> verify terminators are in image 
1930                                                         if ( ! this->containsAddress((void*)func
) ) { 
1931                                                                 dyld::throwf("termination function %p not in mapped image for %s\n", func
, this->getPath()); 
1933                                                         if ( context
.verboseInit 
) 
1934                                                                 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath()); 
1940                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1946 void ImageLoaderMachO::printStatistics(unsigned int imageCount
, const InitializerTimingList
& timingInfo
) 
1948         ImageLoader::printStatistics(imageCount
, timingInfo
); 
1949         dyld::log("total symbol trie searches:    %d\n", fgSymbolTrieSearchs
); 
1950         dyld::log("total symbol table binary searches:    %d\n", fgSymbolTableBinarySearchs
); 
1951         dyld::log("total images defining weak symbols:  %u\n", fgImagesHasWeakDefinitions
); 
1952         dyld::log("total images using weak symbols:  %u\n", fgImagesRequiringCoalescing
); 
1956 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
) 
1958         // preflight and calculate slide if needed 
1959         const bool inPIE 
= (fgNextPIEDylibAddress 
!= 0); 
1961         if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) { 
1962                 bool needsToSlide 
= false; 
1963                 bool imageHasPreferredLoadAddress 
= segHasPreferredLoadAddress(0); 
1964                 uintptr_t lowAddr 
= (unsigned long)(-1); 
1965                 uintptr_t highAddr 
= 0; 
1966                 for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
1967                         const uintptr_t segLow 
= segPreferredLoadAddress(i
); 
1968                         const uintptr_t segHigh 
= dyld_page_round(segLow 
+ segSize(i
)); 
1969                         if ( segLow 
< highAddr 
) { 
1970                                 if ( dyld_page_size 
> 4096 ) 
1971                                         dyld::throwf("can't map segments into 16KB pages"); 
1973                                         dyld::throwf("overlapping segments"); 
1975                         if ( segLow 
< lowAddr 
) 
1977                         if ( segHigh 
> highAddr 
) 
1980                         if ( needsToSlide 
|| !imageHasPreferredLoadAddress 
|| inPIE 
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) ) 
1981                                 needsToSlide 
= true; 
1983                 if ( needsToSlide 
) { 
1984                         // find a chunk of address space to hold all segments 
1985                         uintptr_t addr 
= reserveAnAddressRange(highAddr
-lowAddr
, context
); 
1986                         slide 
= addr 
- lowAddr
; 
1989         else if ( ! this->segmentsCanSlide() ) { 
1990                 for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
1991                         if ( strcmp(segName(i
), "__PAGEZERO") == 0 ) 
1993                         if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) ) 
1994                                 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
)); 
1998                 throw "mach-o does not support independently sliding segments"; 
2004 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
) 
2006         vm_address_t addr 
= 0; 
2007         vm_size_t size 
= length
; 
2008         // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either 
2009         if ( fgNextPIEDylibAddress 
!= 0 ) { 
2010                  // add small (0-3 pages) random padding between dylibs 
2011                 addr 
= fgNextPIEDylibAddress 
+ (__stack_chk_guard
/fgNextPIEDylibAddress 
& (sizeof(long)-1))*dyld_page_size
; 
2012                 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard)); 
2013                 kern_return_t r 
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED 
| VM_MAKE_TAG(VM_MEMORY_DYLIB
)); 
2014                 if ( r 
== KERN_SUCCESS 
) { 
2015                         fgNextPIEDylibAddress 
= addr 
+ size
; 
2018                 fgNextPIEDylibAddress 
= 0; 
2020         kern_return_t r 
= vm_alloc(&addr
, size
, VM_FLAGS_ANYWHERE 
| VM_MAKE_TAG(VM_MEMORY_DYLIB
)); 
2021         if ( r 
!= KERN_SUCCESS 
)  
2022                 throw "out of address space"; 
2027 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
) 
2029         vm_address_t addr 
= start
; 
2030         vm_size_t size 
= length
; 
2031         kern_return_t r 
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED 
| VM_MAKE_TAG(VM_MEMORY_DYLIB
)); 
2032         if ( r 
!= KERN_SUCCESS 
)  
2039 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
) 
2041         // find address range for image 
2042         intptr_t slide 
= this->assignSegmentAddresses(context
); 
2043         if ( context
.verboseMapping 
) { 
2044                 if ( offsetInFat 
!= 0 ) 
2045                         dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat
); 
2047                         dyld::log("dyld: Mapping %s\n", this->getPath()); 
2049         // map in all segments 
2050         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2051                 vm_offset_t fileOffset 
= segFileOffset(i
) + offsetInFat
; 
2052                 vm_size_t size 
= segFileSize(i
); 
2053                 uintptr_t requestedLoadAddress 
= segPreferredLoadAddress(i
) + slide
; 
2055                 if ( !segUnaccessible(i
) ) { 
2056                         // If has text-relocs, don't set x-bit initially. 
2057                         // Instead set it later after text-relocs have been done. 
2058                         if ( segExecutable(i
) && !(segHasRebaseFixUps(i
) && (slide 
!= 0)) ) 
2059                                 protection   
|= PROT_EXEC
; 
2060                         if ( segReadable(i
) ) 
2061                                 protection   
|= PROT_READ
; 
2062                         if ( segWriteable(i
) ) 
2063                                 protection   
|= PROT_WRITE
; 
2066                 // initially map __IMPORT segments R/W so dyld can update them 
2067                 if ( segIsReadOnlyImport(i
) ) 
2068                         protection 
|= PROT_WRITE
; 
2070                 // wholly zero-fill segments have nothing to mmap() in 
2072                         if ( (fileOffset
+size
) > fileLen 
) { 
2073                                 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",  
2074                                                                 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
); 
2076                         void* loadAddress 
= xmmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED 
| MAP_PRIVATE
, fd
, fileOffset
); 
2077                         if ( loadAddress 
== ((void*)(-1)) ) { 
2078                                 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",  
2079                                         errno
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath()); 
2083                 ++ImageLoader::fgTotalSegmentsMapped
; 
2084                 ImageLoader::fgTotalBytesMapped 
+= size
; 
2085                 if ( context
.verboseMapping 
) 
2086                         dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1, 
2087                                 (protection 
& PROT_READ
) ? 'r' : '.',  (protection 
& PROT_WRITE
) ? 'w' : '.',  (protection 
& PROT_EXEC
) ? 'x' : '.' ); 
2090         // update slide to reflect load location                         
2091         this->setSlide(slide
); 
2094 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
) 
2096         // find address range for image 
2097         intptr_t slide 
= this->assignSegmentAddresses(context
); 
2098         if ( context
.verboseMapping 
) 
2099                 dyld::log("dyld: Mapping memory %p\n", memoryImage
); 
2100         // map in all segments 
2101         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2102                 vm_address_t loadAddress 
= segPreferredLoadAddress(i
) + slide
; 
2103                 vm_address_t srcAddr 
= (uintptr_t)memoryImage 
+ segFileOffset(i
); 
2104                 vm_size_t size 
= segFileSize(i
); 
2105                 kern_return_t r 
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
); 
2106                 if ( r 
!= KERN_SUCCESS 
)  
2107                         throw "can't map segment"; 
2108                 if ( context
.verboseMapping 
) 
2109                         dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1); 
2111         // update slide to reflect load location                         
2112         this->setSlide(slide
); 
2113         // set R/W permissions on all segments at slide location 
2114         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2115                 segProtect(i
, context
);          
2120 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
) 
2122         vm_prot_t protection 
= 0; 
2123         if ( !segUnaccessible(segIndex
) ) { 
2124                 if ( segExecutable(segIndex
) ) 
2125                         protection   
|= PROT_EXEC
; 
2126                 if ( segReadable(segIndex
) ) 
2127                         protection   
|= PROT_READ
; 
2128                 if ( segWriteable(segIndex
) ) 
2129                         protection   
|= PROT_WRITE
; 
2131         vm_address_t addr 
= segActualLoadAddress(segIndex
); 
2132         vm_size_t size 
= segSize(segIndex
); 
2133         const bool setCurrentPermissions 
= false; 
2134         kern_return_t r 
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
); 
2135         if ( r 
!= KERN_SUCCESS 
) { 
2136         dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s", 
2137             (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath()); 
2139         if ( context
.verboseMapping 
) { 
2140                 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex
), (uintptr_t)addr
, (uintptr_t)addr
+size
-1, 
2141                         (protection 
& PROT_READ
) ? 'r' : '.',  (protection 
& PROT_WRITE
) ? 'w' : '.',  (protection 
& PROT_EXEC
) ? 'x' : '.' ); 
2145 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
) 
2147         vm_address_t addr 
= segActualLoadAddress(segIndex
); 
2148         vm_size_t size 
= segSize(segIndex
); 
2149         const bool setCurrentPermissions 
= false; 
2150         vm_prot_t protection 
= VM_PROT_WRITE 
| VM_PROT_READ
; 
2151         if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) ) 
2152                 protection 
|= VM_PROT_EXECUTE
; 
2153         kern_return_t r 
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
); 
2154         if ( r 
!= KERN_SUCCESS 
) { 
2155         dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s", 
2156             (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath()); 
2158         if ( context
.verboseMapping 
) { 
2159                 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex
), (uintptr_t)addr
, (uintptr_t)addr
+size
-1, 
2160                         (protection 
& PROT_READ
) ? 'r' : '.',  (protection 
& PROT_WRITE
) ? 'w' : '.',  (protection 
& PROT_EXEC
) ? 'x' : '.' );