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 <mach-o/dyld_images.h> 
  43 #include <sys/sysctl.h> 
  44 #include <sys/syscall.h> 
  45 #include <libkern/OSAtomic.h> 
  46 #include <libkern/OSCacheControl.h> 
  48 #include <System/sys/codesign.h> 
  50 #if __has_feature(ptrauth_calls) 
  54 #include "ImageLoaderMachO.h" 
  55 #include "ImageLoaderMachOCompressed.h" 
  56 #if SUPPORT_CLASSIC_MACHO 
  57 #include "ImageLoaderMachOClassic.h" 
  62 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs 
  63 extern "C" long __stack_chk_guard
; 
  65 #define LIBSYSTEM_DYLIB_PATH                      "/usr/lib/libSystem.B.dylib" 
  66 #define LIBDYLD_DYLIB_PATH                        "/usr/lib/system/libdyld.dylib" 
  68   #define DRIVERKIT_LIBSYSTEM_DYLIB_PATH  "/System/DriverKit/usr/lib/libSystem.dylib" 
  69   #define DRIVERKIT_LIBDYLD_DYLIB_PATH    "/System/DriverKit/usr/lib/system/libdyld.dylib" 
  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; 
  92 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,  
  93                                                                                                                                 uint32_t segOffsets
[], unsigned int libCount
) 
  94  : ImageLoader(path
, libCount
), fCoveredCodeLength(0), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0), 
  95         fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),  
  96 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false), 
  97 #if TEXT_RELOC_SUPPORT 
  98         fTextSegmentRebases(false), 
  99         fTextSegmentBinds(false), 
 101     fReadOnlyDataSegment(false), 
 104         fReadOnlyImportSegment(false), 
 106         fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false), 
 107         fHasInitializers(false), fHasTerminators(false), fNotifyObjC(false), fRetainForObjC(false), fRegisteredAsRequiresCoalescing(false), fOverrideOfCacheImageNum(0) 
 109         fIsSplitSeg 
= ((mh
->flags 
& MH_SPLIT_SEGS
) != 0);         
 111         // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put  
 112         // each SegmentMachO object in array at end of ImageLoaderMachO object 
 113         const uint32_t cmd_count 
= mh
->ncmds
; 
 114         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 115         const struct load_command
* cmd 
= cmds
; 
 116         for (uint32_t i 
= 0, segIndex
=0; i 
< cmd_count
; ++i
) { 
 117                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 118                         const struct macho_segment_command
* segCmd 
= (struct macho_segment_command
*)cmd
; 
 119                         // ignore zero-sized segments 
 120                         if ( segCmd
->vmsize 
!= 0 ) { 
 121                                 // record offset of load command 
 122                                 segOffsets
[segIndex
++] = (uint32_t)((uint8_t*)segCmd 
- fMachOData
); 
 125                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 131 static uintptr_t pageAlign(uintptr_t value
) 
 133         return (value 
+ 4095) & (-4096); 
 137 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has 
 138 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool inCache
, bool* compressed
, 
 139                                                                                         unsigned int* segCount
, unsigned int* libCount
, const LinkContext
& context
, 
 140                                                                                         const linkedit_data_command
** codeSigCmd
, 
 141                                                                                         const encryption_info_command
** encryptCmd
) 
 149         const uint32_t cmd_count 
= mh
->ncmds
; 
 150         const uint32_t sizeofcmds 
= mh
->sizeofcmds
; 
 151         if ( cmd_count 
> (sizeofcmds
/sizeof(load_command
)) ) 
 152                 dyld::throwf("malformed mach-o: ncmds (%u) too large to fit in sizeofcmds (%u)", cmd_count
, sizeofcmds
); 
 153         const struct load_command
* const startCmds 
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
)); 
 154         const struct load_command
* const endCmds 
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + sizeofcmds
); 
 155         const struct load_command
* cmd 
= startCmds
; 
 156         bool foundLoadCommandSegment 
= false; 
 157         const macho_segment_command
* linkeditSegCmd 
= NULL
; 
 158         const macho_segment_command
* startOfFileSegCmd 
= NULL
; 
 159         const dyld_info_command
* dyldInfoCmd 
= NULL
; 
 160         const linkedit_data_command
* chainedFixupsCmd 
= NULL
; 
 161         const linkedit_data_command
* exportsTrieCmd 
= NULL
; 
 162         const symtab_command
* symTabCmd 
= NULL
; 
 163         const dysymtab_command
* dynSymbTabCmd 
= NULL
; 
 164         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 165                 uint32_t cmdLength 
= cmd
->cmdsize
; 
 166                 const macho_segment_command
* segCmd
; 
 167                 const dylib_command
* dylibCmd
; 
 168                 if ( cmdLength 
< 8 ) { 
 169                         dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s", 
 172                 const struct load_command
* const nextCmd 
= (const struct load_command
*)(((char*)cmd
)+cmdLength
); 
 173                 if ( (nextCmd 
> endCmds
) || (nextCmd 
< cmd
) ) { 
 174                         dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s", 
 175                                                                                            i
, cmdLength
, mh
->sizeofcmds
, path
); 
 179                         case LC_DYLD_INFO_ONLY
: 
 180                                 if ( cmd
->cmdsize 
!= sizeof(dyld_info_command
) ) 
 181                                         throw "malformed mach-o image: LC_DYLD_INFO size wrong"; 
 182                                 dyldInfoCmd 
= (struct dyld_info_command
*)cmd
; 
 185                         case LC_DYLD_CHAINED_FIXUPS
: 
 186                                 if ( cmd
->cmdsize 
!= sizeof(linkedit_data_command
) ) 
 187                                         throw "malformed mach-o image: LC_DYLD_CHAINED_FIXUPS size wrong"; 
 188                                 chainedFixupsCmd 
= (struct linkedit_data_command
*)cmd
; 
 191                         case LC_DYLD_EXPORTS_TRIE
: 
 192                                 if ( cmd
->cmdsize 
!= sizeof(linkedit_data_command
) ) 
 193                                         throw "malformed mach-o image: LC_DYLD_EXPORTS_TRIE size wrong"; 
 194                                 exportsTrieCmd 
= (struct linkedit_data_command
*)cmd
; 
 196                         case LC_SEGMENT_COMMAND
: 
 197                                 segCmd 
= (struct macho_segment_command
*)cmd
; 
 199                                 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS) 
 200                                 if ( ((segCmd
->filesize
) > pageAlign(segCmd
->vmsize
)) && (segCmd
->vmsize 
!= 0) ) 
 202                                 // <rdar://problem/19986776> dyld should support non-allocatable __LLVM segment 
 203                                 if ( (segCmd
->filesize 
> segCmd
->vmsize
) && ((segCmd
->vmsize 
!= 0) || ((segCmd
->flags 
& SG_NORELOC
) == 0)) ) 
 205                                     dyld::throwf("malformed mach-o image: segment load command %s filesize (0x%0lX) is larger than vmsize (0x%0lX)", segCmd
->segname
, (long)segCmd
->filesize 
, (long)segCmd
->vmsize 
); 
 206                                 if ( cmd
->cmdsize 
< sizeof(macho_segment_command
) ) 
 207                                         throw "malformed mach-o image: LC_SEGMENT size too small"; 
 208                                 if ( cmd
->cmdsize 
!= (sizeof(macho_segment_command
) + segCmd
->nsects 
* sizeof(macho_section
)) ) 
 209                                         throw "malformed mach-o image: LC_SEGMENT size wrong for number of sections"; 
 210                                 // ignore zero-sized segments 
 211                                 if ( segCmd
->vmsize 
!= 0 ) 
 213                                 if ( strcmp(segCmd
->segname
, "__LINKEDIT") == 0 ) { 
 214                 #if TARGET_OS_SIMULATOR 
 215                                         // Note: should check on all platforms that __LINKEDIT is read-only, but <rdar://problem/22637626&22525618> 
 216                                         if ( segCmd
->initprot 
!= VM_PROT_READ 
) 
 217                                                 throw "malformed mach-o image: __LINKEDIT segment does not have read-only permissions"; 
 219                                         if ( segCmd
->fileoff 
==  0 ) 
 220                                                 throw "malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header"; 
 221                                         if ( linkeditSegCmd 
!= NULL 
) 
 222                                                 throw "malformed mach-o image: multiple __LINKEDIT segments"; 
 223                                         linkeditSegCmd 
= segCmd
; 
 226                                         if ( segCmd
->initprot 
& 0xFFFFFFF8 ) 
 227                                                 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in initprot", segCmd
->segname
, segCmd
->initprot
); 
 228                                         if ( segCmd
->maxprot 
& 0xFFFFFFF8 ) 
 229                                                 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in maxprot", segCmd
->segname
, segCmd
->maxprot
); 
 230                                         if ( (segCmd
->initprot 
!= 0) && ((segCmd
->initprot 
& VM_PROT_READ
) == 0) ) 
 231                                                 dyld::throwf("malformed mach-o image: %s segment is not mapped readable", segCmd
->segname
); 
 233                 if ( (segCmd
->fileoff 
== 0) && (segCmd
->filesize 
!= 0) ) { 
 234                                         if ( (segCmd
->initprot 
& VM_PROT_READ
) == 0 ) 
 235                                                 dyld::throwf("malformed mach-o image: %s segment maps start of file but is not readable", segCmd
->segname
); 
 236                                         if ( (segCmd
->initprot 
& VM_PROT_WRITE
) == VM_PROT_WRITE 
) { 
 237                                                 if ( context
.strictMachORequired 
) 
 238                                                         dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd
->segname
); 
 240                                         if ( segCmd
->filesize 
< (sizeof(macho_header
) + mh
->sizeofcmds
) ) 
 241                                                 dyld::throwf("malformed mach-o image: %s segment does not map all of load commands", segCmd
->segname
); 
 242                                         if ( startOfFileSegCmd 
!= NULL 
) 
 243                                                 dyld::throwf("malformed mach-o image: multiple segments map start of file: %s %s", startOfFileSegCmd
->segname
, segCmd
->segname
); 
 244                                         startOfFileSegCmd 
= segCmd
; 
 246                                 if ( context
.strictMachORequired 
) { 
 247                                         uintptr_t vmStart   
= segCmd
->vmaddr
; 
 248                                         uintptr_t vmSize    
= segCmd
->vmsize
; 
 249                                         uintptr_t vmEnd     
= vmStart 
+ vmSize
; 
 250                                         uintptr_t fileStart 
= segCmd
->fileoff
; 
 251                                         uintptr_t fileSize  
= segCmd
->filesize
; 
 252                                         if ( (intptr_t)(vmSize
) < 0 ) 
 253                                                 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large in %s", segCmd
->segname
, path
); 
 254                                         if ( vmStart 
> vmEnd 
) 
 255                                                 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd
->segname
); 
 256                                         if ( vmSize 
!= fileSize 
) { 
 257                                                 if ( segCmd
->initprot 
== 0 ) { 
 258                                                         // allow: fileSize == 0 && initprot == 0                e.g. __PAGEZERO 
 259                                                         // allow: vmSize == 0 && initprot == 0                  e.g. __LLVM 
 260                                                         if ( (fileSize 
!= 0) && (vmSize 
!= 0) ) 
 261                                                                 dyld::throwf("malformed mach-o image: unaccessable segment %s has non-zero filesize and vmsize", segCmd
->segname
); 
 264                                                         // allow: vmSize > fileSize && initprot != X  e.g. __DATA 
 265                                                         if ( vmSize 
< fileSize 
) { 
 266                                                                 dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd
->segname
); 
 268                                                         if ( segCmd
->initprot 
& VM_PROT_EXECUTE 
) { 
 269                                                                 dyld::throwf("malformed mach-o image: segment %s has vmsize != filesize and is executable", segCmd
->segname
); 
 274                                                 if ( (fileSize 
!= 0) && (segCmd
->initprot 
== (VM_PROT_READ 
| VM_PROT_EXECUTE
)) ) { 
 275                                                         if ( foundLoadCommandSegment 
) 
 276                                                                 throw "load commands in multiple segments"; 
 277                                                         foundLoadCommandSegment 
= true; 
 280                                         else if ( (fileStart 
< mh
->sizeofcmds
) && (fileSize 
!= 0) ) { 
 281                                                 // <rdar://problem/7942521> all load commands must be in an executable segment 
 282                                                 if ( (fileStart 
!= 0) || (fileSize 
< (mh
->sizeofcmds
+sizeof(macho_header
))) ) 
 283                                                         dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd
->segname
);  
 284                                                 if ( segCmd
->initprot 
!= (VM_PROT_READ 
| VM_PROT_EXECUTE
) )  
 285                                                         dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd
->segname
);  
 286                                                 if ( foundLoadCommandSegment 
) 
 287                                                         throw "load commands in multiple segments"; 
 288                                                 foundLoadCommandSegment 
= true; 
 291                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)segCmd 
+ sizeof(struct macho_segment_command
)); 
 292                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[segCmd
->nsects
]; 
 293                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 294                                                 if (!inCache 
&& sect
->offset 
!= 0 && ((sect
->offset 
+ sect
->size
) > (segCmd
->fileoff 
+ segCmd
->filesize
))) 
 295                                                         dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect
->segname
, sect
->sectname
, path
, segCmd
->segname
); 
 299                         case LC_SEGMENT_COMMAND_WRONG
: 
 300                                 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");  
 303                         case LC_LOAD_WEAK_DYLIB
: 
 304                         case LC_REEXPORT_DYLIB
: 
 305                         case LC_LOAD_UPWARD_DYLIB
: 
 308                                 [[clang::fallthrough]]; 
 310                                 dylibCmd 
= (dylib_command
*)cmd
; 
 311                                 if ( dylibCmd
->dylib
.name
.offset 
> cmdLength 
) 
 312                                         dyld::throwf("malformed mach-o image: dylib load command #%d has offset (%u) outside its size (%u)", i
, dylibCmd
->dylib
.name
.offset
, cmdLength
); 
 313                                 if ( (dylibCmd
->dylib
.name
.offset 
+ strlen((char*)dylibCmd 
+ dylibCmd
->dylib
.name
.offset
) + 1) > cmdLength 
) 
 314                                         dyld::throwf("malformed mach-o image: dylib load command #%d string extends beyond end of load command", i
); 
 316                         case LC_CODE_SIGNATURE
: 
 317                                 if ( cmd
->cmdsize 
!= sizeof(linkedit_data_command
) ) 
 318                                         throw "malformed mach-o image: LC_CODE_SIGNATURE size wrong"; 
 319                                 // <rdar://problem/22799652> only support one LC_CODE_SIGNATURE per image 
 320                                 if ( *codeSigCmd 
!= NULL 
) 
 321                                         throw "malformed mach-o image: multiple LC_CODE_SIGNATURE load commands"; 
 322                                 *codeSigCmd 
= (struct linkedit_data_command
*)cmd
; 
 324                         case LC_ENCRYPTION_INFO
: 
 325                                 if ( cmd
->cmdsize 
!= sizeof(encryption_info_command
) ) 
 326                                         throw "malformed mach-o image: LC_ENCRYPTION_INFO size wrong"; 
 327                                 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO per image 
 328                                 if ( *encryptCmd 
!= NULL 
) 
 329                                         throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO load commands"; 
 330                                 *encryptCmd 
= (encryption_info_command
*)cmd
; 
 332                         case LC_ENCRYPTION_INFO_64
: 
 333                                 if ( cmd
->cmdsize 
!= sizeof(encryption_info_command_64
) ) 
 334                                         throw "malformed mach-o image: LC_ENCRYPTION_INFO_64 size wrong"; 
 335                                 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO_64 per image 
 336                                 if ( *encryptCmd 
!= NULL 
) 
 337                                         throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO_64 load commands"; 
 338                                 *encryptCmd 
= (encryption_info_command
*)cmd
; 
 341                                 if ( cmd
->cmdsize 
!= sizeof(symtab_command
) ) 
 342                                         throw "malformed mach-o image: LC_SYMTAB size wrong"; 
 343                                 symTabCmd 
= (symtab_command
*)cmd
; 
 346                                 if ( cmd
->cmdsize 
!= sizeof(dysymtab_command
) ) 
 347                                         throw "malformed mach-o image: LC_DYSYMTAB size wrong"; 
 348                                 dynSymbTabCmd 
= (dysymtab_command
*)cmd
; 
 351                         // <rdar://problem/26797345> error when loading iOS Simulator mach-o binary into macOS process 
 352                         case LC_VERSION_MIN_WATCHOS
: 
 353                         case LC_VERSION_MIN_TVOS
: 
 354                         case LC_VERSION_MIN_IPHONEOS
: 
 355                                 if ( !context
.iOSonMac 
) 
 356                                         throw "mach-o, but built for simulator (not macOS)"; 
 363         if ( context
.strictMachORequired 
&& !foundLoadCommandSegment 
) 
 364                 throw "load commands not in a segment"; 
 365         if ( linkeditSegCmd 
== NULL 
) 
 366                 throw "malformed mach-o image: missing __LINKEDIT segment"; 
 367         if ( !inCache 
&& (startOfFileSegCmd 
== NULL
) ) 
 368                 throw "malformed mach-o image: missing __TEXT segment that maps start of file"; 
 369         // <rdar://problem/13145644> verify every segment does not overlap another segment 
 370         if ( context
.strictMachORequired 
) { 
 371                 uintptr_t lastFileStart 
= 0; 
 372                 uintptr_t linkeditFileStart 
= 0; 
 373                 const struct load_command
* cmd1 
= startCmds
; 
 374                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 375                         if ( cmd1
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 376                                 struct macho_segment_command
* segCmd1 
= (struct macho_segment_command
*)cmd1
; 
 377                                 uintptr_t vmStart1   
= segCmd1
->vmaddr
; 
 378                                 uintptr_t vmEnd1     
= segCmd1
->vmaddr 
+ segCmd1
->vmsize
; 
 379                                 uintptr_t fileStart1 
= segCmd1
->fileoff
; 
 380                                 uintptr_t fileEnd1   
= segCmd1
->fileoff 
+ segCmd1
->filesize
; 
 382                                 if (fileStart1 
> lastFileStart
) 
 383                                         lastFileStart 
= fileStart1
; 
 385                                 if ( strcmp(&segCmd1
->segname
[0], "__LINKEDIT") == 0 ) { 
 386                                         linkeditFileStart 
= fileStart1
; 
 389                                 const struct load_command
* cmd2 
= startCmds
; 
 390                                 for (uint32_t j 
= 0; j 
< cmd_count
; ++j
) { 
 393                                         if ( cmd2
->cmd 
== LC_SEGMENT_COMMAND 
) { 
 394                                                 struct macho_segment_command
* segCmd2 
= (struct macho_segment_command
*)cmd2
; 
 395                                                 uintptr_t vmStart2   
= segCmd2
->vmaddr
; 
 396                                                 uintptr_t vmEnd2     
= segCmd2
->vmaddr 
+ segCmd2
->vmsize
; 
 397                                                 uintptr_t fileStart2 
= segCmd2
->fileoff
; 
 398                                                 uintptr_t fileEnd2   
= segCmd2
->fileoff 
+ segCmd2
->filesize
; 
 399                                                 if ( ((vmStart2 
<= vmStart1
) && (vmEnd2 
> vmStart1
) && (vmEnd1 
> vmStart1
))  
 400                                                 || ((vmStart2 
>= vmStart1
) && (vmStart2 
< vmEnd1
) && (vmEnd2 
> vmStart2
)) ) 
 401                                                         dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
); 
 402                                                 if ( ((fileStart2 
<= fileStart1
) && (fileEnd2 
> fileStart1
) && (fileEnd1 
> fileStart1
)) 
 403                                                   || ((fileStart2 
>= fileStart1
) && (fileStart2 
< fileEnd1
) && (fileEnd2 
> fileStart2
)) ) 
 404                                                         dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);  
 406                                         cmd2 
= (const struct load_command
*)(((char*)cmd2
)+cmd2
->cmdsize
); 
 409                         cmd1 
= (const struct load_command
*)(((char*)cmd1
)+cmd1
->cmdsize
); 
 412                 if (lastFileStart 
!= linkeditFileStart
) 
 413                         dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment"); 
 416         // validate linkedit content 
 417         if  ( (dyldInfoCmd 
== NULL
) && (chainedFixupsCmd 
== NULL
) && (symTabCmd 
== NULL
) ) 
 418                 throw "malformed mach-o image: missing LC_SYMTAB, LC_DYLD_INFO, or LC_DYLD_CHAINED_FIXUPS"; 
 419         if  ( dynSymbTabCmd 
== NULL 
) 
 420                 throw "malformed mach-o image: missing LC_DYSYMTAB"; 
 422         uint32_t  linkeditFileOffsetStart 
= (uint32_t)linkeditSegCmd
->fileoff
; 
 423         uint32_t  linkeditFileOffsetEnd 
= (uint32_t)linkeditSegCmd
->fileoff 
+ (uint32_t)linkeditSegCmd
->filesize
; 
 425         if ( !inCache 
&& (dyldInfoCmd 
!= NULL
) && context
.strictMachORequired 
) { 
 426                 // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap 
 427                 uint32_t offset 
= linkeditFileOffsetStart
; 
 428                 if ( dyldInfoCmd
->rebase_size 
!= 0 ) { 
 429                         if ( dyldInfoCmd
->rebase_size 
& 0x80000000 ) 
 430                                 throw "malformed mach-o image: dyld rebase info size overflow"; 
 431                         if ( dyldInfoCmd
->rebase_off 
< offset 
) 
 432                                 throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT"; 
 433                         offset 
= dyldInfoCmd
->rebase_off 
+ dyldInfoCmd
->rebase_size
; 
 434                         if ( offset 
> linkeditFileOffsetEnd 
) 
 435                                 throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT"; 
 437                 if ( dyldInfoCmd
->bind_size 
!= 0 ) { 
 438                         if ( dyldInfoCmd
->bind_size 
& 0x80000000 ) 
 439                                 throw "malformed mach-o image: dyld bind info size overflow"; 
 440                         if ( dyldInfoCmd
->bind_off 
< offset 
) 
 441                                 throw "malformed mach-o image: dyld bind info overlaps rebase info"; 
 442                         offset 
= dyldInfoCmd
->bind_off 
+ dyldInfoCmd
->bind_size
; 
 443                         if ( offset 
> linkeditFileOffsetEnd 
) 
 444                                 throw "malformed mach-o image: dyld bind info overruns __LINKEDIT"; 
 446                 if ( dyldInfoCmd
->weak_bind_size 
!= 0 ) { 
 447                         if ( dyldInfoCmd
->weak_bind_size 
& 0x80000000 ) 
 448                                 throw "malformed mach-o image: dyld weak bind info size overflow"; 
 449                         if ( dyldInfoCmd
->weak_bind_off 
< offset 
) 
 450                                 throw "malformed mach-o image: dyld weak bind info overlaps bind info"; 
 451                         offset 
= dyldInfoCmd
->weak_bind_off 
+ dyldInfoCmd
->weak_bind_size
; 
 452                         if ( offset 
> linkeditFileOffsetEnd 
) 
 453                                 throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT"; 
 455                 if ( dyldInfoCmd
->lazy_bind_size 
!= 0 ) { 
 456                         if ( dyldInfoCmd
->lazy_bind_size 
& 0x80000000 ) 
 457                                 throw "malformed mach-o image: dyld lazy bind info size overflow"; 
 458                         if ( dyldInfoCmd
->lazy_bind_off 
< offset 
) 
 459                                 throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info"; 
 460                         offset 
= dyldInfoCmd
->lazy_bind_off 
+ dyldInfoCmd
->lazy_bind_size
; 
 461                         if ( offset 
> linkeditFileOffsetEnd 
) 
 462                                 throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT"; 
 464                 if ( dyldInfoCmd
->export_size 
!= 0 ) { 
 465                         if ( dyldInfoCmd
->export_size 
& 0x80000000 ) 
 466                                 throw "malformed mach-o image: dyld export info size overflow"; 
 467                         if ( dyldInfoCmd
->export_off 
< offset 
) 
 468                                 throw "malformed mach-o image: dyld export info overlaps lazy bind info"; 
 469                         offset 
= dyldInfoCmd
->export_off 
+ dyldInfoCmd
->export_size
; 
 470                         if ( offset 
> linkeditFileOffsetEnd 
) 
 471                                 throw "malformed mach-o image: dyld export info overruns __LINKEDIT"; 
 475         if ( !inCache 
&& (chainedFixupsCmd 
!= NULL
) && context
.strictMachORequired 
) { 
 476                 // validate all LC_DYLD_CHAINED_FIXUPS chunks fit in LINKEDIT and don't overlap 
 477                 if ( chainedFixupsCmd
->dataoff 
< linkeditFileOffsetStart 
) 
 478                         throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT"; 
 479                 if ( (chainedFixupsCmd
->dataoff 
+ chainedFixupsCmd
->datasize
) > linkeditFileOffsetEnd 
) 
 480                         throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT"; 
 483         if ( !inCache 
&& (exportsTrieCmd 
!= NULL
) && context
.strictMachORequired 
) { 
 484                 // validate all LC_DYLD_EXPORTS_TRIE chunks fit in LINKEDIT and don't overlap 
 485                 if ( exportsTrieCmd
->dataoff 
< linkeditFileOffsetStart 
) 
 486                         throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT"; 
 487                 if ( (exportsTrieCmd
->dataoff 
+ exportsTrieCmd
->datasize
) > linkeditFileOffsetEnd 
) 
 488                         throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT"; 
 491         if ( symTabCmd 
!= NULL 
) { 
 492                 // validate symbol table fits in LINKEDIT 
 493                 if ( (symTabCmd
->nsyms 
> 0) && (symTabCmd
->symoff 
< linkeditFileOffsetStart
) ) 
 494                         throw "malformed mach-o image: symbol table underruns __LINKEDIT"; 
 495                 if ( symTabCmd
->nsyms 
> 0x10000000 ) 
 496                         throw "malformed mach-o image: symbol table too large"; 
 497                 uint32_t symbolsSize 
= symTabCmd
->nsyms 
* sizeof(macho_nlist
); 
 498                 if ( symbolsSize 
> linkeditSegCmd
->filesize 
) 
 499                         throw "malformed mach-o image: symbol table overruns __LINKEDIT"; 
 500                 if ( symTabCmd
->symoff 
+ symbolsSize 
< symTabCmd
->symoff 
) 
 501                         throw "malformed mach-o image: symbol table size wraps"; 
 502                 if ( symTabCmd
->symoff 
+ symbolsSize 
> symTabCmd
->stroff 
) 
 503                         throw "malformed mach-o image: symbol table overlaps symbol strings"; 
 504                 if ( symTabCmd
->stroff 
+ symTabCmd
->strsize 
< symTabCmd
->stroff 
) 
 505                         throw "malformed mach-o image: symbol string size wraps"; 
 506                 if ( symTabCmd
->stroff 
+ symTabCmd
->strsize 
> linkeditFileOffsetEnd 
) { 
 507                         // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page 
 508                         if ( context
.strictMachORequired 
|| (symTabCmd
->stroff 
+ symTabCmd
->strsize 
> ((linkeditFileOffsetEnd 
+ 4095) & (-4096))) ) 
 509                                 throw "malformed mach-o image: symbol strings overrun __LINKEDIT"; 
 512                 if ( (symTabCmd
->symoff 
% sizeof(void*)) != 0 ) { 
 513                         // <rdar://53723577> allow old malformed plugins in new app 
 514                         if ( sdkVersion((mach_header
*)mh
) >= DYLD_PACKED_VERSION(10,15,0) ) 
 515                                 throw "malformed mach-o image: mis-aligned symbol table __LINKEDIT"; 
 518                 // validate indirect symbol table 
 519                 if ( dynSymbTabCmd
->nindirectsyms 
!= 0 ) { 
 520                         if ( dynSymbTabCmd
->indirectsymoff 
< linkeditFileOffsetStart 
) 
 521                                 throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT"; 
 522                         if ( dynSymbTabCmd
->nindirectsyms 
> 0x10000000 ) 
 523                                 throw "malformed mach-o image: indirect symbol table too large"; 
 524                         uint32_t indirectTableSize 
= dynSymbTabCmd
->nindirectsyms 
* sizeof(uint32_t); 
 525                         if ( indirectTableSize 
> linkeditSegCmd
->filesize 
) 
 526                                 throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT"; 
 527                         if ( dynSymbTabCmd
->indirectsymoff 
+ indirectTableSize 
< dynSymbTabCmd
->indirectsymoff 
) 
 528                                 throw "malformed mach-o image: indirect symbol table size wraps"; 
 529                         if ( context
.strictMachORequired 
&& (dynSymbTabCmd
->indirectsymoff 
+ indirectTableSize 
> symTabCmd
->stroff
)  ) 
 530                                 throw "malformed mach-o image: indirect symbol table overruns string pool"; 
 532                 if ( (dynSymbTabCmd
->nlocalsym 
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->ilocalsym 
> symTabCmd
->nsyms
) ) 
 533                         throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols"; 
 534                 if ( dynSymbTabCmd
->ilocalsym 
+ dynSymbTabCmd
->nlocalsym 
< dynSymbTabCmd
->ilocalsym  
) 
 535                         throw "malformed mach-o image: indirect symbol table local symbol count wraps"; 
 536                 if ( (dynSymbTabCmd
->nextdefsym 
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->iextdefsym 
> symTabCmd
->nsyms
) ) 
 537                         throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols"; 
 538                 if ( dynSymbTabCmd
->iextdefsym 
+ dynSymbTabCmd
->nextdefsym 
< dynSymbTabCmd
->iextdefsym  
) 
 539                         throw "malformed mach-o image: indirect symbol table extern symbol count wraps"; 
 540                 if ( (dynSymbTabCmd
->nundefsym 
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->iundefsym 
> symTabCmd
->nsyms
) ) 
 541                         throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols"; 
 542                 if ( dynSymbTabCmd
->iundefsym 
+ dynSymbTabCmd
->nundefsym 
< dynSymbTabCmd
->iundefsym  
) 
 543                         throw "malformed mach-o image: indirect symbol table undefined symbol count wraps"; 
 547         // fSegmentsArrayCount is only 8-bits 
 548         if ( *segCount 
> 255 ) 
 549                 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
); 
 551         // fSegmentsArrayCount is only 8-bits 
 552         if ( *libCount 
> 4095 ) 
 553                 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
); 
 555         if ( needsAddedLibSystemDepency(*libCount
, mh
) ) 
 558         // dylibs that use LC_DYLD_CHAINED_FIXUPS have that load command removed when put in the dyld cache 
 559         if ( !*compressed 
&& (mh
->flags 
& MH_DYLIB_IN_CACHE
) ) 
 565 // create image for main executable 
 566 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
) 
 568         //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n", 
 569         //      sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed)); 
 571         unsigned int segCount
; 
 572         unsigned int libCount
; 
 573         const linkedit_data_command
* codeSigCmd
; 
 574         const encryption_info_command
* encryptCmd
; 
 575         sniffLoadCommands(mh
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
); 
 576         // instantiate concrete class based on content of load commands 
 578                 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
); 
 580 #if SUPPORT_CLASSIC_MACHO 
 581                 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
); 
 583                 throw "missing LC_DYLD_INFO load command"; 
 588 // create image by mapping in a mach-o file 
 589 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPages
[], size_t firstPagesSize
, uint64_t offsetInFat
, 
 590                                                                         uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
) 
 593         unsigned int segCount
; 
 594         unsigned int libCount
; 
 595         const linkedit_data_command
* codeSigCmd
; 
 596         const encryption_info_command
* encryptCmd
; 
 597         sniffLoadCommands((const macho_header
*)firstPages
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
); 
 598         // instantiate concrete class based on content of load commands 
 600                 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, firstPages
, firstPagesSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, encryptCmd
, context
); 
 602 #if SUPPORT_CLASSIC_MACHO 
 603                 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, firstPages
, firstPagesSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
); 
 605                 throw "missing LC_DYLD_INFO load command"; 
 609 // create image by using cached mach-o file 
 610 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
) 
 612         // instantiate right concrete class 
 614         unsigned int segCount
; 
 615         unsigned int libCount
; 
 616         const linkedit_data_command
* codeSigCmd
; 
 617         const encryption_info_command
* encryptCmd
; 
 618         sniffLoadCommands(mh
, path
, true, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
); 
 619         // instantiate concrete class based on content of load commands 
 621                 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
); 
 623 #if SUPPORT_CLASSIC_MACHO 
 624                 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
); 
 626                 throw "missing LC_DYLD_INFO load command"; 
 630 // create image by copying an in-memory mach-o file 
 631 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
) 
 634         unsigned int segCount
; 
 635         unsigned int libCount
; 
 636         const linkedit_data_command
* sigcmd
; 
 637         const encryption_info_command
* encryptCmd
; 
 638         sniffLoadCommands(mh
, moduleName
, false, &compressed
, &segCount
, &libCount
, context
, &sigcmd
, &encryptCmd
); 
 639         // instantiate concrete class based on content of load commands 
 641                 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
); 
 643 #if SUPPORT_CLASSIC_MACHO 
 644                 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
); 
 646                 throw "missing LC_DYLD_INFO load command"; 
 651 int ImageLoaderMachO::crashIfInvalidCodeSignature() 
 653         // Now that segments are mapped in, try reading from first executable segment. 
 654         // If code signing is enabled the kernel will validate the code signature 
 655         // when paging in, and kill the process if invalid. 
 656         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 657                 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) { 
 658                         // return read value to ensure compiler does not optimize away load 
 659                         int* p 
= (int*)segActualLoadAddress(i
); 
 667 void ImageLoaderMachO::parseLoadCmds(const LinkContext
& context
) 
 669         // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 
 670         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
 671                 // set up pointer to __LINKEDIT segment 
 672                 if ( strcmp(segName(i
),"__LINKEDIT") == 0 ) { 
 674                         // <rdar://problem/42419336> historically, macOS never did this check 
 675                         if ( segFileOffset(i
) > fCoveredCodeLength 
) 
 676                                 dyld::throwf("cannot load '%s' (segment outside of code signature)", this->getShortName()); 
 678                         fLinkEditBase 
= (uint8_t*)(segActualLoadAddress(i
) - segFileOffset(i
)); 
 680 #if TEXT_RELOC_SUPPORT 
 681                 // __TEXT segment always starts at beginning of file and contains mach_header and load commands 
 682                 if ( segExecutable(i
) ) { 
 683                         if ( segHasRebaseFixUps(i
) && (fSlide 
!= 0) ) 
 684                                 fTextSegmentRebases 
= true; 
 685                         if ( segHasBindFixUps(i
) ) 
 686                                 fTextSegmentBinds 
= true; 
 689                 if ( segIsReadOnlyData(i
) ) 
 690                         fReadOnlyDataSegment 
= true; 
 693                 if ( segIsReadOnlyImport(i
) ) 
 694                         fReadOnlyImportSegment 
= true; 
 696                 // some segment always starts at beginning of file and contains mach_header and load commands 
 697                 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) { 
 698                         fMachOData 
= (uint8_t*)(segActualLoadAddress(i
)); 
 702         // keep count of prebound images with weak exports 
 703         if ( this->participatesInCoalescing() ) { 
 704                 ++fgImagesRequiringCoalescing
; 
 705                 fRegisteredAsRequiresCoalescing 
= true; 
 706                 if ( this->hasCoalescedExports() )  
 707                         ++fgImagesHasWeakDefinitions
; 
 710         // keep count of images used in shared cache 
 711         if ( fInSharedCache 
) 
 712                 ++fgImagesUsedFromSharedCache
; 
 714         // walk load commands (mapped in at start of __TEXT segment) 
 715         const dyld_info_command
* dyldInfo 
= NULL
; 
 716         const linkedit_data_command
* chainedFixupsCmd 
= NULL
; 
 717         const linkedit_data_command
* exportsTrieCmd 
= NULL
; 
 718         const macho_nlist
* symbolTable 
= NULL
; 
 719         const char* symbolTableStrings 
= NULL
; 
 720         const struct load_command
* firstUnknownCmd 
= NULL
; 
 721         const struct version_min_command
* minOSVersionCmd 
= NULL
; 
 722         const dysymtab_command
* dynSymbolTable 
= NULL
; 
 723         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
 724         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
 725         const struct load_command
* cmd 
= cmds
; 
 726         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
 730                                         const struct symtab_command
* symtab 
= (struct symtab_command
*)cmd
; 
 731                                         symbolTableStrings 
= (const char*)&fLinkEditBase
[symtab
->stroff
]; 
 732                                         symbolTable 
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]); 
 736                                 dynSymbolTable 
= (struct dysymtab_command
*)cmd
; 
 738                         case LC_SUB_UMBRELLA
: 
 739                                 fHasSubUmbrella 
= true; 
 741                         case LC_SUB_FRAMEWORK
: 
 745                                 fHasSubLibraries 
= true; 
 747                         case LC_ROUTINES_COMMAND
: 
 751                         case LC_DYLD_INFO_ONLY
: 
 752                                 dyldInfo 
= (struct dyld_info_command
*)cmd
; 
 754                         case LC_DYLD_CHAINED_FIXUPS
: 
 755                                 chainedFixupsCmd 
= (struct linkedit_data_command
*)cmd
; 
 757                         case LC_DYLD_EXPORTS_TRIE
: 
 758                                 exportsTrieCmd 
= (struct linkedit_data_command
*)cmd
; 
 760                         case LC_SEGMENT_COMMAND
: 
 762                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
 763                                         const bool isTextSeg 
= (strcmp(seg
->segname
, "__TEXT") == 0); 
 764                 #if __i386__ && TARGET_OS_OSX 
 765                                         const bool isObjCSeg 
= (strcmp(seg
->segname
, "__OBJC") == 0); 
 769                                         const bool isDataSeg 
= (strncmp(seg
->segname
, "__DATA", 6) == 0); 
 771                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
 772                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
 773                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 774                                                 const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
 775                                                 if ( type 
== S_MOD_INIT_FUNC_POINTERS 
) 
 776                                                         fHasInitializers 
= true; 
 777                                                 else if ( type 
== S_INIT_FUNC_OFFSETS 
) 
 778                                                         fHasInitializers 
= true; 
 779                                                 else if ( type 
== S_MOD_TERM_FUNC_POINTERS 
) 
 780                                                         fHasTerminators 
= true; 
 781                                                 else if ( type 
== S_DTRACE_DOF 
) 
 782                                                         fHasDOFSections 
= true; 
 783                                                 else if ( isTextSeg 
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) ) 
 784                                                         fEHFrameSectionOffset 
= (uint32_t)((uint8_t*)sect 
- fMachOData
); 
 785                                                 else if ( isTextSeg 
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) ) 
 786                                                         fUnwindInfoSectionOffset 
= (uint32_t)((uint8_t*)sect 
- fMachOData
); 
 788                 #if __i386__ && TARGET_OS_OSX 
 789                                                 else if ( isObjCSeg 
) { 
 790                                                         if ( strcmp(sect
->sectname
, "__image_info") == 0 ) { 
 791                                                                 const uint32_t* imageInfo 
= (uint32_t*)(sect
->addr 
+ fSlide
); 
 792                                                                 uint32_t flags 
= imageInfo
[1]; 
 793                                                                 if ( (flags 
& 4) && (((macho_header
*)fMachOData
)->filetype 
!= MH_EXECUTE
) ) 
 794                                                                         dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath()); 
 796                                                         else if ( ((macho_header
*)fMachOData
)->filetype 
== MH_DYLIB 
) { 
 797                                                                 fRetainForObjC 
= true; 
 801                                                 else if ( isDataSeg 
&& (strncmp(sect
->sectname
, "__objc_imageinfo", 16) == 0) ) { 
 803                                                         const uint32_t* imageInfo 
= (uint32_t*)(sect
->addr 
+ fSlide
); 
 804                                                         uint32_t flags 
= imageInfo
[1]; 
 805                                                         if ( (flags 
& 4) && (((macho_header
*)fMachOData
)->filetype 
!= MH_EXECUTE
) ) 
 806                                                                 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath()); 
 810                                                 else if ( isDataSeg 
&& (strncmp(sect
->sectname
, "__objc_", 7) == 0) && (((macho_header
*)fMachOData
)->filetype 
== MH_DYLIB
) ) 
 811                                                         fRetainForObjC 
= true; 
 816                         case LC_TWOLEVEL_HINTS
: 
 817                                 // no longer supported 
 821                                         fDylibIDOffset 
= (uint32_t)((uint8_t*)cmd 
- fMachOData
); 
 825                         case LC_LOAD_WEAK_DYLIB
: 
 826                     case LC_REEXPORT_DYLIB
: 
 827                         case LC_LOAD_UPWARD_DYLIB
: 
 830                         case LC_VERSION_MIN_MACOSX
: 
 831                         case LC_VERSION_MIN_IPHONEOS
: 
 832                         case LC_VERSION_MIN_TVOS
: 
 833                         case LC_VERSION_MIN_WATCHOS
: 
 834                                 minOSVersionCmd 
= (version_min_command
*)cmd
; 
 837                                 if ( (cmd
->cmd 
& LC_REQ_DYLD
) != 0 ) { 
 838                                         if ( firstUnknownCmd 
== NULL 
) 
 839                                                 firstUnknownCmd 
= cmd
; 
 843                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
 845         if ( firstUnknownCmd 
!= NULL 
) { 
 846                 if ( minOSVersionCmd 
!= NULL 
)  { 
 847                         dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",  
 848                                                  this->getShortName(), 
 849                                                  minOSVersionCmd
->version 
>> 16, ((minOSVersionCmd
->version 
>> 8) & 0xff),  
 850                                                  firstUnknownCmd
->cmd
); 
 853                         dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd
->cmd
); 
 858         if ( dyldInfo 
!= NULL 
) 
 859                 this->setDyldInfo(dyldInfo
); 
 860         if ( chainedFixupsCmd 
!= NULL 
) 
 861                 this->setChainedFixups(chainedFixupsCmd
); 
 862         if ( exportsTrieCmd 
!= NULL 
) 
 863                 this->setExportsTrie(exportsTrieCmd
); 
 865         if ( symbolTable 
!= NULL
) 
 866                 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
); 
 869 // don't do this work in destructor because we need object to be full subclass 
 870 // for UnmapSegments() to work 
 871 void ImageLoaderMachO::destroy() 
 873         // update count of images with weak exports 
 874         if ( fRegisteredAsRequiresCoalescing 
) { 
 875                 --fgImagesRequiringCoalescing
; 
 876                 if ( this->hasCoalescedExports() )  
 877                         --fgImagesHasWeakDefinitions
; 
 880         // keep count of images used in shared cache 
 881         if ( fInSharedCache 
) 
 882                 --fgImagesUsedFromSharedCache
; 
 884         // unmap image when done 
 889 unsigned int ImageLoaderMachO::segmentCount() const 
 891         return fSegmentsCount
; 
 895 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const 
 897         uint32_t* lcOffsets 
= this->segmentCommandOffsets(); 
 898         uint32_t lcOffset 
=     lcOffsets
[segIndex
]; 
 899         return (macho_segment_command
*)(&fMachOData
[lcOffset
]); 
 902 const char*     ImageLoaderMachO::segName(unsigned int segIndex
) const 
 904         return segLoadCommand(segIndex
)->segname
; 
 908 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const 
 910         return segLoadCommand(segIndex
)->vmsize
; 
 914 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const 
 916         return segLoadCommand(segIndex
)->filesize
; 
 920 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
) 
 922         return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) ); 
 926 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const 
 928         return segLoadCommand(segIndex
)->fileoff
; 
 932 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const 
 934         return ( (segLoadCommand(segIndex
)->initprot 
& VM_PROT_READ
) != 0); 
 938 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const 
 940         return ( (segLoadCommand(segIndex
)->initprot 
& VM_PROT_WRITE
) != 0); 
 944 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const 
 946         return ( (segLoadCommand(segIndex
)->initprot 
& VM_PROT_EXECUTE
) != 0); 
 950 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const 
 952         return (segLoadCommand(segIndex
)->initprot 
== 0); 
 955 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const 
 957         return (segLoadCommand(segIndex
)->vmaddr 
!= 0); 
 960 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const 
 962         return segLoadCommand(segIndex
)->vmaddr
; 
 965 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const 
 967         return segLoadCommand(segIndex
)->vmaddr 
+ fSlide
; 
 971 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const 
 973         return segActualLoadAddress(segIndex
) + segSize(segIndex
); 
 976 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const 
 978 #if TEXT_RELOC_SUPPORT 
 979         // scan sections for fix-up bit 
 980         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
 981         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)segCmd 
+ sizeof(struct macho_segment_command
)); 
 982         const struct macho_section
* const sectionsEnd 
= §ionsStart
[segCmd
->nsects
]; 
 983         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 984                 if ( (sect
->flags 
& S_ATTR_LOC_RELOC
) != 0 ) 
 991 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const 
 993 #if TEXT_RELOC_SUPPORT 
 994         // scan sections for fix-up bit 
 995         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
 996         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)segCmd 
+ sizeof(struct macho_segment_command
)); 
 997         const struct macho_section
* const sectionsEnd 
= §ionsStart
[segCmd
->nsects
]; 
 998         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
 999                 if ( (sect
->flags 
& S_ATTR_EXT_RELOC
) != 0 ) 
1007 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const 
1009         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
1010         return (    (segCmd
->initprot 
& VM_PROT_EXECUTE
)  
1011                         && ((segCmd
->initprot 
& VM_PROT_WRITE
) == 0)  
1012                         && (strcmp(segCmd
->segname
, "__IMPORT") == 0) ); 
1016 bool ImageLoaderMachO::segIsReadOnlyData(unsigned int segIndex
) const 
1018         const macho_segment_command
* segCmd 
= segLoadCommand(segIndex
); 
1019         return (    (segCmd
->initprot 
& VM_PROT_WRITE
) 
1020                         && ((segCmd
->initprot 
& VM_PROT_EXECUTE
) == 0) 
1021                         && (segCmd
->flags 
& SG_READ_ONLY
) ); 
1024 void ImageLoaderMachO::UnmapSegments() 
1026         // usually unmap image when done 
1027         if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) { 
1028                 // unmap TEXT segment last because it contains load command being inspected 
1029                 unsigned int textSegmentIndex 
= 0; 
1030                 for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
1031                         //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this)); 
1032                         if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) { 
1033                                 textSegmentIndex 
= i
; 
1037                                 --ImageLoader::fgTotalSegmentsMapped
; 
1038                                 ImageLoader::fgTotalBytesMapped 
-= segSize(i
); 
1039                                 munmap((void*)segActualLoadAddress(i
), segSize(i
)); 
1043                 --ImageLoader::fgTotalSegmentsMapped
; 
1044                 ImageLoader::fgTotalBytesMapped 
-= segSize(textSegmentIndex
); 
1045                 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
)); 
1050 bool ImageLoaderMachO::segmentsMustSlideTogether() const  
1055 bool ImageLoaderMachO::segmentsCanSlide() const  
1057         return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable()); 
1060 bool ImageLoaderMachO::isBundle() const  
1062         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1063         return ( mh
->filetype 
== MH_BUNDLE 
); 
1066 bool ImageLoaderMachO::isDylib() const  
1068         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1069         return ( mh
->filetype 
== MH_DYLIB 
); 
1072 bool ImageLoaderMachO::isExecutable() const  
1074         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1075         return ( mh
->filetype 
== MH_EXECUTE 
); 
1078 bool ImageLoaderMachO::isPositionIndependentExecutable() const  
1080         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1081         return ( (mh
->filetype 
== MH_EXECUTE
) && ((mh
->flags 
& MH_PIE
) != 0) ); 
1085 bool ImageLoaderMachO::forceFlat() const  
1087         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1088         return ( (mh
->flags 
& MH_FORCE_FLAT
) != 0 ); 
1091 bool ImageLoaderMachO::usesTwoLevelNameSpace() const 
1093         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1094         return ( (mh
->flags 
& MH_TWOLEVEL
) != 0 ); 
1097 bool ImageLoaderMachO::isPrebindable() const  
1099         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1100         return ( (mh
->flags 
& MH_PREBOUND
) != 0 ); 
1103 bool ImageLoaderMachO::hasCoalescedExports() const  
1105         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1106         return ( (mh
->flags 
& MH_WEAK_DEFINES
) != 0 ); 
1109 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const  
1111         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1112         return ( (mh
->flags 
& MH_BINDS_TO_WEAK
) != 0 ); 
1115 bool ImageLoaderMachO::participatesInCoalescing() const  
1117         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
1118         // if image is loaded with RTLD_LOCAL, then its symbols' visibility 
1119         // is reduced and it can't coalesce with other images 
1120         if ( this->hasHiddenExports() ) 
1122         return ( (mh
->flags 
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 ); 
1127 void ImageLoaderMachO::setSlide(intptr_t slide
) 
1132 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
,  uint64_t offsetInFatFile
, const LinkContext
& context
) 
1134         dyld3::ScopedTimer(DBG_DYLD_TIMING_ATTACH_CODESIGNATURE
, 0, 0, 0); 
1135         // if dylib being loaded has no code signature load command 
1136         if ( codeSigCmd 
== NULL
) { 
1137                 disableCoverageCheck(); 
1141                 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools 
1142                 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) { 
1143                         disableCoverageCheck(); 
1148                 fsignatures_t siginfo
; 
1149                 siginfo
.fs_file_start
=offsetInFatFile
;                          // start of mach-o slice in fat file 
1150                 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
);       // start of CD in mach-o file 
1151                 siginfo
.fs_blob_size
=codeSigCmd
->datasize
;                      // size of CD 
1152                 int result 
= fcntl(fd
, F_ADDFILESIGS_RETURN
, &siginfo
); 
1154 #if TARGET_OS_SIMULATOR 
1155                 // rdar://problem/18759224> check range covered by the code directory after loading 
1156                 // Attempt to fallback only if we are in the simulator 
1158                 if ( result 
== -1 ) { 
1159                         result 
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
); 
1160                         siginfo
.fs_file_start 
= codeSigCmd
->dataoff
; 
1164                 if ( result 
== -1 ) { 
1165                         if ( (errno 
== EPERM
) || (errno 
== EBADEXEC
) ) 
1166                                 dyld::throwf("code signature invalid for '%s'\n", this->getPath()); 
1167                         if ( context
.verboseCodeSignatures 
) 
1168                                 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno
); 
1169                         siginfo
.fs_file_start 
= UINT64_MAX
; 
1170                 } else if ( context
.verboseCodeSignatures 
)  { 
1171                         dyld::log("dyld: Registered code signature for %s\n", this->getPath()); 
1173                 fCoveredCodeLength 
= siginfo
.fs_file_start
; 
1178                 char  messageBuffer
[512]; 
1179                 messageBuffer
[0] = '\0'; 
1180                 checkInfo
.lv_file_start 
= offsetInFatFile
; 
1181                 checkInfo
.lv_error_message_size 
= sizeof(messageBuffer
); 
1182                 checkInfo
.lv_error_message 
= messageBuffer
; 
1183                 int res 
= fcntl(fd
, F_CHECK_LV
, &checkInfo
); 
1185                         dyld::throwf("code signature in (%s) not valid for use in process using Library Validation: %s", this->getPath(), messageBuffer
); 
1190 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command
* codeSigCmd
, int fd
, const uint8_t *fileData
, size_t lenFileData
, off_t offsetInFat
, const LinkContext
& context
) 
1193         // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure 
1194         // We need to ignore older code signatures because they will be bad. 
1195         if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) { 
1199         if (codeSigCmd 
!= NULL
) { 
1200                 void *fdata 
= xmmap(NULL
, lenFileData
, PROT_READ
, MAP_SHARED
, fd
, offsetInFat
); 
1201                 if ( fdata 
== MAP_FAILED 
) { 
1202                         int errnoCopy 
= errno
; 
1203                         if ( errnoCopy 
== EPERM 
) { 
1204                                 if ( dyld::sandboxBlockedMmap(getPath()) ) 
1205                                         dyld::throwf("file system sandbox blocked mmap() of '%s'", getPath()); 
1207                                         dyld::throwf("code signing blocked mmap() of '%s'", getPath()); 
1210                                 dyld::throwf("mmap() errno=%d validating first page of '%s'", errnoCopy
, getPath()); 
1212                 if ( memcmp(fdata
, fileData
, lenFileData
) != 0 ) 
1213                         dyld::throwf("mmap() page compare failed for '%s'", getPath()); 
1214                 munmap(fdata
, lenFileData
); 
1219 const char* ImageLoaderMachO::getInstallPath() const 
1221         if ( fDylibIDOffset 
!= 0 ) { 
1222                 const dylib_command
* dylibID 
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]); 
1223                 return (char*)dylibID 
+ dylibID
->dylib
.name
.offset
; 
1228 void ImageLoaderMachO::registerInterposing(const LinkContext
& context
) 
1230         // mach-o files advertise interposing by having a __DATA __interpose section 
1231         struct InterposeData 
{ uintptr_t replacement
; uintptr_t replacee
; }; 
1232         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1233         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1234         const struct load_command
* cmd 
= cmds
; 
1235         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1237                         case LC_SEGMENT_COMMAND
: 
1239                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1240                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1241                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1242                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1243                                                 if ( ((sect
->flags 
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) { 
1244                                                         // <rdar://problem/23929217> Ensure section is within segment 
1245                                                         if ( (sect
->addr 
< seg
->vmaddr
) || (sect
->addr
+sect
->size 
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size 
< sect
->addr
) ) 
1246                                                                 dyld::throwf("interpose section has malformed address range for %s\n", this->getPath()); 
1247                                                         const InterposeData
* interposeArray 
= (InterposeData
*)(sect
->addr 
+ fSlide
); 
1248                                                         const size_t count 
= sect
->size 
/ sizeof(InterposeData
); 
1249                                                         for (size_t j
=0; j 
< count
; ++j
) { 
1250                                                                 ImageLoader::InterposeTuple tuple
; 
1251                                                                 tuple
.replacement               
= interposeArray
[j
].replacement
; 
1252                                                                 tuple
.neverImage                
= this; 
1253                                                                 tuple
.onlyImage             
= NULL
; 
1254                                                                 tuple
.replacee                  
= interposeArray
[j
].replacee
; 
1255                                                                 // <rdar://problem/25686570> ignore interposing on a weak function that does not exist 
1256                                                                 if ( tuple
.replacee 
== 0 ) 
1258                                                                 // <rdar://problem/7937695> verify that replacement is in this image 
1259                                                                 if ( this->containsAddress((void*)tuple
.replacement
) ) { 
1260                                                                         // chain to any existing interpositions 
1261                                                                         for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
1262                                                                                 if ( it
->replacee 
== tuple
.replacee 
) { 
1263                                                                                         tuple
.replacee 
= it
->replacement
; 
1266                                                                         ImageLoader::fgInterposingTuples
.push_back(tuple
); 
1274                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1278 uint32_t ImageLoaderMachO::sdkVersion(const mach_header
* mh
) 
1280         const uint32_t cmd_count 
= mh
->ncmds
; 
1281         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
)); 
1282         const struct load_command
* cmd 
= cmds
; 
1283         const struct version_min_command
* versCmd
; 
1284         const struct build_version_command
* buildVersCmd
; 
1285         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1286                 switch ( cmd
->cmd 
) { 
1287                         case LC_VERSION_MIN_MACOSX
: 
1288                         case LC_VERSION_MIN_IPHONEOS
: 
1289                         case LC_VERSION_MIN_TVOS
: 
1290                         case LC_VERSION_MIN_WATCHOS
: 
1291                                 versCmd 
= (version_min_command
*)cmd
; 
1292                                 return versCmd
->sdk
; 
1293                         case LC_BUILD_VERSION
: 
1294                                 buildVersCmd 
= (build_version_command
*)cmd
; 
1295                                 return buildVersCmd
->sdk
; 
1297                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1302 uint32_t ImageLoaderMachO::sdkVersion() const 
1304         return ImageLoaderMachO::sdkVersion(machHeader()); 
1307 uint32_t ImageLoaderMachO::minOSVersion(const mach_header
* mh
) 
1309         const uint32_t cmd_count 
= mh
->ncmds
; 
1310         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
)); 
1311         const struct load_command
* cmd 
= cmds
; 
1312         const struct version_min_command
* versCmd
; 
1313         const struct build_version_command
* buildVersCmd
; 
1314         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1315                 switch ( cmd
->cmd 
) { 
1316                         case LC_VERSION_MIN_MACOSX
: 
1317                         case LC_VERSION_MIN_IPHONEOS
: 
1318                         case LC_VERSION_MIN_TVOS
: 
1319                         case LC_VERSION_MIN_WATCHOS
: 
1320                                 versCmd 
= (version_min_command
*)cmd
; 
1321                                 return versCmd
->version
; 
1322                         case LC_BUILD_VERSION
: 
1323                                 buildVersCmd 
= (build_version_command
*)cmd
; 
1324                                 return buildVersCmd
->minos
; 
1326                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1331 uint32_t ImageLoaderMachO::minOSVersion() const 
1333         return ImageLoaderMachO::minOSVersion(machHeader()); 
1337 void* ImageLoaderMachO::getEntryFromLC_MAIN() const 
1339         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1340         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1341         const struct load_command
* cmd 
= cmds
; 
1342         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1343                 if ( cmd
->cmd 
== LC_MAIN 
) { 
1344                         entry_point_command
* mainCmd 
= (entry_point_command
*)cmd
; 
1345                         void* entry 
= (void*)(mainCmd
->entryoff 
+ (char*)fMachOData
); 
1346                         // <rdar://problem/8543820&9228031> verify entry point is in image 
1347                         if ( this->containsAddress(entry
) ) { 
1348 #if __has_feature(ptrauth_calls) 
1349                                 // start() calls the result pointer as a function pointer so we need to sign it. 
1350                                 return __builtin_ptrauth_sign_unauthenticated(entry
, 0, 0); 
1355                                 throw "LC_MAIN entryoff is out of range"; 
1357                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1363 void* ImageLoaderMachO::getEntryFromLC_UNIXTHREAD() const 
1365         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1366         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1367         const struct load_command
* cmd 
= cmds
; 
1368         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1369                 if ( cmd
->cmd 
== LC_UNIXTHREAD 
) { 
1371                         const i386_thread_state_t
* registers 
= (i386_thread_state_t
*)(((char*)cmd
) + 16); 
1372                         void* entry 
= (void*)(registers
->eip 
+ fSlide
); 
1373                         // <rdar://problem/8543820&9228031> verify entry point is in image 
1374                         if ( this->containsAddress(entry
) ) 
1377                         const x86_thread_state64_t
* registers 
= (x86_thread_state64_t
*)(((char*)cmd
) + 16); 
1378                         void* entry 
= (void*)(registers
->rip 
+ fSlide
); 
1379                         // <rdar://problem/8543820&9228031> verify entry point is in image 
1380                         if ( this->containsAddress(entry
) ) 
1384                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1386         throw "no valid entry point"; 
1389 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
) 
1391         // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem 
1395         // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind 
1396         if ( mh
->filetype 
== MH_EXECUTE 
)  
1399         bool isNonOSdylib 
= false; 
1400         const uint32_t cmd_count 
= mh
->ncmds
; 
1401         const struct load_command
* const cmds 
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
)); 
1402         const struct load_command
* cmd 
= cmds
; 
1403         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1406                         case LC_LOAD_WEAK_DYLIB
: 
1407                         case LC_REEXPORT_DYLIB
: 
1408                         case LC_LOAD_UPWARD_DYLIB
: 
1412                                 const dylib_command
* dylibID 
= (dylib_command
*)cmd
; 
1413                                 const char* installPath 
= (char*)cmd 
+ dylibID
->dylib
.name
.offset
; 
1414                                 // It is OK for OS dylibs (libSystem or libmath) to have no dependents 
1415                                 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first 
1416                                 isNonOSdylib 
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/System/DriverKit/usr/lib/", 26) != 0) ); 
1417                                 // if (isNonOSdylib) dyld::log("ImageLoaderMachO::needsAddedLibSystemDepency(%s)\n", installPath); 
1421                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1423         return isNonOSdylib
; 
1427 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[]) 
1429         if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) { 
1430                 DependentLibraryInfo
* lib 
= &libs
[0]; 
1431                 lib
->name 
= LIBSYSTEM_DYLIB_PATH
; 
1432                 lib
->info
.checksum 
= 0; 
1433                 lib
->info
.minVersion 
= 0; 
1434                 lib
->info
.maxVersion 
= 0; 
1435                 lib
->required 
= false; 
1436                 lib
->reExported 
= false; 
1437                 lib
->upward 
= false; 
1441                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1442                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1443                 const struct load_command
* cmd 
= cmds
; 
1444                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1447                                 case LC_LOAD_WEAK_DYLIB
: 
1448                                 case LC_REEXPORT_DYLIB
: 
1449                                 case LC_LOAD_UPWARD_DYLIB
: 
1451                                         const struct dylib_command
* dylib 
= (struct dylib_command
*)cmd
; 
1452                                         DependentLibraryInfo
* lib 
= &libs
[index
++]; 
1453                                         lib
->name 
= (char*)cmd 
+ dylib
->dylib
.name
.offset
; 
1454                                         //lib->name = strdup((char*)cmd + dylib->dylib.name.offset); 
1455                                         lib
->info
.checksum 
= dylib
->dylib
.timestamp
; 
1456                                         lib
->info
.minVersion 
= dylib
->dylib
.compatibility_version
; 
1457                                         lib
->info
.maxVersion 
= dylib
->dylib
.current_version
; 
1458                                         lib
->required 
= (cmd
->cmd 
!= LC_LOAD_WEAK_DYLIB
); 
1459                                         lib
->reExported 
= (cmd
->cmd 
== LC_REEXPORT_DYLIB
); 
1460                                         lib
->upward 
= (cmd
->cmd 
== LC_LOAD_UPWARD_DYLIB
); 
1464                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1469 ImageLoader::LibraryInfo 
ImageLoaderMachO::doGetLibraryInfo(const LibraryInfo
&) 
1472         if ( fDylibIDOffset 
!= 0 ) { 
1473                 const dylib_command
* dylibID 
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]); 
1474                 info
.minVersion 
= dylibID
->dylib
.compatibility_version
; 
1475                 info
.maxVersion 
= dylibID
->dylib
.current_version
; 
1476                 info
.checksum 
= dylibID
->dylib
.timestamp
; 
1479                 info
.minVersion 
= 0; 
1480                 info
.maxVersion 
= 0;             
1486 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const 
1488         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1489         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1490         const struct load_command
* cmd 
= cmds
; 
1491         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1494                                 const char* pathToAdd 
= NULL
; 
1495                                 const char* path 
= (char*)cmd 
+ ((struct rpath_command
*)cmd
)->path
.offset
; 
1496                                 if ( (strncmp(path
, "@loader_path", 12) == 0) && ((path
[12] == '/') || (path
[12] == '\0')) ) { 
1497                                         if ( !context
.allowAtPaths 
&& (context
.mainExecutable 
== this) ) { 
1498                                                 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path (Codesign main executable with Library Validation to allow @ paths)\n", path
, this->getPath()); 
1501                                         char resolvedPath
[PATH_MAX
]; 
1502                                         if ( realpath(this->getPath(), resolvedPath
) != NULL 
) { 
1503                                                 char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
1504                                                 strcpy(newRealPath
, resolvedPath
); 
1505                                                 char* addPoint 
= strrchr(newRealPath
,'/'); 
1506                                                 if ( addPoint 
!= NULL 
) { 
1507                                                         strcpy(addPoint
, &path
[12]); 
1508                                                         pathToAdd 
= strdup(newRealPath
); 
1512                                 else if ( (strncmp(path
, "@executable_path", 16) == 0) && ((path
[16] == '/') || (path
[16] == '\0')) ) { 
1513                                         if ( !context
.allowAtPaths
) { 
1514                                                 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)\n", path
, this->getPath()); 
1517                                         char resolvedPath
[PATH_MAX
]; 
1518                                         if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL 
) { 
1519                                                 char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
1520                                                 strcpy(newRealPath
, resolvedPath
); 
1521                                                 char* addPoint 
= strrchr(newRealPath
,'/'); 
1522                                                 if ( addPoint 
!= NULL 
) { 
1523                                                         strcpy(addPoint
, &path
[16]); 
1524                                                         pathToAdd 
= strdup(newRealPath
); 
1528                                 else if ( (path
[0] != '/') && !context
.allowAtPaths
) { 
1529                                         dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath()); 
1532 #if SUPPORT_ROOT_PATH 
1533                                 else if ( (path
[0] == '/') && (context
.rootPaths 
!= NULL
) ) { 
1534                                         // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths 
1535                                         // <rdar://problem/49576123> Even if DYLD_ROOT_PATH exists, LC_RPATH should add raw path to rpaths 
1536                                         // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists 
1537                                         for (const char** rp 
= context
.rootPaths
; *rp 
!= NULL
; ++rp
) { 
1538                                                 char newPath
[PATH_MAX
]; 
1539                                                 strlcpy(newPath
, *rp
, PATH_MAX
); 
1540                                                 strlcat(newPath
, path
, PATH_MAX
); 
1541                                                 struct stat stat_buf
; 
1542                                                 if ( dyld3::stat(newPath
, &stat_buf
) != -1 ) { 
1543                                                         // dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath); 
1544                                                         paths
.push_back(strdup(newPath
)); 
1547                                         // add in raw absolute path without root prefix 
1548                                         pathToAdd 
= strdup(path
); 
1552                                         // realpath() is slow, and /usr/lib/swift is a real path, so don't realpath it 
1553                                         if ( strcmp(path
, "/usr/lib/swift") != 0 ) { 
1554                                                 char resolvedPath
[PATH_MAX
]; 
1555                                                 if ( (realpath(path
, resolvedPath
) != NULL
) && (strcmp(path
, resolvedPath
) != 0) ) { 
1556                                                         // <rdar://problem/45470293> support LC_RPATH symlinks to directories of things in the dyld cache 
1557                                                         path 
= resolvedPath
; 
1560                                         // make copy so that all elements of 'paths' can be freed 
1561                                         pathToAdd 
= strdup(path
); 
1563                                 if ( pathToAdd 
!= NULL 
) 
1564                                         paths
.push_back(pathToAdd
); 
1567                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1572 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const 
1574         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1575         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1576         const struct load_command
* cmd 
= cmds
; 
1577         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1580                                 uuid_command
* uc 
= (uuid_command
*)cmd
; 
1581                                 memcpy(uuid
, uc
->uuid
, 16); 
1584                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1590 void ImageLoaderMachO::doRebase(const LinkContext
& context
) 
1592         // <rdar://problem/25329861> Delay calling setNeverUnload() until we know this is not for dlopen_preflight() 
1593         if ( fRetainForObjC 
) 
1594                 this->setNeverUnload(); 
1596     // dylibs with thread local variables cannot be unloaded because there is no way to clean up all threads 
1597     if ( !this->inSharedCache() && (this->machHeader()->flags 
& MH_HAS_TLV_DESCRIPTORS
) ) 
1598         this->setNeverUnload(); 
1600         // if prebound and loaded at prebound address, then no need to rebase 
1601         if ( this->usablePrebinding(context
) ) { 
1602                 // skip rebasing because prebinding is valid 
1603                 ++fgImagesWithUsedPrebinding
; // bump totals for statistics 
1607         // print why prebinding was not used 
1608         if ( context
.verbosePrebinding 
) { 
1609                 if ( !this->isPrebindable() ) { 
1610                         dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath()); 
1612                 else if ( fSlide 
!= 0 ) { 
1613                         dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath()); 
1615                 else if ( !this->allDependentLibrariesAsWhenPreBound() ) { 
1616                         dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath()); 
1618                 else if ( !this->usesTwoLevelNameSpace() ){ 
1619                         dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath()); 
1622                         dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath()); 
1626         //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath()); 
1628 #if PREBOUND_IMAGE_SUPPORT 
1629         // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers 
1630         // if this image is in the shared cache, do not reset, they will be bound in doBind() 
1631         if ( this->isPrebindable() && !fInSharedCache 
) 
1632                 this->resetPreboundLazyPointers(context
); 
1635         // if loaded at preferred address, no rebasing necessary 
1636         if ( this->fSlide 
== 0 ) 
1639 #if TEXT_RELOC_SUPPORT 
1640         // if there are __TEXT fixups, temporarily make __TEXT writable 
1641         if ( fTextSegmentRebases 
)  
1642                 this->makeTextSegmentWritable(context
, true); 
1645         // do actual rebasing 
1646         this->rebase(context
, fSlide
); 
1648 #if TEXT_RELOC_SUPPORT 
1649         // if there were __TEXT fixups, restore write protection 
1650         if ( fTextSegmentRebases 
)  
1651                 this->makeTextSegmentWritable(context
, false); 
1656 #if TEXT_RELOC_SUPPORT 
1657 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
) 
1659         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
1660                 if ( segExecutable(i
) ) { 
1662                                 segMakeWritable(i
, context
); 
1665                         #if !__i386__ && !__x86_64__ 
1666                                 // some processors require range to be invalidated before it is made executable 
1667                                 sys_icache_invalidate((void*)segActualLoadAddress(i
), segSize(textSegmentIndex
)); 
1669                                 segProtect(i
, context
); 
1677 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const char* thisPath
, const ImageLoader
** foundIn
) const 
1679         // look in this image first 
1680         const ImageLoader::Symbol
* result 
= this->findShallowExportedSymbol(name
, foundIn
); 
1681         if ( result 
!= NULL 
) 
1684         if ( searchReExports 
) { 
1685                 for(unsigned int i
=0; i 
< libraryCount(); ++i
){ 
1686                         if ( libReExported(i
) ) { 
1687                                 ImageLoader
* image 
= libImage(i
); 
1688                                 if ( image 
!= NULL 
) { 
1689                                         const char* reExPath 
= libPath(i
); 
1690                                         result 
= image
->findExportedSymbol(name
, searchReExports
, reExPath
, foundIn
); 
1691                                         if ( result 
!= NULL 
) 
1704 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,  
1705                                                                                         const ImageLoader
* requestor
, bool runResolver
, const char* symbolName
) const 
1707         return this->getSymbolAddress(sym
, requestor
, context
, runResolver
); 
1710 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,  
1711                                                                                                 const LinkContext
& context
, bool runResolver
) const 
1713         uintptr_t result 
= exportedSymbolAddress(context
, sym
, requestor
, runResolver
); 
1714         // check for interposing overrides 
1715         result 
= interposedAddress(context
, result
, requestor
); 
1719 ImageLoader::DefinitionFlags 
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const 
1721         if ( exportedSymbolIsWeakDefintion(sym
) ) 
1722                 return kWeakDefinition
; 
1724                 return kNoDefinitionOptions
; 
1727 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const 
1729         return exportedSymbolName(sym
); 
1732 uint32_t ImageLoaderMachO::getExportedSymbolCount() const 
1734         return exportedSymbolCount(); 
1738 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const 
1740         return exportedSymbolIndexed(index
); 
1744 uint32_t ImageLoaderMachO::getImportedSymbolCount() const 
1746         return importedSymbolCount(); 
1750 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const 
1752         return importedSymbolIndexed(index
); 
1756 ImageLoader::ReferenceFlags 
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const 
1758         ImageLoader::ReferenceFlags flags 
= kNoReferenceOptions
; 
1763 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const 
1765         return importedSymbolName(sym
); 
1769 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
) 
1771         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1772         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1773         const struct load_command
* cmd 
= cmds
; 
1774         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1776                         case LC_SEGMENT_COMMAND
: 
1778                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1779                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1780                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1781                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1782                                                 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) { 
1783                                                         *start 
= (uintptr_t*)(sect
->addr 
+ fSlide
); 
1784                                                         *length 
= sect
->size
; 
1791                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1798 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
) 
1800         info
->mh 
= this->machHeader(); 
1801         info
->dwarf_section 
= 0; 
1802         info
->dwarf_section_length 
= 0; 
1803         info
->compact_unwind_section 
= 0; 
1804         info
->compact_unwind_section_length 
= 0; 
1805         if ( fEHFrameSectionOffset 
!= 0 ) { 
1806                 const macho_section
* sect 
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
]; 
1807                 info
->dwarf_section 
= (void*)(sect
->addr 
+ fSlide
); 
1808                 info
->dwarf_section_length 
= sect
->size
; 
1810         if ( fUnwindInfoSectionOffset 
!= 0 ) { 
1811                 const macho_section
* sect 
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
]; 
1812                 info
->compact_unwind_section 
= (void*)(sect
->addr 
+ fSlide
); 
1813                 info
->compact_unwind_section_length 
= sect
->size
; 
1817 intptr_t ImageLoaderMachO::computeSlide(const mach_header
* mh
) 
1819         const uint32_t cmd_count 
= mh
->ncmds
; 
1820         const load_command
* const cmds 
= (load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
1821         const load_command
* cmd 
= cmds
; 
1822         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1823                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
1824                         const macho_segment_command
* seg 
= (macho_segment_command
*)cmd
; 
1825                         if ( strcmp(seg
->segname
, "__TEXT") == 0 ) 
1826                                 return (char*)mh 
- (char*)(seg
->vmaddr
); 
1828                 cmd 
= (const load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1833 bool ImageLoaderMachO::findSection(const mach_header
* mh
, const char* segmentName
, const char* sectionName
, void** sectAddress
, size_t* sectSize
) 
1835         const uint32_t cmd_count 
= mh
->ncmds
; 
1836         const load_command
* const cmds 
= (load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
1837         const load_command
* cmd 
= cmds
; 
1838         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1840                         case LC_SEGMENT_COMMAND
: 
1842                                         const macho_segment_command
* seg 
= (macho_segment_command
*)cmd
; 
1843                                         const macho_section
* const sectionsStart 
= (macho_section
*)((char*)seg 
+ sizeof(macho_segment_command
)); 
1844                                         const macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1845                                         for (const macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1846                                                 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) { 
1847                                                         *sectAddress 
= (void*)(sect
->addr 
+ computeSlide(mh
)); 
1848                                                         *sectSize 
= sect
->size
; 
1855                 cmd 
= (const load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1861 const macho_section
* ImageLoaderMachO::findSection(const void* imageInterior
) const 
1863         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1864         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1865         const struct load_command
* cmd 
= cmds
; 
1866         const uintptr_t unslidInteriorAddress 
= (uintptr_t)imageInterior 
- this->getSlide(); 
1867         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1869                         case LC_SEGMENT_COMMAND
: 
1871                                         const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
1872                                         if ( (unslidInteriorAddress 
>= seg
->vmaddr
) && (unslidInteriorAddress 
< (seg
->vmaddr
+seg
->vmsize
)) ) { 
1873                                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
1874                                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
1875                                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
1876                                                         if ((sect
->addr 
<= unslidInteriorAddress
) && (unslidInteriorAddress 
< (sect
->addr
+sect
->size
))) { 
1884                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1890 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
) 
1892         if (const struct macho_section
* sect 
= findSection(imageInterior
)) { 
1893                 const uintptr_t unslidInteriorAddress 
= (uintptr_t)imageInterior 
- this->getSlide(); 
1894                 if ( segmentName 
!= NULL 
) 
1895                         *segmentName 
= sect
->segname
; 
1896                 if ( sectionName 
!= NULL 
) 
1897                         *sectionName 
= sect
->sectname
; 
1898                 if ( sectionOffset 
!= NULL 
) 
1899                         *sectionOffset 
= unslidInteriorAddress 
- sect
->addr
; 
1905 const char* ImageLoaderMachO::libPath(unsigned int index
) const 
1907         const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
1908         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
1909         const struct load_command
* cmd 
= cmds
; 
1911         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
1912                 switch ( cmd
->cmd 
) { 
1914                         case LC_LOAD_WEAK_DYLIB
: 
1915                         case LC_REEXPORT_DYLIB
: 
1916                         case LC_LOAD_UPWARD_DYLIB
: 
1917                                 if ( index 
== count 
) { 
1918                                         const struct dylib_command
*  dylibCmd 
= (struct dylib_command
*)cmd
; 
1919                                         return (char*)cmd 
+ dylibCmd
->dylib
.name
.offset
; 
1924                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
1927         // <rdar://problem/24256354> if image linked with nothing and we implicitly added libSystem.dylib, return that 
1928         if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) { 
1929                 return LIBSYSTEM_DYLIB_PATH
; 
1936 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,  
1937                                                                                                                                         const char* referencedFrom
, const char* fromVersMismatch
, 
1938                                                                                                                                         const char* expectedIn
) 
1940         // record values for possible use by CrashReporter or Finder 
1941         (*context
.setErrorStrings
)(DYLD_EXIT_REASON_SYMBOL_MISSING
, referencedFrom
, expectedIn
, symbol
); 
1942         dyld::throwf("Symbol not found: %s\n  Referenced from: %s%s\n  Expected in: %s\n", 
1943                                         symbol
, referencedFrom
, fromVersMismatch
, expectedIn
); 
1946 const mach_header
* ImageLoaderMachO::machHeader() const 
1948         return (mach_header
*)fMachOData
; 
1951 uintptr_t ImageLoaderMachO::getSlide() const 
1956 // hmm. maybe this should be up in ImageLoader?? 
1957 const void* ImageLoaderMachO::getEnd() const 
1959         uintptr_t lastAddress 
= 0; 
1960         for(unsigned int i
=0; i 
< fSegmentsCount
; ++i
) { 
1961                 uintptr_t segEnd 
= segActualEndAddress(i
); 
1962                 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) { 
1963                         if ( segEnd 
> lastAddress 
) 
1964                                 lastAddress 
= segEnd
; 
1967         return (const void*)lastAddress
; 
1970 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t baseVMAddress
, 
1971                                          uintptr_t location
, uintptr_t value
, 
1972                                          uint8_t type
, const char* symbolName
, 
1973                                          intptr_t addend
, const char* inPath
, const char* toPath
, const char* msg
, 
1974                                          ExtraBindData 
*extraBindData
, uintptr_t slide
) 
1976     auto logBind 
= [&]() { 
1977         if ( !context
.verboseBind 
) 
1979         if ( addend 
!= 0 ) { 
1980             dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n", 
1981                       msg
, shortName(inPath
), (uintptr_t)location
, 
1982                       ((toPath 
!= NULL
) ? shortName(toPath
) : "<missing weak_import>"), 
1983                       symbolName
, (uintptr_t)location
, value
, addend
); 
1985             dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n", 
1986                       msg
, shortName(inPath
), (uintptr_t)location
, 
1987                       ((toPath 
!= NULL
) ? shortName(toPath
) : "<missing weak_import>"), 
1988                       symbolName
, (uintptr_t)location
, value
); 
1994 //      dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName); 
1998         uintptr_t* locationToFix 
= (uintptr_t*)location
; 
2000         uintptr_t newValue 
= value
+addend
; 
2003                 case BIND_TYPE_POINTER
: 
2005                         // test first so we don't needless dirty pages 
2006                         if ( *locationToFix 
!= newValue 
) 
2007                                 *locationToFix 
= newValue
; 
2009         case BIND_TYPE_TEXT_ABSOLUTE32
: 
2011                         loc32 
= (uint32_t*)locationToFix
; 
2012                         value32 
= (uint32_t)newValue
; 
2013                         if ( *loc32 
!= value32 
) 
2016         case BIND_TYPE_TEXT_PCREL32
: 
2018                         loc32 
= (uint32_t*)locationToFix
; 
2019                         value32 
= (uint32_t)(newValue 
- (((uintptr_t)locationToFix
) + 4)); 
2020                         if ( *loc32 
!= value32 
) 
2023         case BIND_TYPE_THREADED_BIND
: 
2025             // test first so we don't needless dirty pages 
2026             if ( *locationToFix 
!= newValue 
) 
2027                 *locationToFix 
= newValue
; 
2029         case BIND_TYPE_THREADED_REBASE
: { 
2030             // Regular pointer which needs to fit in 51-bits of value. 
2031             // C++ RTTI uses the top bit, so we'll allow the whole top-byte 
2032             // and the signed-extended bottom 43-bits to be fit in to 51-bits. 
2033             uint64_t top8Bits 
= *locationToFix 
& 0x0007F80000000000ULL
; 
2034             uint64_t bottom43Bits 
= *locationToFix 
& 0x000007FFFFFFFFFFULL
; 
2035             uint64_t targetValue 
= ( top8Bits 
<< 13 ) | (((intptr_t)(bottom43Bits 
<< 21) >> 21) & 0x00FFFFFFFFFFFFFF); 
2036             newValue 
= (uintptr_t)(targetValue 
+ slide
); 
2037             if ( context
.verboseRebase 
) { 
2038                 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX = 0x%08lX\n", shortName(inPath
), (uintptr_t)locationToFix
, slide
, newValue
); 
2040             *locationToFix 
= newValue
; 
2044                         dyld::throwf("bad bind type %d", type
); 
2047         // update statistics 
2048         ++fgTotalBindFixups
; 
2057 #if SUPPORT_OLD_CRT_INITIALIZATION 
2058 // first 16 bytes of "start" in crt1.o 
2060         static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 }; 
2065         void*                   dyldLazyBinder
;         // filled in at launch by dyld to point into dyld to &stub_binding_helper 
2066         void*                   dyldFuncLookup
;         // filled in at launch by dyld to point into dyld to &_dyld_func_lookup 
2067         // the following only exist in main executables built for 10.5 or later 
2071 // These are defined in dyldStartup.s 
2072 extern "C" void stub_binding_helper(); 
2073 extern "C" int _dyld_func_lookup(const char* name
, void** address
); 
2075 static const char* libDyldPath(const ImageLoader::LinkContext
& context
) 
2078         if ( context
.driverKit 
) 
2079                 return DRIVERKIT_LIBDYLD_DYLIB_PATH
; 
2082         return LIBDYLD_DYLIB_PATH
; 
2085 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
) 
2087         const macho_header
* mh 
= (macho_header
*)fMachOData
; 
2088         const uint32_t cmd_count 
= mh
->ncmds
; 
2089         const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2090         const struct load_command
* cmd
; 
2091         // There used to be some optimizations to skip this section scan, but we need to handle the  
2092         // __dyld section in libdyld.dylib, so everything needs to be scanned for now. 
2093         // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv 
2096                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2097                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
2098                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2099                                 if ( strncmp(seg
->segname
, "__DATA", 6) == 0 ) { 
2100                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2101                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2102                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2103                                                 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) { 
2104                                                         struct DATAdyld
* dd 
= (struct DATAdyld
*)(sect
->addr 
+ fSlide
); 
2105                                 #if !__arm64__ && !__ARM_ARCH_7K__ 
2106                                                         if ( sect
->size 
> offsetof(DATAdyld
, dyldLazyBinder
) ) { 
2107                                                                 if ( dd
->dyldLazyBinder 
!= (void*)&stub_binding_helper 
) 
2108                                                                         dd
->dyldLazyBinder 
= (void*)&stub_binding_helper
; 
2110                                 #endif // !__arm64__ 
2111                                                         // <rdar://problem/40352925> Add work around for existing apps that have deprecated __dyld section 
2112                                                         const char* installNm 
= this->getInstallPath(); 
2113                                                         if ( (mh
->filetype 
!= MH_DYLIB
) || (installNm 
== NULL
) || (strcmp(installNm
, libDyldPath(context
)) != 0) ) { 
2115                                                                 // don't allow macOS apps build with 10.14 or later SDK and targeting 10.8 or later to have a __dyld section 
2116                                                                 if ( (minOSVersion() >= 0x000a0800) && (sdkVersion() >= 0x000a0e00) ) 
2117                                                                         dyld::throwf("__dyld section not supported in %s", this->getPath()); 
2119                                                 #if TARGET_OS_IOS || TARGET_OS_TV 
2120                                                                 // don't allow iOS apps build with 12.0 or later SDK to have a __dyld section 
2121                                                                 if ( sdkVersion() >= 0x000c0000 ) 
2122                                                                         dyld::throwf("__dyld section not supported in %s", this->getPath()); 
2125                                                                 if ( sdkVersion() >= 0x00050000 ) 
2126                                                                         dyld::throwf("__dyld section not supported in %s", this->getPath()); 
2129                                                         if ( sect
->size 
> offsetof(DATAdyld
, dyldFuncLookup
) ) { 
2130                                                                 if ( dd
->dyldFuncLookup 
!= (void*)&_dyld_func_lookup 
) 
2131                                                                         dd
->dyldFuncLookup 
= (void*)&_dyld_func_lookup
; 
2133                                                         if ( mh
->filetype 
== MH_EXECUTE 
) { 
2134                                                                 // there are two ways to get the program variables 
2135                                                                 if ( (sect
->size 
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh 
== mh
) ) { 
2136                                                                         // some really old binaries have space for vars, but it is zero filled 
2137                                                                         // main executable has 10.5 style __dyld section that has program variable pointers 
2138                                                                         context
.setNewProgramVars(dd
->vars
); 
2141                                                                         // main executable is pre-10.5 and requires the symbols names to be looked up 
2142                                                                         this->lookupProgramVars(context
); 
2143                                 #if SUPPORT_OLD_CRT_INITIALIZATION 
2144                                                                         // If the first 16 bytes of the entry point's instructions do not  
2145                                                                         // match what crt1.o supplies, then the program has a custom entry point. 
2146                                                                         // This means it might be doing something that needs to be executed before  
2147                                                                         // initializers are run.  
2148                                                                         if ( memcmp(this->getEntryFromLC_UNIXTHREAD(), sStandardEntryPointInstructions
, 16) != 0 ) { 
2149                                                                                 if ( context
.verboseInit 
) 
2150                                                                                         dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n"); 
2151                                                                                 context
.setRunInitialzersOldWay(); 
2156                                                         else if ( mh
->filetype 
== MH_DYLIB 
) { 
2157                                                                 const char* installPath 
= this->getInstallPath(); 
2158                                                                 if ( (installPath 
!= NULL
) && ((strncmp(installPath
, "/usr/lib/", 9) == 0) || (strncmp(installPath
, "/System/DriverKit/usr/lib/", 26) == 0)) ) { 
2159                                                                         if ( sect
->size 
> offsetof(DATAdyld
, vars
) ) { 
2160                                                                                 // use ProgramVars from libdyld.dylib but tweak mh field to correct value 
2161                                                                                 dd
->vars
.mh 
= context
.mainExecutable
->machHeader(); 
2162                                                                                 context
.setNewProgramVars(dd
->vars
); 
2167                                                 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype 
== MH_EXECUTE
) ) { 
2168                                                         // this is a Mac OS X 10.6 or later main executable  
2169                                                         struct ProgramVars
* pv 
= (struct ProgramVars
*)(sect
->addr 
+ fSlide
); 
2170                                                         context
.setNewProgramVars(*pv
); 
2175                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2181 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const 
2183         ProgramVars vars 
= context
.programVars
; 
2184         const ImageLoader::Symbol
* sym
; 
2186         // get mach header directly 
2187         vars
.mh 
= (macho_header
*)fMachOData
; 
2190         sym 
= this->findShallowExportedSymbol("_NXArgc", NULL
); 
2192                 vars
.NXArgcPtr 
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
); 
2195         sym 
= this->findShallowExportedSymbol("_NXArgv", NULL
); 
2197                 vars
.NXArgvPtr 
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
); 
2200         sym 
= this->findShallowExportedSymbol("_environ", NULL
); 
2202                 vars
.environPtr 
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
); 
2204         // lookup __progname 
2205         sym 
= this->findShallowExportedSymbol("___progname", NULL
); 
2207                 vars
.__prognamePtr 
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
); 
2209         context
.setNewProgramVars(vars
); 
2213 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const 
2215         // dylibs in dyld cache do not need to be rebased or bound 
2216         // for chained fixups always pretend dylib is up to date, patch tables will be used later 
2217         if ( fInSharedCache 
&& (this->allDependentLibrariesAsWhenPreBound() || context
.dyldCache
->header
.builtFromChainedFixups
) ) { 
2218                 // allow environment variables to disable prebinding 
2219                 if ( context
.bindFlat 
) 
2221                 switch ( context
.prebindUsage 
) { 
2222                         case kUseAllPrebinding
: 
2224                         case kUseSplitSegPrebinding
: 
2225                                 return this->fIsSplitSeg
; 
2226                         case kUseAllButAppPredbinding
: 
2227                                 return (this != context
.mainExecutable
); 
2228                         case kUseNoPrebinding
: 
2235 static void *stripPointer(void *ptr
) { 
2236 #if __has_feature(ptrauth_calls) 
2237     return __builtin_ptrauth_strip(ptr
, ptrauth_key_asia
); 
2244 void ImageLoaderMachO::doImageInit(const LinkContext
& context
) 
2246         if ( fHasDashInit 
) { 
2247                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2248                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2249                 const struct load_command
* cmd 
= cmds
; 
2250                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2252                                 case LC_ROUTINES_COMMAND
: 
2253                                         Initializer func 
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address 
+ fSlide
); 
2254 #if __has_feature(ptrauth_calls) 
2255                                         func 
= (Initializer
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0); 
2257                                         // <rdar://problem/8543820&9228031> verify initializers are in image 
2258                                         if ( ! this->containsAddress(stripPointer((void*)func
)) ) { 
2259                                                 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath()); 
2261                                         if ( ! dyld::gProcessInfo
->libSystemInitialized 
) { 
2262                                                 // <rdar://problem/17973316> libSystem initializer must run first 
2263                                                 dyld::throwf("-init function in image (%s) that does not link with libSystem.dylib\n", this->getPath()); 
2265                                         if ( context
.verboseInit 
) 
2266                                                 dyld::log("dyld: calling -init function %p in %s\n", func
, this->getPath()); 
2268                                                 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)fMachOData
, (uint64_t)func
, 0); 
2269                                                 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
); 
2273                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2278 static const char* libSystemPath(const ImageLoader::LinkContext
& context
) 
2281         if ( context
.driverKit 
) 
2282                 return DRIVERKIT_LIBSYSTEM_DYLIB_PATH
; 
2285         return LIBSYSTEM_DYLIB_PATH
; 
2290 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
) 
2292         if ( fHasInitializers 
) { 
2293                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2294                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2295                 const struct load_command
* cmd 
= cmds
; 
2296                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2297                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
2298                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2299                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2300                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2301                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2302                                         const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2303                                         if ( type 
== S_MOD_INIT_FUNC_POINTERS 
) { 
2304                                                 Initializer
* inits 
= (Initializer
*)(sect
->addr 
+ fSlide
); 
2305                                                 const size_t count 
= sect
->size 
/ sizeof(uintptr_t); 
2306                                                 // <rdar://problem/23929217> Ensure __mod_init_func section is within segment 
2307                                                 if ( (sect
->addr 
< seg
->vmaddr
) || (sect
->addr
+sect
->size 
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size 
< sect
->addr
) ) 
2308                                                         dyld::throwf("__mod_init_funcs section has malformed address range for %s\n", this->getPath()); 
2309                                                 for (size_t j
=0; j 
< count
; ++j
) { 
2310                                                         Initializer func 
= inits
[j
]; 
2311                                                         // <rdar://problem/8543820&9228031> verify initializers are in image 
2312                                                         if ( ! this->containsAddress(stripPointer((void*)func
)) ) { 
2313                                                                 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath()); 
2315                                                         if ( ! dyld::gProcessInfo
->libSystemInitialized 
) { 
2316                                                                 // <rdar://problem/17973316> libSystem initializer must run first 
2317                                                                 const char* installPath 
= getInstallPath(); 
2318                                                                 if ( (installPath 
== NULL
) || (strcmp(installPath
, libSystemPath(context
)) != 0) ) 
2319                                                                         dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath()); 
2321                                                         if ( context
.verboseInit 
) 
2322                                                                 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath()); 
2323                                                         bool haveLibSystemHelpersBefore 
= (dyld::gLibSystemHelpers 
!= NULL
); 
2325                                                                 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)fMachOData
, (uint64_t)func
, 0); 
2326                                                                 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
); 
2328                                                         bool haveLibSystemHelpersAfter 
= (dyld::gLibSystemHelpers 
!= NULL
); 
2329                                                         if ( !haveLibSystemHelpersBefore 
&& haveLibSystemHelpersAfter 
) { 
2330                                                                 // now safe to use malloc() and other calls in libSystem.dylib 
2331                                                                 dyld::gProcessInfo
->libSystemInitialized 
= true; 
2335                                         else if ( type 
== S_INIT_FUNC_OFFSETS 
) { 
2336                                                 const uint32_t* inits 
= (uint32_t*)(sect
->addr 
+ fSlide
); 
2337                                                 const size_t count 
= sect
->size 
/ sizeof(uint32_t); 
2338                                                 // Ensure section is within segment 
2339                                                 if ( (sect
->addr 
< seg
->vmaddr
) || (sect
->addr
+sect
->size 
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size 
< sect
->addr
) ) 
2340                                                         dyld::throwf("__init_offsets section has malformed address range for %s\n", this->getPath()); 
2341                                                 if ( seg
->initprot 
& VM_PROT_WRITE 
) 
2342                                                         dyld::throwf("__init_offsets section is not in read-only segment %s\n", this->getPath()); 
2343                                                 for (size_t j
=0; j 
< count
; ++j
) { 
2344                                                         uint32_t funcOffset 
= inits
[j
]; 
2345                                                         // verify initializers are in image 
2346                                                         if ( ! this->containsAddress((uint8_t*)this->machHeader() + funcOffset
) ) { 
2347                                                                 dyld::throwf("initializer function offset 0x%08X not in mapped image for %s\n", funcOffset
, this->getPath()); 
2349                                                         if ( ! dyld::gProcessInfo
->libSystemInitialized 
) { 
2350                                                                 // <rdar://problem/17973316> libSystem initializer must run first 
2351                                                                 const char* installPath 
= getInstallPath(); 
2352                                                                 if ( (installPath 
== NULL
) || (strcmp(installPath
, libSystemPath(context
)) != 0) ) 
2353                                                                         dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath()); 
2355                             Initializer func 
= (Initializer
)((uint8_t*)this->machHeader() + funcOffset
); 
2356                                                         if ( context
.verboseInit 
) 
2357                                                                 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath()); 
2358 #if __has_feature(ptrauth_calls) 
2359                                                         func 
= (Initializer
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0); 
2361                                                         bool haveLibSystemHelpersBefore 
= (dyld::gLibSystemHelpers 
!= NULL
); 
2363                                                                 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)fMachOData
, (uint64_t)func
, 0); 
2364                                 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
); 
2366                                                         bool haveLibSystemHelpersAfter 
= (dyld::gLibSystemHelpers 
!= NULL
); 
2367                                                         if ( !haveLibSystemHelpersBefore 
&& haveLibSystemHelpersAfter 
) { 
2368                                                                 // now safe to use malloc() and other calls in libSystem.dylib 
2369                                                                 dyld::gProcessInfo
->libSystemInitialized 
= true; 
2375                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2382 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
) 
2384         if ( fHasDOFSections 
) { 
2385                 // walk load commands (mapped in at start of __TEXT segment) 
2386                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2387                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2388                 const struct load_command
* cmd 
= cmds
; 
2389                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2391                                 case LC_SEGMENT_COMMAND
: 
2393                                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2394                                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2395                                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2396                                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2397                                                         if ( (sect
->flags 
& SECTION_TYPE
) == S_DTRACE_DOF 
) { 
2398                                                                 // <rdar://problem/23929217> Ensure section is within segment 
2399                                                                 if ( (sect
->addr 
< seg
->vmaddr
) || (sect
->addr
+sect
->size 
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size 
< sect
->addr
) ) 
2400                                                                         dyld::throwf("DOF section has malformed address range for %s\n", this->getPath()); 
2401                                                                 ImageLoader::DOFInfo info
; 
2402                                                                 info
.dof                        
= (void*)(sect
->addr 
+ fSlide
); 
2403                                                                 info
.imageHeader        
= this->machHeader(); 
2404                                                                 info
.imageShortName 
= this->getShortName(); 
2405                                                                 dofs
.push_back(info
); 
2411                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2417 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
) 
2419         CRSetCrashLogMessage2(this->getPath()); 
2421         // mach-o has -init and static initializers 
2422         doImageInit(context
); 
2423         doModInitFunctions(context
); 
2425         CRSetCrashLogMessage2(NULL
); 
2427         return (fHasDashInit 
|| fHasInitializers
); 
2430 bool ImageLoaderMachO::needsInitialization() 
2432         return ( fHasDashInit 
|| fHasInitializers 
); 
2436 bool ImageLoaderMachO::needsTermination() 
2438         return fHasTerminators
; 
2442 void ImageLoaderMachO::doTermination(const LinkContext
& context
) 
2444         if ( fHasTerminators 
) { 
2445                 const uint32_t cmd_count 
= ((macho_header
*)fMachOData
)->ncmds
; 
2446                 const struct load_command
* const cmds 
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)]; 
2447                 const struct load_command
* cmd 
= cmds
; 
2448                 for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2449                         if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
2450                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2451                                 const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2452                                 const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2453                                 for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2454                                         const uint8_t type 
= sect
->flags 
& SECTION_TYPE
; 
2455                                         if ( type 
== S_MOD_TERM_FUNC_POINTERS 
) { 
2456                                                 // <rdar://problem/23929217> Ensure section is within segment 
2457                                                 if ( (sect
->addr 
< seg
->vmaddr
) || (sect
->addr
+sect
->size 
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size 
< sect
->addr
) ) 
2458                                                         dyld::throwf("DOF section has malformed address range for %s\n", this->getPath()); 
2459                                                 Terminator
* terms 
= (Terminator
*)(sect
->addr 
+ fSlide
); 
2460                                                 const size_t count 
= sect
->size 
/ sizeof(uintptr_t); 
2461                                                 for (size_t j
=count
; j 
> 0; --j
) { 
2462                                                         Terminator func 
= terms
[j
-1]; 
2463 #if __has_feature(ptrauth_calls) 
2464                                                         func 
= (Terminator
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0); 
2466                                                         // <rdar://problem/8543820&9228031> verify terminators are in image 
2467                                                         if ( ! this->containsAddress(stripPointer((void*)func
)) ) { 
2468                                                                 dyld::throwf("termination function %p not in mapped image for %s\n", func
, this->getPath()); 
2470                                                         if ( context
.verboseInit 
) 
2471                                                                 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath()); 
2477                         cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2483 void ImageLoaderMachO::printStatisticsDetails(unsigned int imageCount
, const InitializerTimingList
& timingInfo
) 
2485         ImageLoader::printStatisticsDetails(imageCount
, timingInfo
); 
2486         dyld::log("total symbol trie searches:    %d\n", fgSymbolTrieSearchs
); 
2487         dyld::log("total symbol table binary searches:    %d\n", fgSymbolTableBinarySearchs
); 
2488         dyld::log("total images defining weak symbols:  %u\n", fgImagesHasWeakDefinitions
); 
2489         dyld::log("total images using weak symbols:  %u\n", fgImagesRequiringCoalescing
); 
2492 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
, size_t extraAllocationSize
) 
2494         // preflight and calculate slide if needed 
2495         const bool inPIE 
= (fgNextPIEDylibAddress 
!= 0); 
2497         if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) { 
2498                 intptr_t segmentReAlignSlide 
= 0; 
2499                 bool needsToSlide 
= false; 
2500                 bool imageHasPreferredLoadAddress 
= segHasPreferredLoadAddress(0); 
2501                 uintptr_t lowAddr 
= (unsigned long)(-1); 
2502                 uintptr_t highAddr 
= 0; 
2503                 for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2504                         const uintptr_t segLow 
= segPreferredLoadAddress(i
); 
2505                         const uintptr_t segHigh 
= dyld_page_round(segLow 
+ segSize(i
)); 
2506                         if ( segLow 
< highAddr 
) { 
2507                                 if ( dyld_page_size 
> 4096 ) 
2508                                         dyld::throwf("can't map segments into 16KB pages"); 
2510                                         dyld::throwf("overlapping segments"); 
2512                         if ( segLow 
< lowAddr 
) 
2514                         if ( segHigh 
> highAddr 
) 
2517 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR 
2518                         // For Cambria on Aruba systems (16k page size), realign the image so the first segment ends on a 16k boundry. 
2519                         // FIXME: this can be removed when Aruba dev systems are no longer supported. 
2520                         if ( dyld::isTranslated() && vm_page_size 
== 0x4000 && i 
== 0 && segLow 
== 0 ) { 
2521                                 const uintptr_t segHighPageOffset 
= segHigh 
& vm_page_mask
; 
2522                                 if ( segHighPageOffset 
> 0 ) { 
2523                                         // Adjust the slide to make the first segment end on a page boundry. 
2524                                         needsToSlide 
= true; 
2525                                         segmentReAlignSlide 
= vm_page_size 
- segHighPageOffset
; 
2527                                         if (context
.verboseMapping
) { 
2528                                                 dyld::log("dyld: Image %s first segment(%s) does not end on a page boundry [0x%lx, 0x%lx) adding 0x%lx to slide to realign\n", getPath(), segName(i
), segLow
, segHigh
, segmentReAlignSlide
); 
2533                         if ( needsToSlide 
|| !imageHasPreferredLoadAddress 
|| inPIE 
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) ) 
2534                                 needsToSlide 
= true; 
2536                 if ( needsToSlide 
) { 
2537                         // find a chunk of address space to hold all segments 
2538                         size_t size 
= highAddr
-lowAddr
+segmentReAlignSlide
; 
2539                         uintptr_t addr 
= reserveAnAddressRange(size
+extraAllocationSize
, context
); 
2540                         slide 
= addr 
- lowAddr 
+ segmentReAlignSlide
; 
2541                 } else if ( extraAllocationSize 
) { 
2542                         if (!reserveAddressRange(highAddr
, extraAllocationSize
)) { 
2543                                 throw "failed to reserve space for aot"; 
2547         else if ( ! this->segmentsCanSlide() ) { 
2548                 uintptr_t highAddr 
= 0; 
2549                 for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2550                         const uintptr_t segLow 
= segPreferredLoadAddress(i
); 
2551                         const uintptr_t segHigh 
= dyld_page_round(segLow 
+ segSize(i
)); 
2553                         if ( segHigh 
> highAddr 
) 
2556                         if ( (strcmp(segName(i
), "__PAGEZERO") == 0) && (segFileSize(i
) == 0) && (segPreferredLoadAddress(i
) == 0) ) 
2558                         if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) ) 
2559                                 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
)); 
2561                 if (extraAllocationSize
) { 
2562                         dyld::throwf("binaries with non-slidable segments don't support aot: %s", this->getPath()); 
2566                 throw "mach-o does not support independently sliding segments"; 
2572 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
) 
2574         vm_address_t addr 
= 0; 
2575         vm_size_t size 
= length
; 
2576         // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either 
2577         if ( fgNextPIEDylibAddress 
!= 0 ) { 
2578                  // add small (0-3 pages) random padding between dylibs 
2579                 addr 
= fgNextPIEDylibAddress 
+ (__stack_chk_guard
/fgNextPIEDylibAddress 
& (sizeof(long)-1))*dyld_page_size
; 
2580                 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard)); 
2581                 kern_return_t r 
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED 
| VM_MAKE_TAG(VM_MEMORY_DYLIB
)); 
2582                 if ( r 
== KERN_SUCCESS 
) { 
2583                         fgNextPIEDylibAddress 
= addr 
+ size
; 
2586                 fgNextPIEDylibAddress 
= 0; 
2588         kern_return_t r 
= vm_alloc(&addr
, size
, VM_FLAGS_ANYWHERE 
| VM_MAKE_TAG(VM_MEMORY_DYLIB
)); 
2589         if ( r 
!= KERN_SUCCESS 
)  
2590                 throw "out of address space"; 
2595 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
) 
2597         vm_address_t addr 
= start
; 
2598         vm_size_t size 
= length
; 
2599         kern_return_t r 
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED 
| VM_MAKE_TAG(VM_MEMORY_DYLIB
)); 
2600         if ( r 
!= KERN_SUCCESS 
)  
2605 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
) 
2607         uint64_t extra_allocation_size 
= 0; 
2609 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR 
2610         if (dyld::isTranslated()) { 
2611                 fAotPath 
= new char[PATH_MAX
]; 
2612                 int ret 
= syscall(0x7000001, fd
, this->getPath(), &extra_allocation_size
, fAotPath
, PATH_MAX
); 
2620         // find address range for image 
2621         intptr_t slide 
= this->assignSegmentAddresses(context
, extra_allocation_size
); 
2622         if ( context
.verboseMapping 
) { 
2623                 if ( offsetInFat 
!= 0 ) 
2624                         dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat
); 
2626                         dyld::log("dyld: Mapping %s\n", this->getPath()); 
2629         // <rdar://problem/47163421> speculatively read whole slice 
2630         fspecread_t specread 
= {} ; 
2631         specread
.fsr_offset 
= offsetInFat
; 
2632         specread
.fsr_length 
= lenInFat
; 
2633         specread
.fsr_flags  
= 0; 
2634         fcntl(fd
, F_SPECULATIVE_READ
, &specread
); 
2635         if ( context
.verboseMapping 
) 
2636                 dyld::log("dyld: Speculatively read offset=0x%08llX, len=0x%08llX, path=%s\n", offsetInFat
, lenInFat
, this->getPath()); 
2638         // map in all segments 
2639         uintptr_t baseAddress 
= (unsigned long)(-1); 
2640         uintptr_t endAddress 
= 0; 
2641         uintptr_t mappedMachHeaderAddress 
= 0; 
2642         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2643                 vm_offset_t fileOffset 
= (vm_offset_t
)(segFileOffset(i
) + offsetInFat
); 
2644                 vm_size_t size 
= segFileSize(i
); 
2645                 uintptr_t requestedLoadAddress 
= segPreferredLoadAddress(i
) + slide
; 
2646                 const uintptr_t segmentEnd 
= dyld_page_round(requestedLoadAddress 
+ segSize(i
)); 
2648                 if ( requestedLoadAddress 
< baseAddress 
) 
2649                         baseAddress 
= requestedLoadAddress
; 
2650                 if ( segmentEnd 
> endAddress 
) 
2651                         endAddress 
= segmentEnd
; 
2653                 if (segFileOffset(i
) == 0 && segFileSize(i
) != 0) { 
2654                         mappedMachHeaderAddress 
= requestedLoadAddress
; 
2658                 if ( !segUnaccessible(i
) ) { 
2659                         if ( segExecutable(i
) ) 
2660                                 protection   
|= PROT_EXEC
; 
2661                         if ( segReadable(i
) ) 
2662                                 protection   
|= PROT_READ
; 
2663                         if ( segWriteable(i
) ) { 
2664                                 protection   
|= PROT_WRITE
; 
2665                                 // rdar://problem/22525618 force __LINKEDIT to always be mapped read-only 
2666                                 if ( strcmp(segName(i
), "__LINKEDIT") == 0 ) 
2667                                         protection 
= PROT_READ
; 
2671                 // initially map __IMPORT segments R/W so dyld can update them 
2672                 if ( segIsReadOnlyImport(i
) ) 
2673                         protection 
|= PROT_WRITE
; 
2675                 // wholly zero-fill segments have nothing to mmap() in 
2677                         if ( (fileOffset
+size
) > fileLen 
) { 
2678                                 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",  
2679                                                                 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
); 
2681                         void* loadAddress 
= xmmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED 
| MAP_PRIVATE
, fd
, fileOffset
); 
2682                         if ( loadAddress 
== ((void*)(-1)) ) { 
2683                                 int mmapErr 
= errno
; 
2684                                 if ( mmapErr 
== EPERM 
) { 
2685                                         if ( dyld::sandboxBlockedMmap(getPath()) ) 
2686                                                 dyld::throwf("file system sandbox blocked mmap() of '%s'", this->getPath()); 
2688                                                 dyld::throwf("code signing blocked mmap() of '%s'", this->getPath()); 
2691                                         dyld::throwf("mmap() errno=%d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s", 
2692                                                 mmapErr
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath()); 
2696                 ++ImageLoader::fgTotalSegmentsMapped
; 
2697                 ImageLoader::fgTotalBytesMapped 
+= size
; 
2698                 if ( context
.verboseMapping 
) 
2699                         dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1, 
2700                                 (protection 
& PROT_READ
) ? 'r' : '.',  (protection 
& PROT_WRITE
) ? 'w' : '.',  (protection 
& PROT_EXEC
) ? 'x' : '.' ); 
2703 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR 
2704         if (dyld::isTranslated() && extra_allocation_size 
!= 0) { 
2705                 const struct mach_header
* aot_load_address
; 
2706                 dyld_aot_image_info aot_image_info 
= {}; 
2707                 int ret 
= syscall(0x7000002, this->getPath(), mappedMachHeaderAddress
, endAddress
, &aot_load_address
, &aot_image_info
.aotImageSize
, aot_image_info
.aotImageKey
); 
2709                         extern void addAotImagesToAllAotImages(uint32_t aotInfoCount
, const dyld_aot_image_info aotInfo
[]); 
2711                         // fill in the aot load address, at this point the cambria trap has filled in 
2712                         // the image size and image key fields 
2713                         aot_image_info
.aotLoadAddress 
= aot_load_address
; 
2714                         aot_image_info
.x86LoadAddress 
= (struct mach_header
*)baseAddress
; 
2716                         addAotImagesToAllAotImages(1, &aot_image_info
); 
2721         // update slide to reflect load location                         
2722         this->setSlide(slide
); 
2725 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
) 
2727         // find address range for image 
2728         intptr_t slide 
= this->assignSegmentAddresses(context
, 0); 
2729         if ( context
.verboseMapping 
) 
2730                 dyld::log("dyld: Mapping memory %p\n", memoryImage
); 
2731         // map in all segments 
2732         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2733                 vm_address_t loadAddress 
= segPreferredLoadAddress(i
) + slide
; 
2734                 vm_address_t srcAddr 
= (uintptr_t)memoryImage 
+ segFileOffset(i
); 
2735                 vm_size_t size 
= segFileSize(i
); 
2736                 kern_return_t r 
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
); 
2737                 if ( r 
!= KERN_SUCCESS 
)  
2738                         throw "can't map segment"; 
2739                 if ( context
.verboseMapping 
) 
2740                         dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1); 
2742         // update slide to reflect load location                         
2743         this->setSlide(slide
); 
2744         // set R/W permissions on all segments at slide location 
2745         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
2746                 segProtect(i
, context
); 
2750 static vm_prot_t 
protectionForSegIndex(const ImageLoaderMachO
* image
, unsigned int segIndex
) 
2752         if ( image
->segUnaccessible(segIndex
) ) 
2754         vm_prot_t protection 
= 0; 
2755         if ( image
->segExecutable(segIndex
) ) 
2756                 protection 
|= PROT_EXEC
; 
2757         if ( image
->segReadable(segIndex
) ) 
2758                 protection 
|= PROT_READ
; 
2759         if ( image
->segWriteable(segIndex
) ) 
2760                 protection 
|= PROT_WRITE
; 
2765 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
) 
2767         vm_prot_t protection 
= protectionForSegIndex(this, segIndex
); 
2768         vm_address_t addr 
= segActualLoadAddress(segIndex
); 
2769         vm_size_t size 
= segSize(segIndex
); 
2771 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR 
2772         if ( dyld::isTranslated() ) { 
2773                 // <rdar://problem/60543794> can't vm_protect non-16KB segments 
2774                 if ( (segIndex 
> 0) && ((addr 
& 0x3FFF) != 0) ) { 
2775                         // overlaps previous segment 
2776                         vm_prot_t prevProt 
= protectionForSegIndex(this, segIndex
-1); 
2777                         if ( (protection 
& prevProt
) != prevProt 
) { 
2778                                 // previous had more bits, so we need to not apply new permissions to the overlap 
2779                                 vm_size_t overlap 
= 0x4000 - (addr 
& 0x3FFF); 
2781                                 if ( size 
>= overlap 
) 
2783                                 else if ( size 
< overlap 
) 
2792         const bool setCurrentPermissions 
= false; 
2793         kern_return_t r 
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
); 
2794         if ( r 
!= KERN_SUCCESS 
) { 
2795         dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s", 
2796             (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath()); 
2798         if ( context
.verboseMapping 
) { 
2799                 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, 
2800                         (protection 
& PROT_READ
) ? 'r' : '.',  (protection 
& PROT_WRITE
) ? 'w' : '.',  (protection 
& PROT_EXEC
) ? 'x' : '.' ); 
2804 #if TEXT_RELOC_SUPPORT 
2805 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
) 
2807         vm_address_t addr 
= segActualLoadAddress(segIndex
); 
2808         vm_size_t size 
= segSize(segIndex
); 
2809         const bool setCurrentPermissions 
= false; 
2810         vm_prot_t protection 
= VM_PROT_WRITE 
| VM_PROT_READ 
| VM_PROT_COPY
; 
2811         if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) ) 
2812                 protection 
|= VM_PROT_EXECUTE
; 
2813         kern_return_t r 
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
); 
2814         if ( r 
!= KERN_SUCCESS 
) { 
2815         dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s", 
2816             (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath()); 
2818         if ( context
.verboseMapping 
) { 
2819                 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, 
2820                         (protection 
& PROT_READ
) ? 'r' : '.',  (protection 
& PROT_WRITE
) ? 'w' : '.',  (protection 
& PROT_EXEC
) ? 'x' : '.' ); 
2825 const char* ImageLoaderMachO::findClosestSymbol(const mach_header
* mh
, const void* addr
, const void** closestAddr
) 
2827         // called by dladdr() 
2828         // only works with compressed LINKEDIT if classic symbol table is also present 
2829         const dysymtab_command
* dynSymbolTable 
= NULL
; 
2830         const symtab_command
* symtab 
= NULL
; 
2831         const macho_segment_command
* seg
; 
2832         const uint8_t* unslidLinkEditBase 
= NULL
; 
2833         bool linkEditBaseFound 
= false; 
2835         const uint32_t cmd_count 
= mh
->ncmds
; 
2836         const load_command
* const cmds 
= (load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
2837         const load_command
* cmd 
= cmds
; 
2838         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2840                         case LC_SEGMENT_COMMAND
: 
2841                                 seg 
= (macho_segment_command
*)cmd
; 
2842                                 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 ) { 
2843                                         unslidLinkEditBase 
= (uint8_t*)(seg
->vmaddr 
- seg
->fileoff
); 
2844                                         linkEditBaseFound 
= true; 
2846                                 else if ( strcmp(seg
->segname
, "__TEXT") == 0 ) { 
2847                                         slide 
= (uintptr_t)mh 
- seg
->vmaddr
; 
2851                                 symtab 
= (symtab_command
*)cmd
; 
2854                                 dynSymbolTable 
= (dysymtab_command
*)cmd
; 
2857                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2859         // no symbol table => no lookup by address 
2860         if ( (symtab 
== NULL
) || (dynSymbolTable 
== NULL
) || !linkEditBaseFound 
) 
2863         const uint8_t* linkEditBase 
= unslidLinkEditBase 
+ slide
; 
2864         const char* symbolTableStrings 
= (const char*)&linkEditBase
[symtab
->stroff
]; 
2865         const macho_nlist
* symbolTable 
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]); 
2867         uintptr_t targetAddress 
= (uintptr_t)addr 
- slide
; 
2868         const struct macho_nlist
* bestSymbol 
= NULL
; 
2869         // first walk all global symbols 
2870         const struct macho_nlist
* const globalsStart 
= &symbolTable
[dynSymbolTable
->iextdefsym
]; 
2871         const struct macho_nlist
* const globalsEnd
= &globalsStart
[dynSymbolTable
->nextdefsym
]; 
2872         for (const struct macho_nlist
* s 
= globalsStart
; s 
< globalsEnd
; ++s
) { 
2873                 if ( (s
->n_type 
& N_TYPE
) == N_SECT 
) { 
2874                         if ( bestSymbol 
== NULL 
) { 
2875                                 if ( s
->n_value 
<= targetAddress 
) 
2878                         else if ( (s
->n_value 
<= targetAddress
) && (bestSymbol
->n_value 
< s
->n_value
) ) { 
2883         // next walk all local symbols 
2884         const struct macho_nlist
* const localsStart 
= &symbolTable
[dynSymbolTable
->ilocalsym
]; 
2885         const struct macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nlocalsym
]; 
2886         for (const struct macho_nlist
* s 
= localsStart
; s 
< localsEnd
; ++s
) { 
2887                 if ( ((s
->n_type 
& N_TYPE
) == N_SECT
) && ((s
->n_type 
& N_STAB
) == 0) ) { 
2888                         if ( bestSymbol 
== NULL 
) { 
2889                                 if ( s
->n_value 
<= targetAddress 
) 
2892                         else if ( (s
->n_value 
<= targetAddress
) && (bestSymbol
->n_value 
< s
->n_value
) ) { 
2897         if ( bestSymbol 
!= NULL 
) { 
2899                 if (bestSymbol
->n_desc 
& N_ARM_THUMB_DEF
) 
2900                         *closestAddr 
= (void*)((bestSymbol
->n_value 
| 1) + slide
); 
2902                         *closestAddr 
= (void*)(bestSymbol
->n_value 
+ slide
); 
2904                 *closestAddr 
= (void*)(bestSymbol
->n_value 
+ slide
); 
2906                 return &symbolTableStrings
[bestSymbol
->n_un
.n_strx
]; 
2911 bool ImageLoaderMachO::getLazyBindingInfo(uint32_t& lazyBindingInfoOffset
, const uint8_t* lazyInfoStart
, const uint8_t* lazyInfoEnd
, 
2912                                                                                                         uint8_t* segIndex
, uintptr_t* segOffset
, int* ordinal
, const char** symbolName
, bool* doneAfterBind
) 
2914         if ( lazyBindingInfoOffset 
> (lazyInfoEnd
-lazyInfoStart
) ) 
2917         const uint8_t* p 
= &lazyInfoStart
[lazyBindingInfoOffset
]; 
2918         while ( !done 
&& (p 
< lazyInfoEnd
) ) { 
2919                 uint8_t immediate 
= *p 
& BIND_IMMEDIATE_MASK
; 
2920                 uint8_t opcode 
= *p 
& BIND_OPCODE_MASK
; 
2923                         case BIND_OPCODE_DONE
: 
2924                                 *doneAfterBind 
= false; 
2927                         case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
: 
2928                                 *ordinal 
= immediate
; 
2930                         case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
: 
2931                                 *ordinal 
= (int)read_uleb128(p
, lazyInfoEnd
); 
2933                         case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
: 
2934                                 // the special ordinals are negative numbers 
2935                                 if ( immediate 
== 0 ) 
2938                                         int8_t signExtended 
= BIND_OPCODE_MASK 
| immediate
; 
2939                                         *ordinal 
= signExtended
; 
2942                         case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
: 
2943                                 *symbolName 
= (char*)p
; 
2948                         case BIND_OPCODE_SET_TYPE_IMM
: 
2950                         case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
: 
2951                                 *segIndex  
= immediate
; 
2952                                 *segOffset 
= read_uleb128(p
, lazyInfoEnd
); 
2954                         case BIND_OPCODE_DO_BIND
: 
2955                                 *doneAfterBind 
= ((*p 
& BIND_OPCODE_MASK
) == BIND_OPCODE_DONE
); 
2956                                 lazyBindingInfoOffset 
+= p 
- &lazyInfoStart
[lazyBindingInfoOffset
]; 
2959                         case BIND_OPCODE_SET_ADDEND_SLEB
: 
2960                         case BIND_OPCODE_ADD_ADDR_ULEB
: 
2961                         case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
: 
2962                         case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
: 
2963                         case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
: 
2971 const dyld_info_command
* ImageLoaderMachO::findDyldInfoLoadCommand(const mach_header
* mh
) 
2973         const uint32_t cmd_count 
= mh
->ncmds
; 
2974         const load_command
* const cmds 
= (load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
2975         const load_command
* cmd 
= cmds
; 
2976         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2979                         case LC_DYLD_INFO_ONLY
: 
2980                                 return (dyld_info_command
*)cmd
; 
2982                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2988 uintptr_t ImageLoaderMachO::segPreferredAddress(const mach_header
* mh
, unsigned segIndex
) 
2990         const uint32_t cmd_count 
= mh
->ncmds
; 
2991         const load_command
* const cmds 
= (load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
2992         const load_command
* cmd 
= cmds
; 
2993         unsigned curSegIndex 
= 0; 
2994         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2995                 if ( cmd
->cmd 
== LC_SEGMENT_COMMAND 
) { 
2996                         if ( segIndex 
== curSegIndex 
) { 
2997                                 const macho_segment_command
* segCmd 
= (macho_segment_command
*)cmd
; 
2998                                 return segCmd
->vmaddr
; 
3002                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
3009 uintptr_t ImageLoaderMachO::imageBaseAddress() const { 
3010     //printf("imageBaseAddress: %s %d->%d\n", getPath(), 0, segmentCount()); 
3011     for (unsigned int i 
= 0, e 
= segmentCount(); i 
!= e
; ++i
) { 
3012         if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) 
3013             return segPreferredLoadAddress(i
);