1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2013 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@ 
  34 #include <sys/param.h> 
  35 #include <mach/mach_time.h> // mach_absolute_time() 
  36 #include <mach/mach_init.h>  
  37 #include <sys/types.h> 
  39 #include <sys/syscall.h> 
  40 #include <sys/socket.h> 
  42 #include <sys/syslog.h> 
  44 #include <mach/mach.h> 
  45 #include <mach-o/fat.h> 
  46 #include <mach-o/loader.h>  
  47 #include <mach-o/ldsyms.h>  
  48 #include <libkern/OSByteOrder.h>  
  49 #include <libkern/OSAtomic.h> 
  50 #include <mach/mach.h> 
  51 #include <sys/sysctl.h> 
  53 #include <sys/dtrace.h> 
  54 #include <libkern/OSAtomic.h> 
  55 #include <Availability.h> 
  56 #include <System/sys/codesign.h> 
  57 #include <System/sys/csr.h> 
  59 #include <os/lock_private.h> 
  60 #include <System/machine/cpu_capabilities.h> 
  61 #include <System/sys/reason.h> 
  62 #include <kern/kcdata.h> 
  64 #include <sys/fsgetpath.h> 
  65 #include <System/sys/content_protection.h> 
  67 #if TARGET_OS_SIMULATOR 
  69                 AMFI_DYLD_INPUT_PROC_IN_SIMULATOR 
= (1 << 0), 
  71         enum amfi_dyld_policy_output_flag_set 
{ 
  72                 AMFI_DYLD_OUTPUT_ALLOW_AT_PATH 
= (1 << 0), 
  73                 AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS 
= (1 << 1), 
  74                 AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE 
= (1 << 2), 
  75                 AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS 
= (1 << 3), 
  76                 AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS 
= (1 << 4), 
  77                 AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION 
= (1 << 5), 
  78                 AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING 
= (1 << 6), 
  80         extern "C" int amfi_check_dyld_policy_self(uint64_t input_flags
, uint64_t* output_flags
); 
  86 #include <sandbox/private.h> 
  87 #if __has_feature(ptrauth_calls) 
  91 extern "C" int __fork(); 
  99 #include "ImageLoader.h" 
 100 #include "ImageLoaderMachO.h" 
 101 #include "dyldLibSystemInterface.h" 
 102 #include "dyld_cache_format.h" 
 103 #include "dyld_process_info_internal.h" 
 105 #if SUPPORT_ACCELERATE_TABLES 
 106         #include "ImageLoaderMegaDylib.h" 
 109 #if TARGET_OS_SIMULATOR 
 110         extern "C" void* gSyscallHelpers
; 
 112         #include "dyldSyscallInterface.h" 
 116 #include "libdyldEntryVector.h" 
 117 #include "MachOLoaded.h" 
 119 #include "DyldSharedCache.h" 
 120 #include "SharedCacheRuntime.h" 
 121 #include "StringUtils.h" 
 123 #include "ClosureBuilder.h" 
 124 #include "ClosureFileSystemPhysical.h" 
 125 #include "FileUtils.h" 
 126 #include "BootArgs.h" 
 129   #define MH_HAS_OBJC                   0x40000000 
 132 // not libc header for send() syscall interface 
 133 extern "C" ssize_t 
__sendto(int, const void *, size_t, int, const struct sockaddr 
*, socklen_t
); 
 136 // ARM and x86_64 are the only architecture that use cpu-sub-types 
 137 #define CPU_SUBTYPES_SUPPORTED  ((__arm__ || __arm64__ || __x86_64__) && !TARGET_OS_SIMULATOR) 
 140         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
 141         #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT 
 142         #define LC_ENCRYPT_COMMAND              LC_ENCRYPTION_INFO 
 143         #define macho_segment_command   segment_command_64 
 144         #define macho_section                   section_64 
 146         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
 147         #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64 
 148         #define LC_ENCRYPT_COMMAND              LC_ENCRYPTION_INFO_64 
 149         #define macho_segment_command   segment_command 
 150         #define macho_section                   section 
 155 #define CPU_TYPE_MASK 0x00FFFFFF        /* complement of CPU_ARCH_MASK */ 
 158 /* implemented in dyld_gdb.cpp */ 
 159 extern void resetAllImages(); 
 160 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]); 
 161 extern void removeImageFromAllImages(const mach_header
* mh
); 
 162 extern void addNonSharedCacheImageUUID(const dyld_uuid_info
& info
); 
 163 extern const char* notifyGDB(enum dyld_image_states state
, uint32_t infoCount
, const dyld_image_info info
[]); 
 164 extern size_t allImagesCount(); 
 166 // magic so CrashReporter logs message 
 168         char error_string
[1024]; 
 171 // magic linker symbol for start of dyld binary 
 172 extern "C" const macho_header __dso_handle
; 
 176 // The file contains the core of dyld used to get a process to main().   
 177 // The API's that dyld supports are implemented in dyldAPIs.cpp. 
 184         struct RegisteredDOF 
{ const mach_header
* mh
; int registrationID
; }; 
 185         struct DylibOverride 
{ const char* installName
; const char* override
; }; 
 189 VECTOR_NEVER_DESTRUCTED(ImageLoader
*); 
 190 VECTOR_NEVER_DESTRUCTED(dyld::RegisteredDOF
); 
 191 VECTOR_NEVER_DESTRUCTED(dyld::ImageCallback
); 
 192 VECTOR_NEVER_DESTRUCTED(dyld::DylibOverride
); 
 193 VECTOR_NEVER_DESTRUCTED(ImageLoader::DynamicReference
); 
 195 VECTOR_NEVER_DESTRUCTED(dyld_image_state_change_handler
); 
 201 // state of all environment variables dyld uses 
 203 struct EnvironmentVariables 
{ 
 204         const char* const *                     DYLD_FRAMEWORK_PATH
; 
 205         const char* const *                     DYLD_FALLBACK_FRAMEWORK_PATH
; 
 206         const char* const *                     DYLD_LIBRARY_PATH
; 
 207         const char* const *                     DYLD_FALLBACK_LIBRARY_PATH
; 
 208         const char* const *                     DYLD_INSERT_LIBRARIES
; 
 209         const char* const *                     LD_LIBRARY_PATH
;                        // for unix conformance 
 210         const char* const *                     DYLD_VERSIONED_LIBRARY_PATH
; 
 211         const char* const *                     DYLD_VERSIONED_FRAMEWORK_PATH
; 
 212         bool                                            DYLD_PRINT_LIBRARIES_POST_LAUNCH
; 
 213         bool                                            DYLD_BIND_AT_LAUNCH
; 
 214         bool                                            DYLD_PRINT_STATISTICS
; 
 215         bool                                            DYLD_PRINT_STATISTICS_DETAILS
; 
 216         bool                                            DYLD_PRINT_OPTS
; 
 218         bool                                            DYLD_DISABLE_DOFS
; 
 220                             //  DYLD_SHARED_CACHE_DIR           ==> sSharedCacheOverrideDir 
 221                                                         //      DYLD_ROOT_PATH                                  ==> gLinkContext.rootPaths 
 222                                                         //      DYLD_IMAGE_SUFFIX                               ==> gLinkContext.imageSuffix 
 223                                                         //      DYLD_PRINT_OPTS                                 ==> gLinkContext.verboseOpts 
 224                                                         //      DYLD_PRINT_ENV                                  ==> gLinkContext.verboseEnv 
 225                                                         //      DYLD_FORCE_FLAT_NAMESPACE               ==> gLinkContext.bindFlat 
 226                                                         //      DYLD_PRINT_INITIALIZERS                 ==> gLinkContext.verboseInit 
 227                                                         //      DYLD_PRINT_SEGMENTS                             ==> gLinkContext.verboseMapping 
 228                                                         //      DYLD_PRINT_BINDINGS                             ==> gLinkContext.verboseBind 
 229                                                         //  DYLD_PRINT_WEAK_BINDINGS            ==> gLinkContext.verboseWeakBind 
 230                                                         //      DYLD_PRINT_REBASINGS                    ==> gLinkContext.verboseRebase 
 231                                                         //      DYLD_PRINT_DOFS                                 ==> gLinkContext.verboseDOF 
 232                                                         //      DYLD_PRINT_APIS                                 ==> gLogAPIs 
 233                                                         //      DYLD_IGNORE_PREBINDING                  ==> gLinkContext.prebindUsage 
 234                                                         //      DYLD_PREBIND_DEBUG                              ==> gLinkContext.verbosePrebinding 
 235                                                         //      DYLD_NEW_LOCAL_SHARED_REGIONS   ==> gLinkContext.sharedRegionMode 
 236                                                         //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode 
 237                                                         //      DYLD_PRINT_WARNINGS                             ==> gLinkContext.verboseWarnings 
 238                                                         //      DYLD_PRINT_RPATHS                               ==> gLinkContext.verboseRPaths 
 239                                                         //      DYLD_PRINT_INTERPOSING                  ==> gLinkContext.verboseInterposing 
 240                                                         //  DYLD_PRINT_LIBRARIES                        ==> gLinkContext.verboseLoading 
 245 typedef std::vector
<dyld_image_state_change_handler
> StateHandlers
; 
 248 enum EnvVarMode 
{ envNone
, envPrintOnly
, envAll 
}; 
 251 static const char*                                      sExecPath 
= NULL
; 
 252 static const char*                                      sExecShortName 
= NULL
; 
 253 static const macho_header
*                      sMainExecutableMachHeader 
= NULL
; 
 254 static uintptr_t                                        sMainExecutableSlide 
= 0; 
 255 #if CPU_SUBTYPES_SUPPORTED 
 256 static cpu_type_t                                       sHostCPU
; 
 257 static cpu_subtype_t                            sHostCPUsubtype
; 
 259 static ImageLoaderMachO
*                        sMainExecutable 
= NULL
; 
 260 static size_t                                           sInsertedDylibCount 
= 0; 
 261 static std::vector
<ImageLoader
*>        sAllImages
; 
 262 static std::vector
<ImageLoader
*>        sImageRoots
; 
 263 static std::vector
<ImageLoader
*>        sImageFilesNeedingTermination
; 
 264 static std::vector
<RegisteredDOF
>       sImageFilesNeedingDOFUnregistration
; 
 265 static std::vector
<ImageCallback
>   sAddImageCallbacks
; 
 266 static std::vector
<ImageCallback
>   sRemoveImageCallbacks
; 
 267 static std::vector
<LoadImageCallback
> sAddLoadImageCallbacks
; 
 268 static std::vector
<LoadImageBulkCallback
> sAddBulkLoadImageCallbacks
; 
 269 static bool                                                     sRemoveImageCallbacksInUse 
= false; 
 270 static void*                                            sSingleHandlers
[7][3]; 
 271 static void*                                            sBatchHandlers
[7][3]; 
 272 static ImageLoader
*                                     sLastImageByAddressCache
; 
 273 static EnvironmentVariables                     sEnv
; 
 274 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
 275 static const char*                                      sFrameworkFallbackPaths
[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL 
}; 
 276 static const char*                                      sLibraryFallbackPaths
[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL 
}; 
 277 static const char*                                      sRestrictedFrameworkFallbackPaths
[] = { "/System/Library/Frameworks", NULL 
}; 
 278 static const char*                                      sRestrictedLibraryFallbackPaths
[] = { "/usr/lib", NULL 
}; 
 280 static const char*                                      sFrameworkFallbackPaths
[] = { "/System/Library/Frameworks", NULL 
}; 
 281 static const char*                                      sLibraryFallbackPaths
[] = { "/usr/local/lib", "/usr/lib", NULL 
}; 
 283 static UndefinedHandler                         sUndefinedHandler 
= NULL
; 
 284 static ImageLoader
*                                     sBundleBeingLoaded 
= NULL
;      // hack until OFI is reworked 
 285 static dyld3::SharedCacheLoadInfo       sSharedCacheLoadInfo
; 
 286 static const char*                                      sSharedCacheOverrideDir
; 
 287        bool                                                     gSharedCacheOverridden 
= false; 
 288 ImageLoader::LinkContext                        gLinkContext
; 
 289 bool                                                            gLogAPIs 
= false; 
 290 #if SUPPORT_ACCELERATE_TABLES 
 291 bool                                                            gLogAppAPIs 
= false; 
 293 const struct LibSystemHelpers
*          gLibSystemHelpers 
= NULL
; 
 294 #if SUPPORT_OLD_CRT_INITIALIZATION 
 295 bool                                                            gRunInitializersOldWay 
= false; 
 297 static std::vector
<DylibOverride
>       sDylibOverrides
; 
 298 #if !TARGET_OS_SIMULATOR         
 299 static int                                                      sLogSocket 
= -1; 
 301 static bool                                                     sFrameworksFoundAsDylibs 
= false; 
 302 #if __x86_64__ && !TARGET_OS_SIMULATOR 
 303 static bool                                                     sHaswell 
= false; 
 305 static std::vector
<ImageLoader::DynamicReference
> sDynamicReferences
; 
 306 #pragma clang diagnostic push 
 307 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 308 static OSSpinLock                                       sDynamicReferencesLock 
= 0; 
 309 #pragma clang diagnostic pop 
 310 #if !TARGET_OS_SIMULATOR 
 311 static bool                                                     sLogToFile 
= false; 
 313 static char                                                     sLoadingCrashMessage
[1024] = "dyld: launch, loading dependent libraries"; 
 314 static _dyld_objc_notify_mapped         sNotifyObjCMapped
; 
 315 static _dyld_objc_notify_init           sNotifyObjCInit
; 
 316 static _dyld_objc_notify_unmapped       sNotifyObjCUnmapped
; 
 318 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
 319 static bool                                                     sForceStderr 
= false; 
 323 #if SUPPORT_ACCELERATE_TABLES 
 324 static ImageLoaderMegaDylib
*            sAllCacheImagesProxy 
= NULL
; 
 325 // Note these are now off by default as everything should use dyld3. 
 326 static bool                                                     sDisableAcceleratorTables 
= true; 
 329 bool                                                            gUseDyld3 
= false; 
 330 static bool                                                     sSkipMain 
= false; 
 331 static void                       (*sEntryOveride
)() = nullptr; 
 332 static bool                                                     sJustBuildClosure 
= false; 
 333 static bool                                                     sLogClosureFailure 
= false; 
 335 enum class ClosureMode 
{ 
 336         // Unset means we haven't provided an env variable or boot-arg to explicitly choose a mode 
 338         // On means we set DYLD_USE_CLOSURES=1, or we didn't have DYLD_USE_CLOSURES=0 but did have 
 339         // -force_dyld3=1 env variable or a customer cache on iOS 
 341         // Off means we set DYLD_USE_CLOSURES=0, or we didn't have DYLD_USE_CLOSURES=1 but did have 
 342         // -force_dyld2=1 env variable or an internal cache on iOS 
 344         // PreBuiltOnly means only use a shared cache closure and don't try build a new one 
 348 static ClosureMode                                      sClosureMode 
= ClosureMode::Unset
; 
 349 static bool                                                     sForceInvalidSharedCacheClosureFormat 
= false; 
 350 static uint64_t                                         launchTraceID 
= 0; 
 353 // The MappedRanges structure is used for fast address->image lookups. 
 354 // The table is only updated when the dyld lock is held, so we don't 
 355 // need to worry about multiple writers.  But readers may look at this 
 356 // data without holding the lock. Therefore, all updates must be done 
 357 // in an order that will never cause readers to see inconsistent data. 
 358 // The general rule is that if the image field is non-NULL then 
 359 // the other fields are valid. 
 372 static MappedRanges
*    sMappedRangesStart
; 
 374 #pragma clang diagnostic push 
 375 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 376 void addMappedRange(ImageLoader
* image
, uintptr_t start
, uintptr_t end
) 
 378         //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName()); 
 379         for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 380                 for (unsigned long i
=0; i 
< p
->count
; ++i
) { 
 381                         if ( p
->array
[i
].image 
== NULL 
) { 
 382                                 p
->array
[i
].start 
= start
; 
 383                                 p
->array
[i
].end 
= end
; 
 384                                 // add image field last with a barrier so that any reader will see consistent records 
 386                                 p
->array
[i
].image 
= image
; 
 391         // table must be full, chain another 
 392 #if SUPPORT_ACCELERATE_TABLES 
 393         unsigned count 
= (sAllCacheImagesProxy 
!= NULL
) ? 16 : 400; 
 395         unsigned count 
= 400; 
 397         size_t allocationSize 
= sizeof(MappedRanges
) + (count
-1)*3*sizeof(void*); 
 398         MappedRanges
* newRanges 
= (MappedRanges
*)malloc(allocationSize
); 
 399         bzero(newRanges
, allocationSize
); 
 400         newRanges
->count 
= count
; 
 401         newRanges
->array
[0].start 
= start
; 
 402         newRanges
->array
[0].end 
= end
; 
 403         newRanges
->array
[0].image 
= image
; 
 405         if ( sMappedRangesStart 
== NULL 
) { 
 406                 sMappedRangesStart 
= newRanges
; 
 409                 for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 410                         if ( p
->next 
== NULL 
) { 
 419 void removedMappedRanges(ImageLoader
* image
) 
 421         for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 422                 for (unsigned long i
=0; i 
< p
->count
; ++i
) { 
 423                         if ( p
->array
[i
].image 
== image 
) { 
 424                                 // clear with a barrier so that any reader will see consistent records 
 426                                 p
->array
[i
].image 
= NULL
; 
 431 #pragma clang diagnostic pop 
 433 ImageLoader
* findMappedRange(uintptr_t target
) 
 435         for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 436                 for (unsigned long i
=0; i 
< p
->count
; ++i
) { 
 437                         if ( p
->array
[i
].image 
!= NULL 
) { 
 438                                 if ( (p
->array
[i
].start 
<= target
) && (target 
< p
->array
[i
].end
) ) 
 439                                         return p
->array
[i
].image
; 
 448 const char* mkstringf(const char* format
, ...) 
 450         _SIMPLE_STRING buf 
= _simple_salloc(); 
 453                 va_start(list
, format
); 
 454                 _simple_vsprintf(buf
, format
, list
); 
 456                 const char*     t 
= strdup(_simple_string(buf
)); 
 461         return "mkstringf, out of memory error"; 
 465 void throwf(const char* format
, ...)  
 467         _SIMPLE_STRING buf 
= _simple_salloc(); 
 470                 va_start(list
, format
); 
 471                 _simple_vsprintf(buf
, format
, list
); 
 473                 const char*     t 
= strdup(_simple_string(buf
)); 
 478         throw "throwf, out of memory error"; 
 482 #if !TARGET_OS_SIMULATOR 
 483 static int sLogfile 
= STDERR_FILENO
; 
 486 #if !TARGET_OS_SIMULATOR         
 487 // based on CFUtilities.c: also_do_stderr() 
 488 static bool useSyslog() 
 490         // Use syslog() for processes managed by launchd 
 491         static bool launchdChecked 
= false; 
 492         static bool launchdOwned 
= false; 
 493         if ( !launchdChecked 
&& gProcessInfo
->libSystemInitialized 
) { 
 494                 if ( (gLibSystemHelpers 
!= NULL
) && (gLibSystemHelpers
->version 
>= 11) ) { 
 495                         // <rdar://problem/23520449> only call isLaunchdOwned() after libSystem is initialized 
 496                         launchdOwned 
= (*gLibSystemHelpers
->isLaunchdOwned
)(); 
 497                         launchdChecked 
= true; 
 500         if ( launchdChecked 
&& launchdOwned 
) 
 503         // If stderr is not available, use syslog() 
 505         int result 
= fstat(STDERR_FILENO
, &sb
); 
 507                 return true; // file descriptor 2 is closed 
 513 static void socket_syslogv(int priority
, const char* format
, va_list list
) 
 515         // lazily create socket and connection to syslogd 
 516         if ( sLogSocket 
== -1 ) { 
 517                 sLogSocket 
= ::socket(AF_UNIX
, SOCK_DGRAM
, 0); 
 518                 if (sLogSocket 
== -1) 
 519                         return;  // cannot log 
 520                 ::fcntl(sLogSocket
, F_SETFD
, 1); 
 522                 struct sockaddr_un addr
; 
 523                 addr
.sun_family 
= AF_UNIX
; 
 524                 strncpy(addr
.sun_path
, _PATH_LOG
, sizeof(addr
.sun_path
)); 
 525                 if ( ::connect(sLogSocket
, (struct sockaddr 
*)&addr
, sizeof(addr
)) == -1 ) { 
 532         // format message to syslogd like: "<priority>Process[pid]: message" 
 533         _SIMPLE_STRING buf 
= _simple_salloc(); 
 536         if ( _simple_sprintf(buf
, "<%d>%s[%d]: ", LOG_USER
|LOG_NOTICE
, sExecShortName
, getpid()) == 0 ) { 
 537                 if ( _simple_vsprintf(buf
, format
, list
) == 0 ) { 
 538                         const char* p 
= _simple_string(buf
); 
 539                         ::__sendto(sLogSocket
, p
, strlen(p
), 0, NULL
, 0); 
 547 void vlog(const char* format
, va_list list
) 
 549 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
 550         // <rdar://problem/25965832> log to console when running iOS app from Xcode 
 551         if ( !sLogToFile 
&& !sForceStderr 
&& useSyslog() ) 
 553         if ( !sLogToFile 
&& useSyslog() ) 
 555                 socket_syslogv(LOG_ERR
, format
, list
); 
 557                 _simple_vdprintf(sLogfile
, format
, list
); 
 561 void log(const char* format
, ...) 
 564         va_start(list
, format
); 
 570 void vwarn(const char* format
, va_list list
)  
 572         _simple_dprintf(sLogfile
, "dyld: warning, "); 
 573         _simple_vdprintf(sLogfile
, format
, list
); 
 576 void warn(const char* format
, ...)  
 579         va_start(list
, format
); 
 585         extern void vlog(const char* format
, va_list list
); 
 586 #endif // !TARGET_OS_SIMULATOR   
 589 #pragma clang diagnostic push 
 590 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 591 // <rdar://problem/8867781> control access to sAllImages through a lock 
 592 // because global dyld lock is not held during initialization phase of dlopen() 
 593 // <rdar://problem/16145518> Use OSSpinLockLock to allow yielding 
 594 static OSSpinLock sAllImagesLock 
= 0; 
 596 static void allImagesLock() 
 598         OSSpinLockLock(&sAllImagesLock
); 
 601 static void allImagesUnlock() 
 603         OSSpinLockUnlock(&sAllImagesLock
); 
 605 #pragma clang diagnostic pop 
 608 // utility class to assure files are closed when an exception is thrown 
 611         FileOpener(const char* path
); 
 613         int getFileDescriptor() { return fd
; } 
 618 FileOpener::FileOpener(const char* path
) 
 621         fd 
= my_open(path
, O_RDONLY
, 0); 
 624 FileOpener::~FileOpener() 
 631 static void     registerDOFs(const std::vector
<ImageLoader::DOFInfo
>& dofs
) 
 633         const size_t dofSectionCount 
= dofs
.size(); 
 634         if ( !sEnv
.DYLD_DISABLE_DOFS 
&& (dofSectionCount 
!= 0) ) { 
 635                 int fd 
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
); 
 637                         //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n"); 
 640                         // allocate a buffer on the stack for the variable length dof_ioctl_data_t type 
 641                         uint8_t buffer
[sizeof(dof_ioctl_data_t
) + dofSectionCount
*sizeof(dof_helper_t
)]; 
 642                         dof_ioctl_data_t
* ioctlData 
= (dof_ioctl_data_t
*)buffer
; 
 644                         // fill in buffer with one dof_helper_t per DOF section 
 645                         ioctlData
->dofiod_count 
= dofSectionCount
; 
 646                         for (unsigned int i
=0; i 
< dofSectionCount
; ++i
) { 
 647                                 strlcpy(ioctlData
->dofiod_helpers
[i
].dofhp_mod
, dofs
[i
].imageShortName
, DTRACE_MODNAMELEN
); 
 648                                 ioctlData
->dofiod_helpers
[i
].dofhp_dof 
= (uintptr_t)(dofs
[i
].dof
); 
 649                                 ioctlData
->dofiod_helpers
[i
].dofhp_addr 
= (uintptr_t)(dofs
[i
].dof
); 
 652                         // tell kernel about all DOF sections en mas 
 653                         // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel 
 654                         user_addr_t val 
= (user_addr_t
)(unsigned long)ioctlData
; 
 655                         if ( ioctl(fd
, DTRACEHIOC_ADDDOF
, &val
) != -1 ) { 
 656                                 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field. 
 657                                 for (unsigned int i
=0; i 
< dofSectionCount
; ++i
) { 
 659                                         info
.mh 
= dofs
[i
].imageHeader
; 
 660                                         info
.registrationID 
= (int)(ioctlData
->dofiod_helpers
[i
].dofhp_dof
); 
 661                                         sImageFilesNeedingDOFUnregistration
.push_back(info
); 
 662                                         if ( gLinkContext
.verboseDOF 
) { 
 663                                                 dyld::log("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",  
 664                                                         dofs
[i
].dof
, dofs
[i
].imageShortName
, info
.registrationID
); 
 669                                 //dyld::log( "dyld: ioctl to register dtrace DOF section failed\n"); 
 676 static void     unregisterDOF(int registrationID
) 
 678         int fd 
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
); 
 680                 dyld::warn("can't open /dev/" DTRACEMNR_HELPER 
" to unregister dtrace DOF section\n"); 
 683                 ioctl(fd
, DTRACEHIOC_REMOVE
, registrationID
); 
 685                 if ( gLinkContext
.verboseInit 
) 
 686                         dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID
); 
 692 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification 
 693 // Returns true if we did call add image callbacks on this image 
 695 static bool notifyAddImageCallbacks(ImageLoader
* image
) 
 697         // use guard so that we cannot notify about the same image twice 
 698         if ( ! image
->addFuncNotified() ) { 
 699                 for (std::vector
<ImageCallback
>::iterator it
=sAddImageCallbacks
.begin(); it 
!= sAddImageCallbacks
.end(); it
++) { 
 700                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*it
), 0); 
 701                         (*it
)(image
->machHeader(), image
->getSlide()); 
 703                 for (LoadImageCallback func 
: sAddLoadImageCallbacks
) { 
 704                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*func
), 0); 
 705                         (*func
)(image
->machHeader(), image
->getPath(), !image
->neverUnload()); 
 707                 image
->setAddFuncNotified(); 
 715 // notify gdb about these new images 
 716 static const char* updateAllImages(enum dyld_image_states state
, uint32_t infoCount
, const struct dyld_image_info info
[]) 
 718         // <rdar://problem/8812589> don't add images without paths to all-image-info-list 
 719         if ( info
[0].imageFilePath 
!= NULL 
) 
 720                 addImagesToAllImages(infoCount
, info
); 
 725 static StateHandlers
* stateToHandlers(dyld_image_states state
, void* handlersArray
[7][3]) 
 728                 case dyld_image_state_mapped
: 
 729                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[0]); 
 731                 case dyld_image_state_dependents_mapped
: 
 732                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[1]); 
 734                 case dyld_image_state_rebased
: 
 735                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[2]); 
 737                 case dyld_image_state_bound
: 
 738                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[3]); 
 740                 case dyld_image_state_dependents_initialized
: 
 741                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[4]); 
 743                 case dyld_image_state_initialized
: 
 744                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[5]); 
 746                 case dyld_image_state_terminated
: 
 747                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[6]); 
 752 #if SUPPORT_ACCELERATE_TABLES 
 753 static dyld_image_state_change_handler 
getPreInitNotifyHandler(unsigned index
) 
 755         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(dyld_image_state_dependents_initialized
, sSingleHandlers
); 
 756         if ( index 
>= handlers
->size() ) 
 758         return (*handlers
)[index
]; 
 761 static dyld_image_state_change_handler 
getBoundBatchHandler(unsigned index
) 
 763         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(dyld_image_state_bound
, sBatchHandlers
); 
 764         if ( index 
>= handlers
->size() ) 
 766         return (*handlers
)[index
]; 
 769 static void notifySingleFromCache(dyld_image_states state
, const mach_header
* mh
, const char* path
) 
 771         //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath()); 
 772         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
 773         if ( handlers 
!= NULL 
) { 
 774                 dyld_image_info info
; 
 775                 info
.imageLoadAddress   
= mh
; 
 776                 info
.imageFilePath              
= path
; 
 777                 info
.imageFileModDate   
= 0; 
 778                 for (dyld_image_state_change_handler handler 
: *handlers
) { 
 779                         const char* result 
= (*handler
)(state
, 1, &info
); 
 780                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_mapped
) ) { 
 781                                 //fprintf(stderr, "  image rejected by handler=%p\n", *it); 
 782                                 // make copy of thrown string so that later catch clauses can free it 
 783                                 const char* str 
= strdup(result
); 
 788         if ( (state 
== dyld_image_state_dependents_initialized
) && (sNotifyObjCInit 
!= NULL
) && (mh
->flags 
& MH_HAS_OBJC
) ) { 
 789                 dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_OBJC_INIT
, (uint64_t)mh
, 0, 0); 
 790                 (*sNotifyObjCInit
)(path
, mh
); 
 795 #if !TARGET_OS_SIMULATOR 
 796 static void sendMessage(unsigned portSlot
, mach_msg_id_t msgId
, mach_msg_size_t sendSize
, mach_msg_header_t
* buffer
, mach_msg_size_t bufferSize
) { 
 797         // Allocate a port to listen on in this monitoring task 
 798         mach_port_t sendPort 
= dyld::gProcessInfo
->notifyPorts
[portSlot
]; 
 799         if (sendPort 
== MACH_PORT_NULL
) { 
 802         mach_port_t replyPort 
= MACH_PORT_NULL
; 
 803         mach_port_options_t options 
= { .flags 
= MPO_CONTEXT_AS_GUARD 
| MPO_STRICT
, 
 805         kern_return_t kr 
= mach_port_construct(mach_task_self(), &options
, (mach_port_context_t
)&replyPort
, &replyPort
); 
 806         if (kr 
!= KERN_SUCCESS
) { 
 809         // Assemble a message 
 810         mach_msg_header_t
* h 
= buffer
; 
 811         h
->msgh_bits         
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND_ONCE
); 
 813         h
->msgh_local_port   
= replyPort
; 
 814         h
->msgh_remote_port  
= sendPort
; 
 815         h
->msgh_reserved     
= 0; 
 816         h
->msgh_size         
= sendSize
; 
 817         kr 
= mach_msg(h
, MACH_SEND_MSG 
| MACH_RCV_MSG
, h
->msgh_size
, bufferSize
, replyPort
, 0, MACH_PORT_NULL
); 
 819         if ( kr 
== MACH_SEND_INVALID_DEST 
) { 
 820                 if (OSAtomicCompareAndSwap32(sendPort
, 0, (volatile int32_t*)&dyld::gProcessInfo
->notifyPorts
[portSlot
])) { 
 821                         mach_port_deallocate(mach_task_self(), sendPort
); 
 824         mach_port_destruct(mach_task_self(), replyPort
, 0, (mach_port_context_t
)&replyPort
); 
 827 static void notifyMonitoringDyld(bool unloading
, unsigned imageCount
, const struct mach_header
* loadAddresses
[], 
 828                                                                  const char* imagePaths
[]) 
 830         dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER
, 0, 0, 0); 
 831         for (int slot
=0; slot 
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) { 
 832                 if ( dyld::gProcessInfo
->notifyPorts
[slot
] == 0) continue; 
 833                 unsigned entriesSize 
= imageCount
*sizeof(dyld_process_info_image_entry
); 
 834                 unsigned pathsSize 
= 0; 
 835                 for (unsigned j
=0; j 
< imageCount
; ++j
) { 
 836                         pathsSize 
+= (strlen(imagePaths
[j
]) + 1); 
 838                 unsigned totalSize 
= (sizeof(dyld_process_info_notify_header
) + entriesSize 
+ pathsSize 
+ 127) & -128;   // align 
 839                 if ( totalSize 
> DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE 
) { 
 840                         // Putting all image paths into one message would make buffer too big. 
 841                         // Instead split into two messages.  Recurse as needed until paths fit in buffer. 
 842                         unsigned imageHalfCount 
= imageCount
/2; 
 843                         notifyMonitoringDyld(unloading
, imageHalfCount
, loadAddresses
, imagePaths
); 
 844                         notifyMonitoringDyld(unloading
, imageCount 
- imageHalfCount
, &loadAddresses
[imageHalfCount
], &imagePaths
[imageHalfCount
]); 
 847                 uint8_t buffer
[totalSize 
+ MAX_TRAILER_SIZE
]; 
 848                 dyld_process_info_notify_header
* header 
= (dyld_process_info_notify_header
*)buffer
; 
 850                 header
->imageCount              
= imageCount
; 
 851                 header
->imagesOffset    
= sizeof(dyld_process_info_notify_header
); 
 852                 header
->stringsOffset   
= sizeof(dyld_process_info_notify_header
) + entriesSize
; 
 853                 header
->timestamp               
= dyld::gProcessInfo
->infoArrayChangeTimestamp
; 
 854                 dyld_process_info_image_entry
* entries 
= (dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
]; 
 855                 char* const pathPoolStart 
= (char*)&buffer
[header
->stringsOffset
]; 
 856                 char* pathPool 
= pathPoolStart
; 
 857                 for (unsigned j
=0; j 
< imageCount
; ++j
) { 
 858                         strcpy(pathPool
, imagePaths
[j
]); 
 859                         uint32_t len 
= (uint32_t)strlen(pathPool
); 
 860                         bzero(entries
->uuid
, 16); 
 861                         dyld3::MachOFile
* mf 
= (dyld3::MachOFile
*)loadAddresses
[j
]; 
 862                         mf
->getUuid(entries
->uuid
); 
 863                         entries
->loadAddress 
= (uint64_t)loadAddresses
[j
]; 
 864                         entries
->pathStringOffset 
= (uint32_t)(pathPool 
- pathPoolStart
); 
 865                         entries
->pathLength  
= len
; 
 866                         pathPool 
+= (len 
+1); 
 870                         sendMessage(slot
, DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
, totalSize
, (mach_msg_header_t
*)buffer
, totalSize
+MAX_TRAILER_SIZE
); 
 872                         sendMessage(slot
, DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
, totalSize
, (mach_msg_header_t
*)buffer
, totalSize
+MAX_TRAILER_SIZE
); 
 877 static void notifyMonitoringDyldMain() 
 879         dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER
, 0, 0, 0); 
 880         for (int slot
=0; slot 
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) { 
 881                 if ( dyld::gProcessInfo
->notifyPorts
[slot
] == 0) continue; 
 882                 uint8_t buffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
]; 
 883                 sendMessage(slot
, DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
, sizeof(mach_msg_header_t
), (mach_msg_header_t
*)buffer
, sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
); 
 887 extern void notifyMonitoringDyldMain() VIS_HIDDEN
; 
 888 extern void notifyMonitoringDyld(bool unloading
, unsigned imageCount
, const struct mach_header
* loadAddresses
[], 
 889                                                                  const char* imagePaths
[]) VIS_HIDDEN
; 
 892 void notifyKernel(const ImageLoader
& image
, bool loading
) { 
 893         uint32_t baseCode 
= loading 
? DBG_DYLD_UUID_MAP_A 
: DBG_DYLD_UUID_UNMAP_A
; 
 896         if ( image
.inSharedCache() ) { 
 897                 dyld3::kdebug_trace_dyld_image(baseCode
, image
.getInstallPath(), (const uuid_t 
*)&uuid
, {0}, {{ 0, 0 }}, image
.machHeader()); 
 899                 fsid_t fsid 
= {{0, 0}}; 
 900                 fsobj_id_t fsobj 
= {0}; 
 901                 ino_t inode 
= image
.getInode(); 
 902                 fsobj
.fid_objno 
= (uint32_t)inode
; 
 903                 fsobj
.fid_generation 
= (uint32_t)(inode
>>32); 
 904                 fsid
.val
[0] = image
.getDevice(); 
 905                 dyld3::kdebug_trace_dyld_image(baseCode
, image
.getPath(), (const uuid_t 
*)&uuid
, fsobj
, fsid
, image
.machHeader()); 
 909 static void notifySingle(dyld_image_states state
, const ImageLoader
* image
, ImageLoader::InitializerTimingList
* timingInfo
) 
 911         //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath()); 
 912         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
 913         if ( handlers 
!= NULL 
) { 
 914                 dyld_image_info info
; 
 915                 info
.imageLoadAddress   
= image
->machHeader(); 
 916                 info
.imageFilePath              
= image
->getRealPath(); 
 917                 info
.imageFileModDate   
= image
->lastModified(); 
 918                 for (std::vector
<dyld_image_state_change_handler
>::iterator it 
= handlers
->begin(); it 
!= handlers
->end(); ++it
) { 
 919                         const char* result 
= (*it
)(state
, 1, &info
); 
 920                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_mapped
) ) { 
 921                                 //fprintf(stderr, "  image rejected by handler=%p\n", *it); 
 922                                 // make copy of thrown string so that later catch clauses can free it 
 923                                 const char* str 
= strdup(result
); 
 928         if ( state 
== dyld_image_state_mapped 
) { 
 929                 // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache 
 930                 if ( !image
->inSharedCache() ) { 
 932                         if ( image
->getUUID(info
.imageUUID
) ) { 
 933                                 info
.imageLoadAddress 
= image
->machHeader(); 
 934                                 addNonSharedCacheImageUUID(info
); 
 938         if ( (state 
== dyld_image_state_dependents_initialized
) && (sNotifyObjCInit 
!= NULL
) && image
->notifyObjC() ) { 
 939                 uint64_t t0 
= mach_absolute_time(); 
 940                 dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_OBJC_INIT
, (uint64_t)image
->machHeader(), 0, 0); 
 941                 (*sNotifyObjCInit
)(image
->getRealPath(), image
->machHeader()); 
 942                 uint64_t t1 
= mach_absolute_time(); 
 943                 uint64_t t2 
= mach_absolute_time(); 
 944                 uint64_t timeInObjC 
= t1
-t0
; 
 945                 uint64_t emptyTime 
= (t2
-t1
)*100; 
 946                 if ( (timeInObjC 
> emptyTime
) && (timingInfo 
!= NULL
) ) { 
 947                         timingInfo
->addTime(image
->getShortName(), timeInObjC
); 
 950     // mach message csdlc about dynamically unloaded images 
 951         if ( image
->addFuncNotified() && (state 
== dyld_image_state_terminated
) ) { 
 952                 notifyKernel(*image
, false); 
 953                 const struct mach_header
* loadAddress
[] = { image
->machHeader() }; 
 954                 const char* loadPath
[] = { image
->getPath() }; 
 955                 notifyMonitoringDyld(true, 1, loadAddress
, loadPath
); 
 961 // Normally, dyld_all_image_infos is only updated in batches after an entire 
 962 // graph is loaded.  But if there is an error loading the initial set of 
 963 // dylibs needed by the main executable, dyld_all_image_infos is not yet set  
 964 // up, leading to usually brief crash logs. 
 966 // This function manually adds the images loaded so far to dyld::gProcessInfo. 
 967 // It should only be called before terminating. 
 971         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); ++it
) { 
 972                 dyld_image_info info
; 
 973                 ImageLoader
* image 
= *it
; 
 974                 info
.imageLoadAddress 
= image
->machHeader(); 
 975                 info
.imageFilePath 
= image
->getRealPath(); 
 976                 info
.imageFileModDate 
= image
->lastModified(); 
 977                 // add to all_image_infos if not already there 
 979                 int existingCount 
= dyld::gProcessInfo
->infoArrayCount
; 
 980                 const dyld_image_info
* existing 
= dyld::gProcessInfo
->infoArray
; 
 981                 if ( existing 
!= NULL 
) { 
 982                         for (int i
=0; i 
< existingCount
; ++i
) { 
 983                                 if ( existing
[i
].imageLoadAddress 
== info
.imageLoadAddress 
) { 
 984                                         //dyld::log("not adding %s\n", info.imageFilePath); 
 991                         //dyld::log("adding %s\n", info.imageFilePath); 
 992                         addImagesToAllImages(1, &info
); 
 998 static int imageSorter(const void* l
, const void* r
) 
1000         const ImageLoader
* left 
= *((ImageLoader
**)l
); 
1001         const ImageLoader
* right
= *((ImageLoader
**)r
); 
1002         return left
->compare(right
); 
1005 static void notifyBatchPartial(dyld_image_states state
, bool orLater
, dyld_image_state_change_handler onlyHandler
, bool preflightOnly
, bool onlyObjCMappedNotification
) 
1007         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sBatchHandlers
); 
1008         if ( (handlers 
!= NULL
) || ((state 
== dyld_image_state_bound
) && (sNotifyObjCMapped 
!= NULL
)) ) { 
1009                 // don't use a vector because it will use malloc/free and we want notifcation to be low cost 
1011                 dyld_image_info infos
[allImagesCount()+1]; 
1012         ImageLoader
* images
[allImagesCount()+1]; 
1013         ImageLoader
** end 
= images
; 
1014         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
1015             dyld_image_states imageState 
= (*it
)->getState(); 
1016             if ( (imageState 
== state
) || (orLater 
&& (imageState 
> state
)) ) 
1019                 if ( sBundleBeingLoaded 
!= NULL 
) { 
1020                         dyld_image_states imageState 
= sBundleBeingLoaded
->getState(); 
1021                         if ( (imageState 
== state
) || (orLater 
&& (imageState 
> state
)) ) 
1022                                 *end
++ = sBundleBeingLoaded
; 
1024         const char* dontLoadReason 
= NULL
; 
1025                 uint32_t imageCount 
= (uint32_t)(end
-images
); 
1026                 if ( imageCount 
!= 0 ) { 
1028                         qsort(images
, imageCount
, sizeof(ImageLoader
*), &imageSorter
); 
1030                         const mach_header
* mhs
[imageCount
]; 
1031                         const char*        paths
[imageCount
]; 
1032                         uint32_t                   bulkNotifyImageCount 
= 0; 
1035                         for (unsigned int i
=0; i 
< imageCount
; ++i
) { 
1036                                 dyld_image_info
* p 
= &infos
[i
]; 
1037                                 ImageLoader
* image 
= images
[i
]; 
1038                                 //dyld::log("  state=%d, name=%s\n", state, image->getPath()); 
1039                                 p
->imageLoadAddress 
= image
->machHeader(); 
1040                                 p
->imageFilePath    
= image
->getRealPath(); 
1041                                 p
->imageFileModDate 
= image
->lastModified(); 
1042                                 // get these registered with the kernel as early as possible 
1043                                 if ( state 
== dyld_image_state_dependents_mapped
) 
1044                                         notifyKernel(*image
, true); 
1045                                 // special case for add_image hook 
1046                                 if ( state 
== dyld_image_state_bound 
) { 
1047                                         if ( notifyAddImageCallbacks(image
) ) { 
1048                                                 // Add this to the list of images to bulk notify 
1049                                                 mhs
[bulkNotifyImageCount
]   = infos
[i
].imageLoadAddress
; 
1050                                                 paths
[bulkNotifyImageCount
] = infos
[i
].imageFilePath
; 
1051                                                 ++bulkNotifyImageCount
; 
1056                         if ( (state 
== dyld_image_state_bound
) && !sAddBulkLoadImageCallbacks
.empty() && (bulkNotifyImageCount 
!= 0) ) { 
1057                                 for (LoadImageBulkCallback func 
: sAddBulkLoadImageCallbacks
) { 
1058                                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)mhs
[0], (uint64_t)func
, 0); 
1059                                         (*func
)(bulkNotifyImageCount
, mhs
, paths
); 
1063 #if SUPPORT_ACCELERATE_TABLES 
1064                 if ( sAllCacheImagesProxy 
!= NULL 
) { 
1065                         unsigned cacheCount 
= sAllCacheImagesProxy
->appendImagesToNotify(state
, orLater
, &infos
[imageCount
]); 
1066                         // support _dyld_register_func_for_add_image() 
1067                         if ( state 
== dyld_image_state_bound 
) { 
1068                                 for (ImageCallback callback 
: sAddImageCallbacks
) { 
1069                                         for (unsigned i
=0; i 
< cacheCount
; ++i
) { 
1070                                                 dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[imageCount
+i
].imageLoadAddress
, (uint64_t)(*callback
), 0); 
1071                                                 (*callback
)(infos
[imageCount
+i
].imageLoadAddress
, sSharedCacheLoadInfo
.slide
); 
1074                                 for (LoadImageCallback func 
: sAddLoadImageCallbacks
) { 
1075                                         for (unsigned i
=0; i 
< cacheCount
; ++i
) { 
1076                                                 dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[imageCount
+i
].imageLoadAddress
, (uint64_t)(*func
), 0); 
1077                                                 (*func
)(infos
[imageCount
+i
].imageLoadAddress
, infos
[imageCount
+i
].imageFilePath
, false); 
1080                                 if ( !sAddBulkLoadImageCallbacks
.empty() ) { 
1081                                         const mach_header
* bulk_mhs
[cacheCount
]; 
1082                                         const char*        bulk_paths
[cacheCount
]; 
1083                                         for (int i
=0; i 
< cacheCount
; ++i
) { 
1084                                                 bulk_mhs
[i
]   = infos
[imageCount
+i
].imageLoadAddress
; 
1085                                                 bulk_paths
[i
] = infos
[imageCount
+i
].imageFilePath
; 
1087                                         for (LoadImageBulkCallback func 
: sAddBulkLoadImageCallbacks
) { 
1088                                                 dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)bulk_mhs
[0], (uint64_t)func
, 0); 
1089                                                 (*func
)(cacheCount
, bulk_mhs
, bulk_paths
); 
1093                         imageCount 
+= cacheCount
; 
1096                 if ( imageCount 
!= 0 ) { 
1097                         if ( !onlyObjCMappedNotification 
) { 
1098                                 if ( onlyHandler 
!= NULL 
) { 
1099                                         const char* result 
= NULL
; 
1100                                         if ( result 
== NULL 
) { 
1101                                                 result 
= (*onlyHandler
)(state
, imageCount
, infos
); 
1103                                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_dependents_mapped
) ) { 
1104                                                 //fprintf(stderr, "  images rejected by handler=%p\n", onlyHandler); 
1105                                                 // make copy of thrown string so that later catch clauses can free it 
1106                                                 dontLoadReason 
= strdup(result
); 
1110                                         // call each handler with whole array 
1111                                         if ( handlers 
!= NULL 
) { 
1112                                                 for (std::vector
<dyld_image_state_change_handler
>::iterator it 
= handlers
->begin(); it 
!= handlers
->end(); ++it
) { 
1113                                                         const char* result 
= (*it
)(state
, imageCount
, infos
); 
1114                                                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_dependents_mapped
) ) { 
1115                                                                 //fprintf(stderr, "  images rejected by handler=%p\n", *it); 
1116                                                                 // make copy of thrown string so that later catch clauses can free it 
1117                                                                 dontLoadReason 
= strdup(result
); 
1124                         // tell objc about new images 
1125                         if ( (onlyHandler 
== NULL
) && ((state 
== dyld_image_state_bound
) || (orLater 
&& (dyld_image_state_bound 
> state
))) && (sNotifyObjCMapped 
!= NULL
) ) { 
1126                                 const char* paths
[imageCount
]; 
1127                                 const mach_header
* mhs
[imageCount
]; 
1128                                 unsigned objcImageCount 
= 0; 
1129                                 for (int i
=0; i 
< imageCount
; ++i
) { 
1130                                         ImageLoader
* image 
= findImageByMachHeader(infos
[i
].imageLoadAddress
); 
1131                                         bool hasObjC 
= false; 
1132                                         if ( image 
!= NULL 
) { 
1133                                                 if ( image
->objCMappedNotified() ) 
1135                                                 hasObjC 
= image
->notifyObjC(); 
1137 #if SUPPORT_ACCELERATE_TABLES 
1138                                         else if ( sAllCacheImagesProxy 
!= NULL 
) { 
1139                                                 const mach_header
* mh
; 
1142                                                 if ( sAllCacheImagesProxy
->addressInCache(infos
[i
].imageLoadAddress
, &mh
, &path
, &index
) ) { 
1143                                                         hasObjC 
= (mh
->flags 
& MH_HAS_OBJC
); 
1148                                                 paths
[objcImageCount
] = infos
[i
].imageFilePath
; 
1149                                                 mhs
[objcImageCount
]   = infos
[i
].imageLoadAddress
; 
1151                                                 if ( image 
!= NULL 
) 
1152                                                         image
->setObjCMappedNotified(); 
1155                                 if ( objcImageCount 
!= 0 ) { 
1156                                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_OBJC_MAP
, 0, 0, 0); 
1157                                         uint64_t t0 
= mach_absolute_time(); 
1158                                         (*sNotifyObjCMapped
)(objcImageCount
, paths
, mhs
); 
1159                                         uint64_t t1 
= mach_absolute_time(); 
1160                                         ImageLoader::fgTotalObjCSetupTime 
+= (t1
-t0
); 
1165         if ( dontLoadReason 
!= NULL 
) 
1166             throw dontLoadReason
; 
1167                 if ( !preflightOnly 
&& (state 
== dyld_image_state_dependents_mapped
) ) { 
1168                         const struct mach_header
* loadAddresses
[imageCount
]; 
1169                         const char* loadPaths
[imageCount
]; 
1170                         for(uint32_t i 
= 0; i
<imageCount
; ++i
) { 
1171                                 loadAddresses
[i
] = infos
[i
].imageLoadAddress
; 
1172                                 loadPaths
[i
] = infos
[i
].imageFilePath
; 
1174                         notifyMonitoringDyld(false, imageCount
, loadAddresses
, loadPaths
); 
1179 static void notifyBatch(dyld_image_states state
, bool preflightOnly
) 
1181         notifyBatchPartial(state
, false, NULL
, preflightOnly
, false); 
1184 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1186 void coresymbolication_load_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
) 
1188         const struct mach_header
* loadAddress
[] = { mh 
}; 
1189         const char* loadPath
[] = { path 
}; 
1190         notifyMonitoringDyld(false, 1, loadAddress
, loadPath
); 
1194 void coresymbolication_unload_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
) 
1196         const struct mach_header
* loadAddress 
= { mh 
}; 
1197         const char* loadPath 
= { path 
}; 
1198         notifyMonitoringDyld(true, 1, &loadAddress
, &loadPath
); 
1202 kern_return_t 
legacy_task_register_dyld_image_infos(task_t task
, dyld_kernel_image_info_array_t dyld_images
, 
1203                                                                                          mach_msg_type_number_t dyld_imagesCnt
) 
1205         return KERN_SUCCESS
; 
1209 kern_return_t 
legacy_task_unregister_dyld_image_infos(task_t task
, dyld_kernel_image_info_array_t dyld_images
, 
1210                                                                                            mach_msg_type_number_t dyld_imagesCnt
) 
1212         return KERN_SUCCESS
; 
1216 kern_return_t 
legacy_task_get_dyld_image_infos(task_inspect_t task
, dyld_kernel_image_info_array_t 
*dyld_images
, 
1217                                                                                 mach_msg_type_number_t 
*dyld_imagesCnt
) 
1219         return KERN_SUCCESS
; 
1223 kern_return_t 
legacy_task_register_dyld_shared_cache_image_info(task_t task
, dyld_kernel_image_info_t dyld_cache_image
, 
1224                                                                                                                  boolean_t no_cache
, boolean_t private_cache
) 
1226         return KERN_SUCCESS
; 
1230 kern_return_t 
legacy_task_register_dyld_set_dyld_state(task_t task
, uint8_t dyld_state
) 
1232         return KERN_SUCCESS
; 
1236 kern_return_t 
legacy_task_register_dyld_get_process_state(task_t task
, dyld_kernel_process_info_t 
*dyld_process_state
) 
1238         return KERN_SUCCESS
; 
1242 // In order for register_func_for_add_image() callbacks to to be called bottom up, 
1243 // we need to maintain a list of root images. The main executable is usally the 
1244 // first root. Any images dynamically added are also roots (unless already loaded). 
1245 // If DYLD_INSERT_LIBRARIES is used, those libraries are first. 
1246 static void addRootImage(ImageLoader
* image
) 
1248         //dyld::log("addRootImage(%p, %s)\n", image, image->getPath()); 
1249         // add to list of roots 
1250         sImageRoots
.push_back(image
); 
1254 static void clearAllDepths() 
1256         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) 
1257                 (*it
)->clearDepth(); 
1260 static void printAllDepths() 
1262         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) 
1263                 dyld::log("%03d %s\n",  (*it
)->getDepth(), (*it
)->getShortName()); 
1267 static unsigned int imageCount() 
1270                 unsigned int result 
= (unsigned int)sAllImages
.size(); 
1276 static void setNewProgramVars(const ProgramVars
& newVars
) 
1278         // make a copy of the pointers to program variables 
1279         gLinkContext
.programVars 
= newVars
; 
1281         // now set each program global to their initial value 
1282         *gLinkContext
.programVars
.NXArgcPtr 
= gLinkContext
.argc
; 
1283         *gLinkContext
.programVars
.NXArgvPtr 
= gLinkContext
.argv
; 
1284         *gLinkContext
.programVars
.environPtr 
= gLinkContext
.envp
; 
1285         *gLinkContext
.programVars
.__prognamePtr 
= gLinkContext
.progname
; 
1288 #if SUPPORT_OLD_CRT_INITIALIZATION 
1289 static void setRunInitialzersOldWay() 
1291         gRunInitializersOldWay 
= true;           
1295 static bool sandboxBlocked(const char* path
, const char* kind
) 
1297 #if TARGET_OS_SIMULATOR 
1298         // sandbox calls not yet supported in simulator runtime 
1301         sandbox_filter_type filter 
= (sandbox_filter_type
)(SANDBOX_FILTER_PATH 
| SANDBOX_CHECK_NO_REPORT
); 
1302         return ( sandbox_check(getpid(), kind
, filter
, path
) > 0 ); 
1306 bool sandboxBlockedMmap(const char* path
) 
1308         return sandboxBlocked(path
, "file-map-executable"); 
1311 bool sandboxBlockedOpen(const char* path
) 
1313         return sandboxBlocked(path
, "file-read-data"); 
1316 bool sandboxBlockedStat(const char* path
) 
1318         return sandboxBlocked(path
, "file-read-metadata"); 
1322 static void addDynamicReference(ImageLoader
* from
, ImageLoader
* to
) { 
1323         // don't add dynamic reference if target is in the shared cache (since it can't be unloaded) 
1324         if ( to
->inSharedCache() ) 
1327         // don't add dynamic reference if there already is a static one 
1328         if ( from
->dependsOn(to
) ) 
1331 #pragma clang diagnostic push 
1332 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
1333         // don't add if this combination already exists 
1334         OSSpinLockLock(&sDynamicReferencesLock
); 
1335         for (std::vector
<ImageLoader::DynamicReference
>::iterator it
=sDynamicReferences
.begin(); it 
!= sDynamicReferences
.end(); ++it
) { 
1336                 if ( (it
->from 
== from
) && (it
->to 
== to
) ) { 
1337                         OSSpinLockUnlock(&sDynamicReferencesLock
); 
1342         //dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName()); 
1343         ImageLoader::DynamicReference t
; 
1346         sDynamicReferences
.push_back(t
); 
1347         OSSpinLockUnlock(&sDynamicReferencesLock
); 
1348 #pragma clang diagnostic pop 
1351 static void addImage(ImageLoader
* image
) 
1353         // add to master list 
1355         sAllImages
.push_back(image
); 
1358         // update mapped ranges 
1359         uintptr_t lastSegStart 
= 0; 
1360         uintptr_t lastSegEnd 
= 0; 
1361         for(unsigned int i
=0, e
=image
->segmentCount(); i 
< e
; ++i
) { 
1362                 if ( image
->segUnaccessible(i
) )  
1364                 uintptr_t start 
= image
->segActualLoadAddress(i
); 
1365                 uintptr_t end 
= image
->segActualEndAddress(i
); 
1366                 if ( start 
== lastSegEnd 
) { 
1367                         // two segments are contiguous, just record combined segments 
1371                         // non-contiguous segments, record last (if any) 
1372                         if ( lastSegEnd 
!= 0 ) 
1373                                 addMappedRange(image
, lastSegStart
, lastSegEnd
); 
1374                         lastSegStart 
= start
; 
1378         if ( lastSegEnd 
!= 0 ) 
1379                 addMappedRange(image
, lastSegStart
, lastSegEnd
); 
1382         if ( gLinkContext
.verboseLoading 
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) { 
1383                 const char *imagePath 
= image
->getPath(); 
1385                 if ( image
->getUUID(imageUUID
) ) { 
1386                         uuid_string_t imageUUIDStr
; 
1387                         uuid_unparse_upper(imageUUID
, imageUUIDStr
); 
1388                         dyld::log("dyld: loaded: <%s> %s\n", imageUUIDStr
, imagePath
); 
1391                         dyld::log("dyld: loaded: %s\n", imagePath
); 
1398 // Helper for std::remove_if 
1400 class RefUsesImage 
{ 
1402         RefUsesImage(ImageLoader
* image
) : _image(image
) {} 
1403         bool operator()(const ImageLoader::DynamicReference
& ref
) const { 
1404                 return ( (ref
.from 
== _image
) || (ref
.to 
== _image
) ); 
1407         ImageLoader
* _image
; 
1412 void removeImage(ImageLoader
* image
) 
1414         // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration 
1415         for (std::vector
<RegisteredDOF
>::iterator it
=sImageFilesNeedingDOFUnregistration
.begin(); it 
!= sImageFilesNeedingDOFUnregistration
.end(); ) { 
1416                 if ( it
->mh 
== image
->machHeader() ) { 
1417                         unregisterDOF(it
->registrationID
); 
1418                         sImageFilesNeedingDOFUnregistration
.erase(it
); 
1419                         // don't increment iterator, the erase caused next element to be copied to where this iterator points 
1426         // tell all registered remove image handlers about this 
1427         // do this before removing image from internal data structures so that the callback can query dyld about the image 
1428         if ( image
->getState() >= dyld_image_state_bound 
) { 
1429                 sRemoveImageCallbacksInUse 
= true; // This only runs inside dyld's global lock, so ok to use a global for the in-use flag. 
1430                 for (std::vector
<ImageCallback
>::iterator it
=sRemoveImageCallbacks
.begin(); it 
!= sRemoveImageCallbacks
.end(); it
++) { 
1431                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_REMOVE_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*it
), 0); 
1432                         (*it
)(image
->machHeader(), image
->getSlide()); 
1434                 sRemoveImageCallbacksInUse 
= false; 
1436                 if ( sNotifyObjCUnmapped 
!=  NULL 
&& image
->notifyObjC() ) 
1437                         (*sNotifyObjCUnmapped
)(image
->getRealPath(), image
->machHeader()); 
1441         notifySingle(dyld_image_state_terminated
, image
, NULL
); 
1443         // remove from mapped images table 
1444         removedMappedRanges(image
); 
1446         // remove from master list 
1448         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
1449             if ( *it 
== image 
) { 
1450                 sAllImages
.erase(it
); 
1456 #pragma clang diagnostic push 
1457 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
1458         // remove from sDynamicReferences 
1459         OSSpinLockLock(&sDynamicReferencesLock
); 
1460                 sDynamicReferences
.erase(std::remove_if(sDynamicReferences
.begin(), sDynamicReferences
.end(), RefUsesImage(image
)), sDynamicReferences
.end()); 
1461         OSSpinLockUnlock(&sDynamicReferencesLock
); 
1462 #pragma clang diagnostic pop 
1464         // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back) 
1465         if ( sLastImageByAddressCache 
== image 
) 
1466                 sLastImageByAddressCache 
= NULL
; 
1468         // if in root list, pull it out  
1469         for (std::vector
<ImageLoader
*>::iterator it
=sImageRoots
.begin(); it 
!= sImageRoots
.end(); it
++) { 
1470                 if ( *it 
== image 
) { 
1471                         sImageRoots
.erase(it
); 
1476         // If this image is the potential canonical definition of any weak defs, then set them to a tombstone value 
1477         if ( gLinkContext
.weakDefMapInitialized 
&& image
->hasCoalescedExports() ) { 
1479                 const dyld3::MachOAnalyzer
* ma 
= (const dyld3::MachOAnalyzer
*)image
->machHeader(); 
1480                 ma
->forEachWeakDef(diag
, ^(const char *symbolName
, uintptr_t imageOffset
, bool isFromExportTrie
) { 
1481                         auto it 
= gLinkContext
.weakDefMap
.find(symbolName
); 
1482                         assert(it 
!= gLinkContext
.weakDefMap
.end()); 
1483                         it
->second 
= { nullptr, 0 }; 
1484                         if ( !isFromExportTrie 
) { 
1485                                 // The string was already duplicated if we are an export trie 
1486                                 // so only strdup as we are the nlist 
1487                                 size_t hash1 
= ImageLoader::HashCString::hash(it
->first
); 
1488                                 it
->first 
= strdup(it
->first
); 
1489                                 size_t hash2 
= ImageLoader::HashCString::hash(it
->first
); 
1490                                 assert(hash1 
== hash2
); 
1496         if ( gLinkContext
.verboseLoading 
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) { 
1497                 const char *imagePath 
= image
->getPath(); 
1499                 if ( image
->getUUID(imageUUID
) ) { 
1500                         uuid_string_t imageUUIDStr
; 
1501                         uuid_unparse_upper(imageUUID
, imageUUIDStr
); 
1502                         dyld::log("dyld: unloaded: <%s> %s\n", imageUUIDStr
, imagePath
); 
1505                         dyld::log("dyld: unloaded: %s\n", imagePath
); 
1509         // tell gdb, new way 
1510         removeImageFromAllImages(image
->machHeader()); 
1514 void runImageStaticTerminators(ImageLoader
* image
) 
1516         // if in termination list, pull it out and run terminator 
1519                 mightBeMore 
= false; 
1520                 for (std::vector
<ImageLoader
*>::iterator it
=sImageFilesNeedingTermination
.begin(); it 
!= sImageFilesNeedingTermination
.end(); it
++) { 
1521                         if ( *it 
== image 
) { 
1522                                 sImageFilesNeedingTermination
.erase(it
); 
1523                                 if (gLogAPIs
) dyld::log("dlclose(), running static terminators for %p %s\n", image
, image
->getShortName()); 
1524                                 image
->doTermination(gLinkContext
); 
1529         } while ( mightBeMore 
); 
1532 static void terminationRecorder(ImageLoader
* image
) 
1534         sImageFilesNeedingTermination
.push_back(image
); 
1537 const char* getExecutablePath() 
1542 static void runAllStaticTerminators(void* extra
) 
1545                 const size_t imageCount 
= sImageFilesNeedingTermination
.size(); 
1546                 for(size_t i
=imageCount
; i 
> 0; --i
){ 
1547                         ImageLoader
* image 
= sImageFilesNeedingTermination
[i
-1]; 
1548                         image
->doTermination(gLinkContext
); 
1550                 sImageFilesNeedingTermination
.clear(); 
1551                 notifyBatch(dyld_image_state_terminated
, false); 
1553         catch (const char* msg
) { 
1558 void initializeMainExecutable() 
1560         // record that we've reached this step 
1561         gLinkContext
.startedInitializingMainExecutable 
= true; 
1563         // run initialzers for any inserted dylibs 
1564         ImageLoader::InitializerTimingList initializerTimes
[allImagesCount()]; 
1565         initializerTimes
[0].count 
= 0; 
1566         const size_t rootCount 
= sImageRoots
.size(); 
1567         if ( rootCount 
> 1 ) { 
1568                 for(size_t i
=1; i 
< rootCount
; ++i
) { 
1569                         sImageRoots
[i
]->runInitializers(gLinkContext
, initializerTimes
[0]); 
1573         // run initializers for main executable and everything it brings up  
1574         sMainExecutable
->runInitializers(gLinkContext
, initializerTimes
[0]); 
1576         // register cxa_atexit() handler to run static terminators in all loaded images when this process exits 
1577         if ( gLibSystemHelpers 
!= NULL 
)  
1578                 (*gLibSystemHelpers
->cxa_atexit
)(&runAllStaticTerminators
, NULL
, NULL
); 
1580         // dump info if requested 
1581         if ( sEnv
.DYLD_PRINT_STATISTICS 
) 
1582                 ImageLoader::printStatistics((unsigned int)allImagesCount(), initializerTimes
[0]); 
1583         if ( sEnv
.DYLD_PRINT_STATISTICS_DETAILS 
) 
1584                 ImageLoaderMachO::printStatisticsDetails((unsigned int)allImagesCount(), initializerTimes
[0]); 
1587 bool mainExecutablePrebound() 
1589         return sMainExecutable
->usablePrebinding(gLinkContext
); 
1592 ImageLoader
* mainExecutable() 
1594         return sMainExecutable
; 
1600 #if SUPPORT_VERSIONED_PATHS 
1602 // forward reference 
1603 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
); 
1607 // Examines a dylib file and if its current_version is newer than the installed 
1608 // dylib at its install_name, then add the dylib file to sDylibOverrides. 
1610 static void checkDylibOverride(const char* dylibFile
) 
1612         //dyld::log("checkDylibOverride('%s')\n", dylibFile); 
1613         uint32_t altVersion
; 
1614         char sysInstallName
[PATH_MAX
]; 
1615         if ( getDylibVersionAndInstallname(dylibFile
, &altVersion
, sysInstallName
) && (sysInstallName
[0] =='/') ) { 
1616                 //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName); 
1617                 uint32_t sysVersion
; 
1618                 if ( getDylibVersionAndInstallname(sysInstallName
, &sysVersion
, NULL
) ) { 
1619                         //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion); 
1620                         if ( altVersion 
> sysVersion 
) { 
1621                                 //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile); 
1622                                 // see if there already is an override for this dylib 
1623                                 bool entryExists 
= false; 
1624                                 for (std::vector
<DylibOverride
>::iterator it 
= sDylibOverrides
.begin(); it 
!= sDylibOverrides
.end(); ++it
) { 
1625                                         if ( strcmp(it
->installName
, sysInstallName
) == 0 ) { 
1627                                                 uint32_t prevVersion
; 
1628                                                 if ( getDylibVersionAndInstallname(it
->override
, &prevVersion
, NULL
) ) { 
1629                                                         if ( altVersion 
> prevVersion 
) { 
1630                                                                 // found an even newer override 
1631                                                                 free((void*)(it
->override
)); 
1632                                                                 char resolvedPath
[PATH_MAX
]; 
1633                                                                 if ( realpath(dylibFile
, resolvedPath
) != NULL 
) 
1634                                                                         it
->override 
= strdup(resolvedPath
); 
1636                                                                         it
->override 
= strdup(dylibFile
); 
1642                                 if ( ! entryExists 
) { 
1643                                         DylibOverride entry
; 
1644                                         entry
.installName 
= strdup(sysInstallName
); 
1645                                         char resolvedPath
[PATH_MAX
]; 
1646                                         if ( realpath(dylibFile
, resolvedPath
) != NULL 
) 
1647                                                 entry
.override 
= strdup(resolvedPath
); 
1649                                                 entry
.override 
= strdup(dylibFile
); 
1650                                         sDylibOverrides
.push_back(entry
); 
1651                                         //dyld::log("added override: %s -> %s\n", entry.installName, entry.override); 
1659 static void checkDylibOverridesInDir(const char* dirPath
) 
1661         //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath); 
1662         char dylibPath
[PATH_MAX
]; 
1663         long dirPathLen 
= strlcpy(dylibPath
, dirPath
, PATH_MAX
-1); 
1664         if ( dirPathLen 
>= PATH_MAX 
) 
1666         DIR* dirp 
= opendir(dirPath
); 
1667         if ( dirp 
!= NULL
) { 
1669                 dirent
* entp 
= NULL
; 
1670                 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) { 
1673                         if ( entp
->d_type 
!= DT_REG 
)  
1675                         dylibPath
[dirPathLen
] = '/'; 
1676                         dylibPath
[dirPathLen
+1] = '\0'; 
1677                         if ( strlcat(dylibPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX 
) 
1679                         checkDylibOverride(dylibPath
); 
1686 static void checkFrameworkOverridesInDir(const char* dirPath
) 
1688         //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath); 
1689         char frameworkPath
[PATH_MAX
]; 
1690         long dirPathLen 
= strlcpy(frameworkPath
, dirPath
, PATH_MAX
-1); 
1691         if ( dirPathLen 
>= PATH_MAX 
) 
1693         DIR* dirp 
= opendir(dirPath
); 
1694         if ( dirp 
!= NULL
) { 
1696                 dirent
* entp 
= NULL
; 
1697                 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) { 
1700                         if ( entp
->d_type 
!= DT_DIR 
)  
1702                         frameworkPath
[dirPathLen
] = '/'; 
1703                         frameworkPath
[dirPathLen
+1] = '\0'; 
1704                         int dirNameLen 
= (int)strlen(entp
->d_name
); 
1705                         if ( dirNameLen 
< 11 ) 
1707                         if ( strcmp(&entp
->d_name
[dirNameLen
-10], ".framework") != 0 ) 
1709                         if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX 
) 
1711                         if ( strlcat(frameworkPath
, "/", PATH_MAX
) >= PATH_MAX 
) 
1713                         if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX 
) 
1715                         frameworkPath
[strlen(frameworkPath
)-10] = '\0'; 
1716                         checkDylibOverride(frameworkPath
); 
1721 #endif // SUPPORT_VERSIONED_PATHS 
1725 // Turns a colon separated list of strings into a NULL terminated array  
1726 // of string pointers. If mainExecutableDir param is not NULL, 
1727 // substitutes @loader_path with main executable's dir. 
1729 static const char** parseColonList(const char* list
, const char* mainExecutableDir
) 
1731         static const char* sEmptyList
[] = { NULL 
}; 
1733         if ( list
[0] == '\0' )  
1737         for(const char* s
=list
; *s 
!= '\0'; ++s
) { 
1743         const char* start 
= list
; 
1744         char** result 
= new char*[colonCount
+2]; 
1745         for(const char* s
=list
; *s 
!= '\0'; ++s
) { 
1747                         size_t len 
= s
-start
; 
1748                         if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) { 
1749                                 if ( !gLinkContext
.allowAtPaths 
) { 
1750                                         dyld::log("dyld: warning: @loader_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n"); 
1753                                 size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1754                                 char* str 
= new char[mainExecDirLen
+len
+1]; 
1755                                 strcpy(str
, mainExecutableDir
); 
1756                                 strlcat(str
, &start
[13], mainExecDirLen
+len
+1); 
1757                                 str
[mainExecDirLen
+len
-13] = '\0'; 
1759                                 result
[index
++] = str
; 
1761                         else if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) { 
1762                                 if ( !gLinkContext
.allowAtPaths 
) { 
1763                                         dyld::log("dyld: warning: @executable_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n"); 
1766                                 size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1767                                 char* str 
= new char[mainExecDirLen
+len
+1]; 
1768                                 strcpy(str
, mainExecutableDir
); 
1769                                 strlcat(str
, &start
[17], mainExecDirLen
+len
+1); 
1770                                 str
[mainExecDirLen
+len
-17] = '\0'; 
1772                                 result
[index
++] = str
; 
1775                                 char* str 
= new char[len
+1]; 
1776                                 strncpy(str
, start
, len
); 
1779                                 result
[index
++] = str
; 
1783         size_t len 
= strlen(start
); 
1784         if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) { 
1785                 if ( !gLinkContext
.allowAtPaths 
) { 
1786                         dyld::log("dyld: warning: @loader_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n"); 
1790                         size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1791                         char* str 
= new char[mainExecDirLen
+len
+1]; 
1792                         strcpy(str
, mainExecutableDir
); 
1793                         strlcat(str
, &start
[13], mainExecDirLen
+len
+1); 
1794                         str
[mainExecDirLen
+len
-13] = '\0'; 
1795                         result
[index
++] = str
; 
1798         else if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) { 
1799                 if ( !gLinkContext
.allowAtPaths 
) { 
1800                         dyld::log("dyld: warning: @executable_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n"); 
1804                         size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1805                         char* str 
= new char[mainExecDirLen
+len
+1]; 
1806                         strcpy(str
, mainExecutableDir
); 
1807                         strlcat(str
, &start
[17], mainExecDirLen
+len
+1); 
1808                         str
[mainExecDirLen
+len
-17] = '\0'; 
1809                         result
[index
++] = str
; 
1813                 char* str 
= new char[len
+1]; 
1815                 result
[index
++] = str
; 
1817         result
[index
] = NULL
; 
1819         //dyld::log("parseColonList(%s)\n", list); 
1820         //for(int i=0; result[i] != NULL; ++i) 
1821         //      dyld::log("  %s\n", result[i]); 
1822         return (const char**)result
; 
1825 static void     appendParsedColonList(const char* list
, const char* mainExecutableDir
, const char* const ** storage
) 
1827         const char** newlist 
= parseColonList(list
, mainExecutableDir
); 
1828         if ( *storage 
== NULL 
) { 
1829                 // first time, just set 
1833                 // need to append to existing list 
1834                 const char* const* existing 
= *storage
; 
1836                 for(int i
=0; existing
[i
] != NULL
; ++i
) 
1838                 for(int i
=0; newlist
[i
] != NULL
; ++i
) 
1840                 const char** combinedList 
= new const char*[count
+2]; 
1842                 for(int i
=0; existing
[i
] != NULL
; ++i
) 
1843                         combinedList
[index
++] = existing
[i
]; 
1844                 for(int i
=0; newlist
[i
] != NULL
; ++i
) 
1845                         combinedList
[index
++] = newlist
[i
]; 
1846                 combinedList
[index
] = NULL
; 
1847                 delete[] newlist
; // free array, note: strings in newList may be leaked 
1848                 *storage 
= combinedList
; 
1852 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1853 static void paths_expand_roots(const char **paths
, const char *key
, const char *val
) 
1855 //      assert(val != NULL); 
1856 //      assert(paths != NULL); 
1858                 size_t keyLen 
= strlen(key
); 
1859                 for(int i
=0; paths
[i
] != NULL
; ++i
) { 
1860                         if ( strncmp(paths
[i
], key
, keyLen
) == 0 ) { 
1861                                 char* newPath 
= new char[strlen(val
) + (strlen(paths
[i
]) - keyLen
) + 1]; 
1862                                 strcpy(newPath
, val
); 
1863                                 strcat(newPath
, &paths
[i
][keyLen
]); 
1871 static void removePathWithPrefix(const char* paths
[], const char* prefix
) 
1873     size_t prefixLen 
= strlen(prefix
); 
1876     for(i 
= 0; paths
[i
] != NULL
; ++i
) { 
1877         if ( strncmp(paths
[i
], prefix
, prefixLen
) == 0 ) 
1880             paths
[i
-skip
] = paths
[i
]; 
1882     paths
[i
-skip
] = NULL
; 
1888 static void paths_dump(const char **paths
) 
1890 //   assert(paths != NULL); 
1891   const char **strs 
= paths
; 
1892   while(*strs 
!= NULL
) 
1894     dyld::log("\"%s\"\n", *strs
); 
1903 static void printOptions(const char* argv
[]) 
1906         while ( NULL 
!= argv
[i
] ) { 
1907                 dyld::log("opt[%i] = \"%s\"\n", i
, argv
[i
]); 
1912 static void printEnvironmentVariables(const char* envp
[]) 
1914         while ( NULL 
!= *envp 
) { 
1915                 dyld::log("%s\n", *envp
); 
1920 void processDyldEnvironmentVariable(const char* key
, const char* value
, const char* mainExecutableDir
) 
1922         if ( strcmp(key
, "DYLD_FRAMEWORK_PATH") == 0 ) { 
1923                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FRAMEWORK_PATH
); 
1924                 sEnv
.hasOverride 
= true; 
1926         else if ( strcmp(key
, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) { 
1927                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
); 
1928                 sEnv
.hasOverride 
= true; 
1930         else if ( strcmp(key
, "DYLD_LIBRARY_PATH") == 0 ) { 
1931                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_LIBRARY_PATH
); 
1932                 sEnv
.hasOverride 
= true; 
1934         else if ( strcmp(key
, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) { 
1935                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_LIBRARY_PATH
); 
1936                 sEnv
.hasOverride 
= true; 
1938 #if SUPPORT_ROOT_PATH 
1939         else if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) ) { 
1940                 if ( strcmp(value
, "/") != 0 ) { 
1941                         gLinkContext
.rootPaths 
= parseColonList(value
, mainExecutableDir
); 
1942                         for (int i
=0; gLinkContext
.rootPaths
[i
] != NULL
; ++i
) { 
1943                                 if ( gLinkContext
.rootPaths
[i
][0] != '/' ) { 
1944                                         dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n"); 
1945                                         gLinkContext
.rootPaths 
= NULL
; 
1950                 sEnv
.hasOverride 
= true; 
1953         else if ( strcmp(key
, "DYLD_IMAGE_SUFFIX") == 0 ) { 
1954                 gLinkContext
.imageSuffix 
= parseColonList(value
, NULL
); 
1955                 sEnv
.hasOverride 
= true; 
1957         else if ( strcmp(key
, "DYLD_INSERT_LIBRARIES") == 0 ) { 
1958                 sEnv
.DYLD_INSERT_LIBRARIES 
= parseColonList(value
, NULL
); 
1959 #if SUPPORT_ACCELERATE_TABLES 
1960                 sDisableAcceleratorTables 
= true; 
1962                 sEnv
.hasOverride 
= true; 
1964         else if ( strcmp(key
, "DYLD_PRINT_OPTS") == 0 ) { 
1965                 sEnv
.DYLD_PRINT_OPTS 
= true; 
1967         else if ( strcmp(key
, "DYLD_PRINT_ENV") == 0 ) { 
1968                 sEnv
.DYLD_PRINT_ENV 
= true; 
1970         else if ( strcmp(key
, "DYLD_DISABLE_DOFS") == 0 ) { 
1971                 sEnv
.DYLD_DISABLE_DOFS 
= true; 
1973         else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES") == 0 ) { 
1974                 gLinkContext
.verboseLoading 
= true; 
1976         else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) { 
1977                 sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
= true; 
1979         else if ( strcmp(key
, "DYLD_BIND_AT_LAUNCH") == 0 ) { 
1980                 sEnv
.DYLD_BIND_AT_LAUNCH 
= true; 
1982         else if ( strcmp(key
, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) { 
1983                 gLinkContext
.bindFlat 
= true; 
1985         else if ( strcmp(key
, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) { 
1986                 // ignore, no longer relevant but some scripts still set it 
1988         else if ( strcmp(key
, "DYLD_NO_FIX_PREBINDING") == 0 ) { 
1990         else if ( strcmp(key
, "DYLD_PREBIND_DEBUG") == 0 ) { 
1991                 gLinkContext
.verbosePrebinding 
= true; 
1993         else if ( strcmp(key
, "DYLD_PRINT_INITIALIZERS") == 0 ) { 
1994                 gLinkContext
.verboseInit 
= true; 
1996         else if ( strcmp(key
, "DYLD_PRINT_DOFS") == 0 ) { 
1997                 gLinkContext
.verboseDOF 
= true; 
1999         else if ( strcmp(key
, "DYLD_PRINT_STATISTICS") == 0 ) { 
2000                 sEnv
.DYLD_PRINT_STATISTICS 
= true; 
2001 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
2002                 // <rdar://problem/26614838> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps 
2003                 sForceStderr 
= true; 
2006         else if ( strcmp(key
, "DYLD_PRINT_TO_STDERR") == 0 ) { 
2007 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
2008                 // <rdar://problem/26633440> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps 
2009                 sForceStderr 
= true; 
2012         else if ( strcmp(key
, "DYLD_PRINT_STATISTICS_DETAILS") == 0 ) { 
2013                 sEnv
.DYLD_PRINT_STATISTICS_DETAILS 
= true; 
2015         else if ( strcmp(key
, "DYLD_PRINT_SEGMENTS") == 0 ) { 
2016                 gLinkContext
.verboseMapping 
= true; 
2018         else if ( strcmp(key
, "DYLD_PRINT_BINDINGS") == 0 ) { 
2019                 gLinkContext
.verboseBind 
= true; 
2021         else if ( strcmp(key
, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) { 
2022                 gLinkContext
.verboseWeakBind 
= true; 
2024         else if ( strcmp(key
, "DYLD_PRINT_REBASINGS") == 0 ) { 
2025                 gLinkContext
.verboseRebase 
= true; 
2027         else if ( strcmp(key
, "DYLD_PRINT_APIS") == 0 ) { 
2030 #if SUPPORT_ACCELERATE_TABLES 
2031         else if ( strcmp(key
, "DYLD_PRINT_APIS_APP") == 0 ) { 
2035         else if ( strcmp(key
, "DYLD_PRINT_WARNINGS") == 0 ) { 
2036                 gLinkContext
.verboseWarnings 
= true; 
2038         else if ( strcmp(key
, "DYLD_PRINT_RPATHS") == 0 ) { 
2039                 gLinkContext
.verboseRPaths 
= true; 
2041         else if ( strcmp(key
, "DYLD_PRINT_INTERPOSING") == 0 ) { 
2042                 gLinkContext
.verboseInterposing 
= true; 
2044         else if ( strcmp(key
, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) { 
2045                 gLinkContext
.verboseCodeSignatures 
= true; 
2047         else if ( (strcmp(key
, "DYLD_SHARED_REGION") == 0) && gLinkContext
.allowEnvVarsSharedCache 
) { 
2048                 if ( strcmp(value
, "private") == 0 ) { 
2049                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
2051                 else if ( strcmp(value
, "avoid") == 0 ) { 
2052                         gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2054                 else if ( strcmp(value
, "use") == 0 ) { 
2055                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUseSharedRegion
; 
2057                 else if ( value
[0] == '\0' ) { 
2058                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUseSharedRegion
; 
2061                         dyld::warn("unknown option to DYLD_SHARED_REGION.  Valid options are: use, private, avoid\n"); 
2064         else if ( (strcmp(key
, "DYLD_SHARED_CACHE_DIR") == 0) && gLinkContext
.allowEnvVarsSharedCache  
) { 
2065                 sSharedCacheOverrideDir 
= value
; 
2067         else if ( strcmp(key
, "DYLD_USE_CLOSURES") == 0 ) { 
2068                 // Handled elsewhere 
2070         else if ( strcmp(key
, "DYLD_FORCE_INVALID_CACHE_CLOSURES") == 0 ) { 
2071                 if ( dyld3::internalInstall() ) { 
2072                         sForceInvalidSharedCacheClosureFormat 
= true; 
2075         else if ( strcmp(key
, "DYLD_IGNORE_PREBINDING") == 0 ) { 
2076                 if ( strcmp(value
, "all") == 0 ) { 
2077                         gLinkContext
.prebindUsage 
= ImageLoader::kUseNoPrebinding
; 
2079                 else if ( strcmp(value
, "app") == 0 ) { 
2080                         gLinkContext
.prebindUsage 
= ImageLoader::kUseAllButAppPredbinding
; 
2082                 else if ( strcmp(value
, "nonsplit") == 0 ) { 
2083                         gLinkContext
.prebindUsage 
= ImageLoader::kUseSplitSegPrebinding
; 
2085                 else if ( value
[0] == '\0' ) { 
2086                         gLinkContext
.prebindUsage 
= ImageLoader::kUseSplitSegPrebinding
; 
2089                         dyld::warn("unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n"); 
2092 #if SUPPORT_VERSIONED_PATHS 
2093         else if ( strcmp(key
, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) { 
2094                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_LIBRARY_PATH
); 
2095         #if SUPPORT_ACCELERATE_TABLES 
2096                 sDisableAcceleratorTables 
= true; 
2098                 sEnv
.hasOverride 
= true; 
2100         else if ( strcmp(key
, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) { 
2101                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
); 
2102         #if SUPPORT_ACCELERATE_TABLES 
2103                 sDisableAcceleratorTables 
= true; 
2105                 sEnv
.hasOverride 
= true; 
2108 #if !TARGET_OS_SIMULATOR 
2109         else if ( (strcmp(key
, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir 
== NULL
) && gLinkContext
.allowEnvVarsSharedCache 
) { 
2110                 int fd 
= open(value
, O_WRONLY 
| O_CREAT 
| O_APPEND
, 0644); 
2116                         dyld::log("dyld: could not open DYLD_PRINT_TO_FILE='%s', errno=%d\n", value
, errno
); 
2119         else if ( (strcmp(key
, "DYLD_SKIP_MAIN") == 0)) { 
2120                 if ( dyld3::internalInstall() ) 
2123         else if ( (strcmp(key
, "DYLD_JUST_BUILD_CLOSURE") == 0) ) { 
2124                 // handled elsewhere 
2127         else if (strcmp(key
, "DYLD_FORCE_PLATFORM") == 0) { 
2128                 // handled elsewhere 
2130         else if (strcmp(key
, "DYLD_AMFI_FAKE") == 0) { 
2131                 // handled elsewhere 
2134                 dyld::warn("unknown environment variable: %s\n", key
); 
2139 #if SUPPORT_LC_DYLD_ENVIRONMENT 
2140 static void checkLoadCommandEnvironmentVariables() 
2142         // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands 
2143         const uint32_t cmd_count 
= sMainExecutableMachHeader
->ncmds
; 
2144         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)sMainExecutableMachHeader
)+sizeof(macho_header
)); 
2145         const struct load_command
* cmd 
= cmds
; 
2146         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2148                         case LC_DYLD_ENVIRONMENT
: 
2150                                 const struct dylinker_command
* envcmd 
= (struct dylinker_command
*)cmd
; 
2151                                 const char* keyEqualsValue 
= (char*)envcmd 
+ envcmd
->name
.offset
; 
2152                                 char mainExecutableDir
[strlen(sExecPath
)+2]; 
2153                                 strcpy(mainExecutableDir
, sExecPath
); 
2154                                 char* lastSlash 
= strrchr(mainExecutableDir
, '/'); 
2155                                 if ( lastSlash 
!= NULL
) 
2156                                         lastSlash
[1] = '\0'; 
2157                                 // only process variables that start with DYLD_ and end in _PATH 
2158                                 if ( (strncmp(keyEqualsValue
, "DYLD_", 5) == 0) ) { 
2159                                         const char* equals 
= strchr(keyEqualsValue
, '='); 
2160                                         if ( equals 
!= NULL 
) { 
2161                                                 if ( strncmp(&equals
[-5], "_PATH", 5) == 0 ) { 
2162                                                         const char* value 
= &equals
[1]; 
2163                                                         const size_t keyLen 
= equals
-keyEqualsValue
; 
2164                                                         // <rdar://problem/22799635> don't let malformed load command overflow stack 
2165                                                         if ( keyLen 
< 40 ) { 
2167                                                                 strncpy(key
, keyEqualsValue
, keyLen
); 
2169                                                                 //dyld::log("processing: %s\n", keyEqualsValue); 
2170                                                                 //dyld::log("mainExecutableDir: %s\n", mainExecutableDir); 
2171 #if SUPPORT_ROOT_PATH 
2172                                                                 if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) ) 
2175                                                                 processDyldEnvironmentVariable(key
, value
, mainExecutableDir
); 
2183                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2186 #endif // SUPPORT_LC_DYLD_ENVIRONMENT    
2189 static bool hasCodeSignatureLoadCommand(const macho_header
* mh
) 
2191         const uint32_t cmd_count 
= mh
->ncmds
; 
2192         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
2193         const struct load_command
* cmd 
= cmds
; 
2194         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2195                 if (cmd
->cmd 
== LC_CODE_SIGNATURE
)  
2197                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2203 #if SUPPORT_VERSIONED_PATHS 
2204 static void checkVersionedPaths() 
2206         // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer 
2207         if ( sEnv
.DYLD_VERSIONED_LIBRARY_PATH 
!= NULL 
) { 
2208                 for(const char* const* lp 
= sEnv
.DYLD_VERSIONED_LIBRARY_PATH
; *lp 
!= NULL
; ++lp
) { 
2209                         checkDylibOverridesInDir(*lp
); 
2213         // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer 
2214         if ( sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH 
!= NULL 
) { 
2215                 for(const char* const* fp 
= sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
; *fp 
!= NULL
; ++fp
) { 
2216                         checkFrameworkOverridesInDir(*fp
); 
2223 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
2225 // For security, setuid programs ignore DYLD_* environment variables. 
2226 // Additionally, the DYLD_* enviroment variables are removed 
2227 // from the environment, so that any child processes don't see them. 
2229 static void pruneEnvironmentVariables(const char* envp
[], const char*** applep
) 
2231 #if SUPPORT_LC_DYLD_ENVIRONMENT 
2232         checkLoadCommandEnvironmentVariables(); 
2235     // Are we testing dyld on an internal config? 
2236     if ( _simple_getenv(envp
, "DYLD_SKIP_MAIN") != NULL 
) { 
2237                 if ( dyld3::internalInstall() ) 
2241         // delete all DYLD_* and LD_LIBRARY_PATH environment variables 
2242         int removedCount 
= 0; 
2243         const char** d 
= envp
; 
2244         for(const char** s 
= envp
; *s 
!= NULL
; s
++) { 
2246             if ( (strncmp(*s
, "DYLD_", 5) != 0) && (strncmp(*s
, "LD_LIBRARY_PATH=", 16) != 0) ) { 
2254         // slide apple parameters 
2255         if ( removedCount 
> 0 ) { 
2258                         *d 
= d
[removedCount
]; 
2259                 } while ( *d
++ != NULL 
); 
2260                 for(int i
=0; i 
< removedCount
; ++i
) 
2264         // disable framework and library fallback paths for setuid binaries rdar://problem/4589305 
2265         sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= NULL
; 
2266         sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= NULL
; 
2268         if ( removedCount 
> 0 ) 
2269                 strlcat(sLoadingCrashMessage
, ", ignoring DYLD_* env vars", sizeof(sLoadingCrashMessage
)); 
2273 static void defaultUninitializedFallbackPaths(const char* envp
[]) 
2275 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
2276         if ( !gLinkContext
.allowClassicFallbackPaths 
) { 
2277                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= sRestrictedFrameworkFallbackPaths
; 
2278                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH   
= sRestrictedLibraryFallbackPaths
; 
2282         // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment 
2283         const char* home 
= _simple_getenv(envp
, "HOME");; 
2284         if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
== NULL 
) { 
2285                 const char** fpaths 
= sFrameworkFallbackPaths
; 
2287                         removePathWithPrefix(fpaths
, "$HOME"); 
2289                         paths_expand_roots(fpaths
, "$HOME", home
); 
2290                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= fpaths
; 
2293     // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment 
2294         if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
== NULL 
) { 
2295                 const char** lpaths 
= sLibraryFallbackPaths
; 
2297                         removePathWithPrefix(lpaths
, "$HOME"); 
2299                         paths_expand_roots(lpaths
, "$HOME", home
); 
2300                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= lpaths
; 
2303         if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
== NULL 
) 
2304                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= sFrameworkFallbackPaths
; 
2306         if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
== NULL 
) 
2307                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= sLibraryFallbackPaths
; 
2312 static void checkEnvironmentVariables(const char* envp
[]) 
2314         if ( !gLinkContext
.allowEnvVarsPath 
&& !gLinkContext
.allowEnvVarsPrint 
) 
2317         for(p 
= envp
; *p 
!= NULL
; p
++) { 
2318                 const char* keyEqualsValue 
= *p
; 
2319             if ( strncmp(keyEqualsValue
, "DYLD_", 5) == 0 ) { 
2320                         const char* equals 
= strchr(keyEqualsValue
, '='); 
2321                         if ( equals 
!= NULL 
) { 
2322                                 strlcat(sLoadingCrashMessage
, "\n", sizeof(sLoadingCrashMessage
)); 
2323                                 strlcat(sLoadingCrashMessage
, keyEqualsValue
, sizeof(sLoadingCrashMessage
)); 
2324                                 const char* value 
= &equals
[1]; 
2325                                 const size_t keyLen 
= equals
-keyEqualsValue
; 
2327                                 strncpy(key
, keyEqualsValue
, keyLen
); 
2329                                 if ( (strncmp(key
, "DYLD_PRINT_", 11) == 0) && !gLinkContext
.allowEnvVarsPrint 
) 
2331                                 processDyldEnvironmentVariable(key
, value
, NULL
); 
2334                 else if ( strncmp(keyEqualsValue
, "LD_LIBRARY_PATH=", 16) == 0 ) { 
2335                         const char* path 
= &keyEqualsValue
[16]; 
2336                         sEnv
.LD_LIBRARY_PATH 
= parseColonList(path
, NULL
); 
2340 #if SUPPORT_LC_DYLD_ENVIRONMENT 
2341         checkLoadCommandEnvironmentVariables(); 
2342 #endif // SUPPORT_LC_DYLD_ENVIRONMENT    
2344 #if SUPPORT_ROOT_PATH 
2345         // <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together 
2346         if ( (gLinkContext
.imageSuffix 
!= NULL 
&& *gLinkContext
.imageSuffix 
!= NULL
) && (gLinkContext
.rootPaths 
!= NULL
) ) { 
2347                 dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n"); 
2348                 gLinkContext
.imageSuffix 
= NULL
; // this leaks allocations from parseColonList 
2353 #if __x86_64__ && !TARGET_OS_SIMULATOR 
2354 static bool isGCProgram(const macho_header
* mh
, uintptr_t slide
) 
2356         const uint32_t cmd_count 
= mh
->ncmds
; 
2357         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
2358         const struct load_command
* cmd 
= cmds
; 
2359         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2361                         case LC_SEGMENT_COMMAND
: 
2363                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2364                                 if (strcmp(seg
->segname
, "__DATA") == 0) { 
2365                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2366                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2367                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2368                                                 if (strncmp(sect
->sectname
, "__objc_imageinfo", 16) == 0) { 
2369                                                         const uint32_t*  objcInfo 
= (uint32_t*)(sect
->addr 
+ slide
); 
2370                                                         return (objcInfo
[1] & 6); // 6 = (OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC) 
2377                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2383 static void getHostInfo(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
) 
2385 #if CPU_SUBTYPES_SUPPORTED 
2387         sHostCPU                
= CPU_TYPE_ARM
; 
2388         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7K
; 
2389 #elif __ARM_ARCH_7A__ 
2390         sHostCPU                
= CPU_TYPE_ARM
; 
2391         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7
; 
2392 #elif __ARM_ARCH_6K__ 
2393         sHostCPU                
= CPU_TYPE_ARM
; 
2394         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V6
; 
2395 #elif __ARM_ARCH_7F__ 
2396         sHostCPU                
= CPU_TYPE_ARM
; 
2397         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7F
; 
2398 #elif __ARM_ARCH_7S__ 
2399         sHostCPU                
= CPU_TYPE_ARM
; 
2400         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7S
; 
2401 #elif __ARM64_ARCH_8_32__ 
2402         sHostCPU                
= CPU_TYPE_ARM64_32
; 
2403         sHostCPUsubtype 
= CPU_SUBTYPE_ARM64_32_V8
; 
2405         sHostCPU                
= CPU_TYPE_ARM64
; 
2406         sHostCPUsubtype 
= CPU_SUBTYPE_ARM64E
; 
2408         sHostCPU                
= CPU_TYPE_ARM64
; 
2409         sHostCPUsubtype 
= CPU_SUBTYPE_ARM64_V8
; 
2411         struct host_basic_info info
; 
2412         mach_msg_type_number_t count 
= HOST_BASIC_INFO_COUNT
; 
2413         mach_port_t hostPort 
= mach_host_self(); 
2414         kern_return_t result 
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
); 
2415         if ( result 
!= KERN_SUCCESS 
) 
2416                 throw "host_info() failed"; 
2417         sHostCPU                
= info
.cpu_type
; 
2418         sHostCPUsubtype 
= info
.cpu_subtype
; 
2419         mach_port_deallocate(mach_task_self(), hostPort
); 
2421           // host_info returns CPU_TYPE_I386 even for x86_64.  Override that here so that 
2422           // we don't need to mask the cpu type later. 
2423           sHostCPU 
= CPU_TYPE_X86_64
; 
2424         #if !TARGET_OS_SIMULATOR 
2425           sHaswell 
= (sHostCPUsubtype 
== CPU_SUBTYPE_X86_64_H
); 
2426           // <rdar://problem/18528074> x86_64h: Fall back to the x86_64 slice if an app requires GC. 
2428                 if ( isGCProgram(mainExecutableMH
, mainExecutableSlide
) ) { 
2429                         // When running a GC program on a haswell machine, don't use and 'h slices 
2430                         sHostCPUsubtype 
= CPU_SUBTYPE_X86_64_ALL
; 
2432                         gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2441 static void checkSharedRegionDisable(const dyld3::MachOLoaded
* mainExecutableMH
, uintptr_t mainExecutableSlide
) 
2443 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
2444         // if main executable has segments that overlap the shared region, 
2445         // then disable using the shared region 
2446         if ( mainExecutableMH
->intersectsRange(SHARED_REGION_BASE
, SHARED_REGION_SIZE
) ) { 
2447                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2448                 if ( gLinkContext
.verboseMapping 
) 
2449                         dyld::warn("disabling shared region because main executable overlaps\n"); 
2452         if ( !gLinkContext
.allowEnvVarsPath 
) { 
2453                 // <rdar://problem/15280847> use private or no shared region for suid processes 
2454                 gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
2458         // iOS cannot run without shared region 
2461 bool validImage(const ImageLoader
* possibleImage
) 
2463     const size_t imageCount 
= sAllImages
.size(); 
2464     for(size_t i
=0; i 
< imageCount
; ++i
) { 
2465         if ( possibleImage 
== sAllImages
[i
] ) { 
2472 uint32_t getImageCount() 
2474         return (uint32_t)sAllImages
.size(); 
2477 ImageLoader
* getIndexedImage(unsigned int index
) 
2479         if ( index 
< sAllImages
.size() ) 
2480                 return sAllImages
[index
]; 
2484 ImageLoader
* findImageByMachHeader(const struct mach_header
* target
) 
2486         return findMappedRange((uintptr_t)target
); 
2490 ImageLoader
* findImageContainingAddress(const void* addr
) 
2492   #if SUPPORT_ACCELERATE_TABLES 
2493         if ( sAllCacheImagesProxy 
!= NULL 
) { 
2494                 const mach_header
* mh
; 
2497                 if ( sAllCacheImagesProxy
->addressInCache(addr
, &mh
, &path
, &index
) ) 
2498                         return sAllCacheImagesProxy
; 
2501         return findMappedRange((uintptr_t)addr
); 
2505 ImageLoader
* findImageContainingSymbol(const void* symbol
) 
2507         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2508                 ImageLoader
* anImage 
= *it
; 
2509                 if ( anImage
->containsSymbol(symbol
) ) 
2517 void forEachImageDo( void (*callback
)(ImageLoader
*, void* userData
), void* userData
) 
2519         const size_t imageCount 
= sAllImages
.size(); 
2520         for(size_t i
=0; i 
< imageCount
; ++i
) { 
2521                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2522                 (*callback
)(anImage
, userData
); 
2526 ImageLoader
* findLoadedImage(const struct stat
& stat_buf
) 
2528         const size_t imageCount 
= sAllImages
.size(); 
2529         for(size_t i
=0; i 
< imageCount
; ++i
){ 
2530                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2531                 if ( anImage
->statMatch(stat_buf
) ) 
2537 // based on ANSI-C strstr() 
2538 static const char* strrstr(const char* str
, const char* sub
)  
2540         const size_t sublen 
= strlen(sub
); 
2541         for(const char* p 
= &str
[strlen(str
)]; p 
!= str
; --p
) { 
2542                 if ( strncmp(p
, sub
, sublen
) == 0 ) 
2550 // Find framework path 
2552 //  /path/foo.framework/foo                                                             =>   foo.framework/foo   
2553 //  /path/foo.framework/Versions/A/foo                                  =>   foo.framework/Versions/A/foo 
2554 //  /path/foo.framework/Frameworks/bar.framework/bar    =>   bar.framework/bar 
2555 //  /path/foo.framework/Libraries/bar.dylb                              =>   NULL 
2556 //  /path/foo.framework/bar                                                             =>   NULL 
2558 // Returns NULL if not a framework path 
2560 static const char* getFrameworkPartialPath(const char* path
) 
2562         const char* dirDot 
= strrstr(path
, ".framework/"); 
2563         if ( dirDot 
!= NULL 
) { 
2564                 const char* dirStart 
= dirDot
; 
2565                 for ( ; dirStart 
>= path
; --dirStart
) { 
2566                         if ( (*dirStart 
== '/') || (dirStart 
== path
) ) { 
2567                                 const char* frameworkStart 
= &dirStart
[1]; 
2568                                 if ( dirStart 
== path 
) 
2570                                 size_t len 
= dirDot 
- frameworkStart
; 
2571                                 char framework
[len
+1]; 
2572                                 strncpy(framework
, frameworkStart
, len
); 
2573                                 framework
[len
] = '\0'; 
2574                                 const char* leaf 
= strrchr(path
, '/'); 
2575                                 if ( leaf 
!= NULL 
) { 
2576                                         if ( strcmp(framework
, &leaf
[1]) == 0 ) { 
2577                                                 return frameworkStart
; 
2579                                         if (  gLinkContext
.imageSuffix 
!= NULL 
) { 
2580                                                 // some debug frameworks have install names that end in _debug 
2581                                                 if ( strncmp(framework
, &leaf
[1], len
) == 0 ) { 
2582                                                         for (const char* const* suffix
=gLinkContext
.imageSuffix
; *suffix 
!= NULL
; ++suffix
) { 
2583                                                                 if ( strcmp(*suffix
, &leaf
[len
+1]) == 0 ) 
2584                                                                         return frameworkStart
; 
2596 static const char* getLibraryLeafName(const char* path
) 
2598         const char* start 
= strrchr(path
, '/'); 
2599         if ( start 
!= NULL 
) 
2606 // only for architectures that use cpu-sub-types 
2607 #if CPU_SUBTYPES_SUPPORTED  
2609 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST 
= -1; 
2613 //      A fat file may contain multiple sub-images for the same CPU type. 
2614 //      In that case, dyld picks which sub-image to use by scanning a table 
2615 //      of preferred cpu-sub-types for the running cpu.   
2617 //      There is one row in the table for each cpu-sub-type on which dyld might run. 
2618 //  The first entry in a row is that cpu-sub-type.  It is followed by all 
2619 //      cpu-sub-types that can run on that cpu, if preferred order.  Each row ends with  
2620 //      a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),  
2621 //  followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row. 
2627 //     ARM sub-type lists 
2629 const int kARM_RowCount 
= 8; 
2630 static const cpu_subtype_t kARM
[kARM_RowCount
][9] = {  
2632         // armv7f can run: v7f, v7, v6, v5, and v4 
2633         {  CPU_SUBTYPE_ARM_V7F
, CPU_SUBTYPE_ARM_V7
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2635         // armv7k can run: v7k 
2636         {  CPU_SUBTYPE_ARM_V7K
, CPU_SUBTYPE_END_OF_LIST 
}, 
2638         // armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4 
2639         {  CPU_SUBTYPE_ARM_V7S
, CPU_SUBTYPE_ARM_V7
, CPU_SUBTYPE_ARM_V7F
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2641         // armv7 can run: v7, v6, v5, and v4 
2642         {  CPU_SUBTYPE_ARM_V7
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2644         // armv6 can run: v6, v5, and v4 
2645         {  CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
}, 
2647         // xscale can run: xscale, v5, and v4 
2648         {  CPU_SUBTYPE_ARM_XSCALE
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
}, 
2650         // armv5 can run: v5 and v4 
2651         {  CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
}, 
2653         // armv4 can run: v4 
2654         {  CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
}, 
2660 //     ARM64 sub-type lists 
2662 const int kARM64_RowCount 
= 2; 
2663 static const cpu_subtype_t kARM64
[kARM64_RowCount
][4] = { 
2665         // armv64e can run: 64e, 64 
2666         {  CPU_SUBTYPE_ARM64E
, CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2668         // armv64 can run: 64 
2669         {  CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2672 #if __ARM64_ARCH_8_32__ 
2673 const int kARM64_32_RowCount 
= 2; 
2674 static const cpu_subtype_t kARM64_32
[kARM64_32_RowCount
][4] = { 
2676         // armv64_32 can run: v8 
2677         {  CPU_SUBTYPE_ARM64_32_V8
, CPU_SUBTYPE_END_OF_LIST 
}, 
2679         // armv64 can run: 64 
2680         {  CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2688 //     x86_64 sub-type lists 
2690 const int kX86_64_RowCount 
= 2; 
2691 static const cpu_subtype_t kX86_64
[kX86_64_RowCount
][5] = { 
2693         // x86_64h can run: x86_64h, x86_64h(lib), x86_64(lib), and x86_64 
2694         { CPU_SUBTYPE_X86_64_H
, (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_H
), (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_ALL
), CPU_SUBTYPE_X86_64_ALL
,  CPU_SUBTYPE_END_OF_LIST 
}, 
2696         // x86_64 can run: x86_64(lib) and x86_64 
2697         { CPU_SUBTYPE_X86_64_ALL
, (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_ALL
), CPU_SUBTYPE_END_OF_LIST 
}, 
2703 // scan the tables above to find the cpu-sub-type-list for this machine 
2704 static const cpu_subtype_t
* findCPUSubtypeList(cpu_type_t cpu
, cpu_subtype_t subtype
) 
2709                         for (int i
=0; i 
< kARM_RowCount 
; ++i
) { 
2710                                 if ( kARM
[i
][0] == subtype 
) 
2716                 case CPU_TYPE_ARM64
: 
2717                         for (int i
=0; i 
< kARM64_RowCount 
; ++i
) { 
2718                                 if ( kARM64
[i
][0] == subtype 
) 
2723 #if __ARM64_ARCH_8_32__ 
2724                 case CPU_TYPE_ARM64_32
: 
2725                         for (int i
=0; i 
< kARM64_32_RowCount 
; ++i
) { 
2726                                 if ( kARM64_32
[i
][0] == subtype 
) 
2727                                         return kARM64_32
[i
]; 
2734                 case CPU_TYPE_X86_64
: 
2735                         for (int i
=0; i 
< kX86_64_RowCount 
; ++i
) { 
2736                                 if ( kX86_64
[i
][0] == subtype 
) 
2748 // scan fat table-of-contents for best most preferred subtype 
2749 static bool fatFindBestFromOrderedList(cpu_type_t cpu
, const cpu_subtype_t list
[], const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2751         const fat_arch
* const archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2752         for (uint32_t subTypeIndex
=0; list
[subTypeIndex
] != CPU_SUBTYPE_END_OF_LIST
; ++subTypeIndex
) { 
2753                 for(uint32_t fatIndex
=0; fatIndex 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++fatIndex
) { 
2754                         if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cputype
) == cpu
)  
2755                                 && (list
[subTypeIndex
] == (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cpusubtype
)) ) { 
2756                                 *offset 
= OSSwapBigToHostInt32(archs
[fatIndex
].offset
); 
2757                                 *len 
= OSSwapBigToHostInt32(archs
[fatIndex
].size
); 
2765 // scan fat table-of-contents for exact match of cpu and cpu-sub-type 
2766 static bool fatFindExactMatch(cpu_type_t cpu
, cpu_subtype_t subtype
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2768         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2769         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
2770                 if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) 
2771                         && ((cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == subtype
) ) { 
2772                         *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2773                         *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2780 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types 
2781 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2783         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2784         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
2785                 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) { 
2789                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM_ALL 
) { 
2790                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2791                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2797                                 case CPU_TYPE_ARM64
: 
2798                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM64_ALL 
) { 
2799                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2800                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2806                                 case CPU_TYPE_X86_64
: 
2807                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_X86_64_ALL 
) { 
2808                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2809                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2820 #endif // CPU_SUBTYPES_SUPPORTED 
2824 // Validate the fat_header and fat_arch array: 
2826 // 1) arch count would not cause array to extend past 4096 byte read buffer 
2827 // 2) no slice overlaps the fat_header and arch array 
2828 // 3) arch list does not contain duplicate cputype/cpusubtype tuples 
2829 // 4) arch list does not have two overlapping slices. 
2831 static bool fatValidate(const fat_header
* fh
) 
2833         if ( fh
->magic 
!= OSSwapBigToHostInt32(FAT_MAGIC
) ) 
2836         // since only first 4096 bytes of file read, we can only handle up to 204 slices. 
2837         const uint32_t sliceCount 
= OSSwapBigToHostInt32(fh
->nfat_arch
); 
2838         if ( sliceCount 
> 204 ) 
2841         // compare all slices looking for conflicts 
2842         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2843         for (uint32_t i
=0; i 
< sliceCount
; ++i
) { 
2844                 uint32_t i_offset     
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2845                 uint32_t i_size       
= OSSwapBigToHostInt32(archs
[i
].size
); 
2846                 uint32_t i_cputype    
= OSSwapBigToHostInt32(archs
[i
].cputype
); 
2847                 uint32_t i_cpusubtype 
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
); 
2848                 uint32_t i_end        
= i_offset 
+ i_size
; 
2849                 // slice cannot overlap with header 
2850                 if ( i_offset 
< 4096 ) 
2852                 // slice size cannot overflow 
2853                 if ( i_end 
< i_offset 
) 
2855                 for (uint32_t j
=i
+1; j 
< sliceCount
; ++j
) { 
2856                         uint32_t j_offset     
= OSSwapBigToHostInt32(archs
[j
].offset
); 
2857                         uint32_t j_size       
= OSSwapBigToHostInt32(archs
[j
].size
); 
2858                         uint32_t j_cputype    
= OSSwapBigToHostInt32(archs
[j
].cputype
); 
2859                         uint32_t j_cpusubtype 
= OSSwapBigToHostInt32(archs
[j
].cpusubtype
); 
2860                         uint32_t j_end        
= j_offset 
+ j_size
; 
2861                         // duplicate slices types not allowed 
2862                         if ( (i_cputype 
== j_cputype
) && (i_cpusubtype 
== j_cpusubtype
) ) 
2864                         // slice size cannot overflow 
2865                         if ( j_end 
< j_offset 
) 
2867                         // check for overlap of slices 
2868                         if ( i_offset 
<= j_offset 
) { 
2869                                 if ( j_offset 
< i_end 
) 
2870                                         return false; //  j overlaps end of i 
2873                                 //  j overlaps end of i 
2874                                 if ( i_offset 
< j_end 
) 
2875                                         return false;  //  i overlaps end of j 
2883 // A fat file may contain multiple sub-images for the same cpu-type, 
2884 // each optimized for a different cpu-sub-type (e.g G3 or G5). 
2885 // This routine picks the optimal sub-image. 
2887 static bool fatFindBest(const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2889         if ( !fatValidate(fh
) ) 
2892 #if CPU_SUBTYPES_SUPPORTED 
2893         // assume all dylibs loaded must have same cpu type as main executable 
2894         const cpu_type_t cpu 
= sMainExecutableMachHeader
->cputype
; 
2896         // We only know the subtype to use if the main executable cpu type matches the host 
2897         if ( cpu 
== sHostCPU 
) { 
2898                 // get preference ordered list of subtypes 
2899                 const cpu_subtype_t
* subTypePreferenceList 
= findCPUSubtypeList(cpu
, sHostCPUsubtype
); 
2901                 // use ordered list to find best sub-image in fat file 
2902                 if ( subTypePreferenceList 
!= NULL 
) { 
2903                         if ( fatFindBestFromOrderedList(cpu
, subTypePreferenceList
, fh
, offset
, len
) ) 
2907                 // if running cpu is not in list, try for an exact match 
2908                 if ( fatFindExactMatch(cpu
, sHostCPUsubtype
, fh
, offset
, len
) ) 
2912         // running on an uknown cpu, can only load generic code 
2913         return fatFindRunsOnAllCPUs(cpu
, fh
, offset
, len
); 
2915         // just find first slice with matching architecture 
2916         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2917         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
2918                 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == sMainExecutableMachHeader
->cputype
) { 
2919                         *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2920                         *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2931 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used 
2932 // on the current processor. // 
2933 bool isCompatibleMachO(const uint8_t* firstPage
, const char* path
) 
2935 #if CPU_SUBTYPES_SUPPORTED 
2936         // It is deemed compatible if any of the following are true: 
2937         //  1) mach_header subtype is in list of compatible subtypes for running processor 
2938         //  2) mach_header subtype is same as running processor subtype 
2939         //  3) mach_header subtype runs on all processor variants 
2940         const mach_header
* mh 
= (mach_header
*)firstPage
; 
2941         if ( mh
->magic 
== sMainExecutableMachHeader
->magic 
) { 
2942                 if ( mh
->cputype 
== sMainExecutableMachHeader
->cputype 
) { 
2943                         if ( mh
->cputype 
== sHostCPU 
) { 
2944                                 // get preference ordered list of subtypes that this machine can use 
2945                                 const cpu_subtype_t
* subTypePreferenceList 
= findCPUSubtypeList(mh
->cputype
, sHostCPUsubtype
); 
2946                                 if ( subTypePreferenceList 
!= NULL 
) { 
2947                                         // if image's subtype is in the list, it is compatible 
2948                                         for (const cpu_subtype_t
* p 
= subTypePreferenceList
; *p 
!= CPU_SUBTYPE_END_OF_LIST
; ++p
) { 
2949                                                 if ( *p 
== mh
->cpusubtype 
) 
2952                                         // have list and not in list, so not compatible 
2953                                         throwf("incompatible cpu-subtype: 0x%08X in %s", mh
->cpusubtype
, path
); 
2955                                 // unknown cpu sub-type, but if exact match for current subtype then ok to use 
2956                                 if ( mh
->cpusubtype 
== sHostCPUsubtype 
)  
2960                         // cpu type has no ordered list of subtypes 
2961                         switch (mh
->cputype
) { 
2963                                 case CPU_TYPE_X86_64
: 
2964                                         // subtypes are not used or these architectures 
2970         // For architectures that don't support cpu-sub-types 
2971         // this just check the cpu type. 
2972         const mach_header
* mh 
= (mach_header
*)firstPage
; 
2973         if ( mh
->magic 
== sMainExecutableMachHeader
->magic 
) { 
2974                 if ( mh
->cputype 
== sMainExecutableMachHeader
->cputype 
) { 
2985 // The kernel maps in main executable before dyld gets control.  We need to  
2986 // make an ImageLoader* for the already mapped in main executable. 
2987 static ImageLoaderMachO
* instantiateFromLoadedImage(const macho_header
* mh
, uintptr_t slide
, const char* path
) 
2989         // try mach-o loader 
2990         if ( isCompatibleMachO((const uint8_t*)mh
, path
) ) { 
2991                 ImageLoader
* image 
= ImageLoaderMachO::instantiateMainExecutable(mh
, slide
, path
, gLinkContext
); 
2993                 return (ImageLoaderMachO
*)image
; 
2996         throw "main executable not a known format"; 
2999 #if SUPPORT_ACCELERATE_TABLES 
3000 static bool dylibsCanOverrideCache() 
3002         if ( !dyld3::internalInstall() ) 
3004         return ( (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) && (sSharedCacheLoadInfo
.loadAddress
->header
.cacheType 
== kDyldSharedCacheTypeDevelopment
) ); 
3008 const void* imMemorySharedCacheHeader() 
3010         return sSharedCacheLoadInfo
.loadAddress
; 
3014 const char* getStandardSharedCacheFilePath() 
3016         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) 
3017                 return sSharedCacheLoadInfo
.path
; 
3022 bool hasInsertedOrInterposingLibraries() { 
3023         return (sInsertedDylibCount 
> 0) || ImageLoader::haveInterposingTuples(); 
3027 #if SUPPORT_VERSIONED_PATHS 
3028 static bool findInSharedCacheImage(const char* path
, bool searchByPath
, const struct stat
* stat_buf
, const macho_header
** mh
, const char** pathInCache
, long* slide
) 
3030         dyld3::SharedCacheFindDylibResults results
; 
3031         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &results
) ) { 
3032                 *mh                      
= (macho_header
*)results
.mhInCache
; 
3033                 *pathInCache 
= results
.pathInCache
; 
3034                 *slide       
= results
.slideInCache
; 
3041 bool inSharedCache(const char* path
) 
3043         return dyld3::pathIsInSharedCacheImage(sSharedCacheLoadInfo
, path
); 
3047 static ImageLoader
* checkandAddImage(ImageLoader
* image
, const LoadContext
& context
) 
3049         // now sanity check that this loaded image does not have the same install path as any existing image 
3050         const char* loadedImageInstallPath 
= image
->getInstallPath(); 
3051         if ( image
->isDylib() && (loadedImageInstallPath 
!= NULL
) && (loadedImageInstallPath
[0] == '/') ) { 
3052                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
3053                         ImageLoader
* anImage 
= *it
; 
3054                         const char* installPath 
= anImage
->getInstallPath(); 
3055                         if ( installPath 
!= NULL
) { 
3056                                 if ( strcmp(loadedImageInstallPath
, installPath
) == 0 ) { 
3057                                         //dyld::log("duplicate(%s) => %p\n", installPath, anImage); 
3059                                         ImageLoader::deleteImage(image
); 
3066         // some API's restrict what they can load 
3067         if ( context
.mustBeBundle 
&& !image
->isBundle() ) 
3068                 throw "not a bundle"; 
3069         if ( context
.mustBeDylib 
&& !image
->isDylib() ) 
3070                 throw "not a dylib"; 
3072         // regular main executables cannot be loaded  
3073         if ( image
->isExecutable() ) { 
3074                 if ( !context
.canBePIE 
|| !image
->isPositionIndependentExecutable() ) 
3075                         throw "can't load a main executable"; 
3078         // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
3079         if ( ! image
->isBundle() )  
3085 #if TARGET_OS_SIMULATOR  
3086 static bool isSimulatorBinary(const uint8_t* firstPages
, const char* path
) 
3088         const macho_header
* mh 
= (macho_header
*)firstPages
; 
3089         const uint32_t cmd_count 
= mh
->ncmds
; 
3090         const load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
3091         const load_command
* const cmdsEnd 
= (load_command
*)((char*)cmds 
+ mh
->sizeofcmds
); 
3092         const struct load_command
* cmd 
= cmds
; 
3093         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
3096                         case LC_VERSION_MIN_WATCHOS
: 
3099                         case LC_VERSION_MIN_TVOS
: 
3102                         case LC_VERSION_MIN_IPHONEOS
: 
3105                         case LC_VERSION_MIN_MACOSX
: 
3106                                 // grandfather in a few libSystem dylibs 
3107                                 if ((strcmp(path
, "/usr/lib/system/libsystem_kernel.dylib") == 0) || 
3108                                     (strcmp(path
, "/usr/lib/system/libsystem_platform.dylib") == 0) || 
3109                                     (strcmp(path
, "/usr/lib/system/libsystem_pthread.dylib") == 0) || 
3110                                     (strcmp(path
, "/usr/lib/system/libsystem_platform_debug.dylib") == 0) || 
3111                                     (strcmp(path
, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0) || 
3112                                     (strcmp(path
, "/sbin/launchd_sim_trampoline") == 0) || 
3113                                     (strcmp(path
, "/usr/sbin/iokitsimd") == 0) || 
3114                                     (strcmp(path
, "/usr/lib/system/host/liblaunch_sim.dylib") == 0)) 
3117                         case LC_BUILD_VERSION
: 
3119                                 // Same logic as above, but for LC_BUILD_VERSION instead of legacy load commands 
3120                                 const struct build_version_command
* buildVersionCmd 
= (build_version_command
*)cmd
; 
3121                                 switch(buildVersionCmd
->platform
) { 
3122                                         case PLATFORM_IOSSIMULATOR
: 
3123                                         case PLATFORM_TVOSSIMULATOR
: 
3124                                         case PLATFORM_WATCHOSSIMULATOR
: 
3125                                         case PLATFORM_WATCHOS
: 
3127         #if TARGET_OS_IOSMAC 
3131                                         case PLATFORM_MACOS
: 
3132                                                 if ((strcmp(path
, "/usr/lib/system/libsystem_kernel.dylib") == 0) || 
3133                                                         (strcmp(path
, "/usr/lib/system/libsystem_platform.dylib") == 0) || 
3134                                                         (strcmp(path
, "/usr/lib/system/libsystem_pthread.dylib") == 0) || 
3135                                                         (strcmp(path
, "/usr/lib/system/libsystem_platform_debug.dylib") == 0) || 
3136                                                         (strcmp(path
, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0) || 
3137                                                         (strcmp(path
, "/sbin/launchd_sim_trampoline") == 0) || 
3138                                                         (strcmp(path
, "/usr/sbin/iokitsimd") == 0) || 
3139                                                         (strcmp(path
, "/usr/lib/system/host/liblaunch_sim.dylib") == 0)) 
3144                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
3145                 if ( cmd 
> cmdsEnd 
) 
3152 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3153 static bool iOSonMacDenied(const char* path
) 
3155         static char*  blackListBuffer   
= nullptr; 
3156         static size_t blackListSize     
= 0; 
3157         static bool   tried                     
= false; 
3159                 // only try to map file once 
3160                 blackListBuffer 
= (char*)mapFileReadOnly("/System/iOSSupport/dyld/macOS-deny-list.txt", blackListSize
); 
3163         __block 
bool result 
= false; 
3164         if ( blackListBuffer 
!= nullptr ) { 
3165                 dyld3::forEachLineInFile(blackListBuffer
, blackListSize
, ^(const char* line
, bool& stop
) { 
3166                         // lines in the file are prefixes.  Any path that starts with one of these lines is allowed to be unzippered 
3167                         size_t lineLen 
= strlen(line
); 
3168                         if ( (*line 
== '/') && strncmp(line
, path
, lineLen
) == 0 ) { 
3178 // map in file and instantiate an ImageLoader 
3179 static ImageLoader
* loadPhase6(int fd
, const struct stat
& stat_buf
, const char* path
, const LoadContext
& context
) 
3181         //dyld::log("%s(%s)\n", __func__ , path); 
3182         uint64_t fileOffset 
= 0; 
3183         uint64_t fileLength 
= stat_buf
.st_size
; 
3185         // validate it is a file (not directory) 
3186         if ( (stat_buf
.st_mode 
& S_IFMT
) != S_IFREG 
)  
3189         uint8_t firstPages
[MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
]; 
3190         uint8_t *firstPagesPtr 
= firstPages
; 
3191         bool shortPage 
= false; 
3193         // min mach-o file is 4K 
3194         if ( fileLength 
< 4096 ) { 
3195                 if ( pread(fd
, firstPages
, (size_t)fileLength
, 0) != (ssize_t
)fileLength 
) 
3196                         throwf("pread of short file failed: %d", errno
); 
3200                 // optimistically read only first 4KB 
3201                 if ( pread(fd
, firstPages
, 4096, 0) != 4096 ) 
3202                         throwf("pread of first 4K failed: %d", errno
); 
3205         // if fat wrapper, find usable sub-file 
3206         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPages
; 
3207         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
3208                 if ( OSSwapBigToHostInt32(fileStartAsFat
->nfat_arch
) > ((4096 - sizeof(fat_header
)) / sizeof(fat_arch
)) ) 
3209                         throwf("fat header too large: %u entries", OSSwapBigToHostInt32(fileStartAsFat
->nfat_arch
)); 
3210                 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) { 
3211                         if ( (fileOffset
+fileLength
) > (uint64_t)(stat_buf
.st_size
) ) 
3212                                 throwf("truncated fat file.  file length=%llu, but needed slice goes to %llu", stat_buf
.st_size
, fileOffset
+fileLength
); 
3213                         if (pread(fd
, firstPages
, 4096, fileOffset
) != 4096) 
3214                                 throwf("pread of fat file failed: %d", errno
); 
3217                         throw "no matching architecture in universal wrapper"; 
3221         // try mach-o loader 
3223                 throw "file too short"; 
3225         if ( isCompatibleMachO(firstPages
, path
) ) { 
3227                 // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded 
3228                 const mach_header
* mh 
= (mach_header
*)firstPages
; 
3229                 switch ( mh
->filetype 
) { 
3235                                 throw "mach-o, but wrong filetype"; 
3238                 uint32_t headerAndLoadCommandsSize 
= sizeof(macho_header
) + mh
->sizeofcmds
; 
3239                 if ( headerAndLoadCommandsSize 
> MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE 
) 
3240                         throwf("malformed mach-o: load commands size (%u) > %u", headerAndLoadCommandsSize
, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
); 
3242                 if ( headerAndLoadCommandsSize 
> fileLength 
) 
3243                         dyld::throwf("malformed mach-o: load commands size (%u) > mach-o file size (%llu)", headerAndLoadCommandsSize
, fileLength
); 
3245                 if ( headerAndLoadCommandsSize 
> 4096 ) { 
3247                         unsigned readAmount 
= headerAndLoadCommandsSize 
- 4096; 
3248                         if ( pread(fd
, &firstPages
[4096], readAmount
, fileOffset
+4096) != readAmount 
) 
3249                                 throwf("pread of extra load commands past 4KB failed: %d", errno
); 
3252 #if TARGET_OS_SIMULATOR  
3253                 // <rdar://problem/14168872> dyld_sim should restrict loading osx binaries 
3254                 if ( !isSimulatorBinary(firstPages
, path
) ) { 
3256                         throw "mach-o, but not built for watchOS simulator"; 
3258                         throw "mach-o, but not built for tvOS simulator"; 
3260                         throw "mach-o, but not built for iOS simulator"; 
3265 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3266                 if ( gLinkContext
.iOSonMac 
) { 
3267                         const dyld3::MachOFile
* mf 
= (dyld3::MachOFile
*)firstPages
; 
3268                         bool supportsiOSMac 
= mf
->supportsPlatform(dyld3::Platform::iOSMac
); 
3269                         if ( !supportsiOSMac 
&& iOSonMacDenied(path
) ) { 
3270                                 throw "mach-o, but not built for UIKitForMac"; 
3273                 else if ( gLinkContext
.driverKit 
) { 
3274                         const dyld3::MachOFile
* mf 
= (dyld3::MachOFile
*)firstPages
; 
3275                         bool isDriverKitDylib 
= mf
->supportsPlatform(dyld3::Platform::driverKit
); 
3276                         if ( !isDriverKitDylib 
) { 
3277                                 throw "mach-o, but not built for driverkit"; 
3283                 if ( (sMainExecutableMachHeader
->cpusubtype 
== CPU_SUBTYPE_ARM64E
) && (mh
->cpusubtype 
!= CPU_SUBTYPE_ARM64E
) ) 
3284                         throw "arm64 dylibs cannot be loaded into arm64e processes"; 
3286                 ImageLoader
* image 
= nullptr; 
3288                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_MAP_IMAGE
, path
, 0, 0); 
3289                         image 
= ImageLoaderMachO::instantiateFromFile(path
, fd
, firstPagesPtr
, headerAndLoadCommandsSize
, fileOffset
, fileLength
, stat_buf
, gLinkContext
); 
3290                         timer
.setData4((uint64_t)image
->machHeader()); 
3294                 return checkandAddImage(image
, context
); 
3297         // try other file formats here... 
3300         // throw error about what was found 
3301         switch (*(uint32_t*)firstPages
) { 
3306                         throw "mach-o, but wrong architecture"; 
3308                 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",  
3309                         firstPages
[0], firstPages
[1], firstPages
[2], firstPages
[3], firstPages
[4], firstPages
[5], firstPages
[6],firstPages
[7]); 
3314 static ImageLoader
* loadPhase5open(const char* path
, const LoadContext
& context
, const struct stat
& stat_buf
, std::vector
<const char*>* exceptions
) 
3316         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3318         // open file (automagically closed when this function exits) 
3319         FileOpener 
file(path
); 
3321         // just return NULL if file not found, but record any other errors 
3322         if ( file
.getFileDescriptor() == -1 ) { 
3324                 if ( err 
!= ENOENT 
) { 
3326                         if ( (err 
== EPERM
) && sandboxBlockedOpen(path
) ) 
3327                                 newMsg 
= dyld::mkstringf("file system sandbox blocked open() of '%s'", path
); 
3329                                 newMsg 
= dyld::mkstringf("%s: open() failed with errno=%d", path
, err
); 
3330                         exceptions
->push_back(newMsg
); 
3336                 return loadPhase6(file
.getFileDescriptor(), stat_buf
, path
, context
); 
3338         catch (const char* msg
) { 
3339                 const char* newMsg 
= dyld::mkstringf("%s: %s", path
, msg
); 
3340                 exceptions
->push_back(newMsg
); 
3346 static bool isFileRelativePath(const char* path
) 
3348         if ( path
[0] == '/' ) 
3350         if ( path
[0] != '.' ) 
3352         if ( path
[1] == '/' ) 
3354         if ( (path
[1] == '.') && (path
[2] == '/') ) 
3361 static ImageLoader
* loadPhase5load(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3363         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3365         // <rdar://problem/47682983> don't allow file system relative paths in hardened programs 
3366         if ( (exceptions 
!= NULL
) &&  !gLinkContext
.allowEnvVarsPath 
&& isFileRelativePath(path
) ) { 
3367                 exceptions
->push_back("file system relative paths not allowed in hardened programs"); 
3371 #if SUPPORT_ACCELERATE_TABLES 
3372         if ( sAllCacheImagesProxy 
!= NULL 
) { 
3373                 if ( sAllCacheImagesProxy
->hasDylib(path
, &cacheIndex
) ) 
3374                         return sAllCacheImagesProxy
; 
3378         struct stat statBuf
; 
3379         bool didStat 
= false; 
3381         __block 
dyld3::SharedCacheFindDylibResults shareCacheResults
; 
3382         shareCacheResults
.image 
= nullptr; 
3384 #if TARGET_OS_SIMULATOR 
3386         auto findSharedCacheImage 
= ^() { 
3387                 // in simulators, 'path' has DYLD_ROOT_PATH prepended, but cache index does not have the prefix, so use orgPath 
3388                 return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, orgPath
, &shareCacheResults
); 
3393         auto findSharedCacheImage 
= ^() { 
3394 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3395                 if ( gLinkContext
.iOSonMac 
) { 
3396                         // On iOSMac, we are also running with DYLD_ROOT_PATH set, but want to look up the orgPath 
3397                         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, orgPath
, &shareCacheResults
) ) 
3401                 return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
); 
3406         if ( findSharedCacheImage() ) { 
3407                 // see if this image in the cache was already loaded via a different path 
3408                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); ++it
) { 
3409                         ImageLoader
* anImage 
= *it
; 
3410                         if ( (const mach_header
*)anImage
->machHeader() == shareCacheResults
.mhInCache 
) 
3413                 // if RTLD_NOLOAD, do nothing if not already loaded 
3414                 if ( context
.dontLoad 
) { 
3415                         // <rdar://33412890> possible that there is an override of cache 
3416                         if ( my_stat(path
, &statBuf
) == 0 ) { 
3417                                 ImageLoader
* imageLoader 
= findLoadedImage(statBuf
); 
3418                                 if ( imageLoader 
!= NULL 
) 
3423                 bool useCache 
= false; 
3424                 if ( shareCacheResults
.image 
== nullptr ) { 
3425                         // HACK to support old caches 
3426                         existsOnDisk 
= ( my_stat(path
, &statBuf
) == 0 ); 
3429                         useCache 
= !existsOnDisk
; 
3432                         // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache 
3433                         bzero(&statBuf
, sizeof(statBuf
)); 
3434                         if ( shareCacheResults
.image
->overridableDylib() ) { 
3435                                 existsOnDisk 
= ( my_stat(path
, &statBuf
) == 0 ); 
3438                                 if ( sSharedCacheLoadInfo
.loadAddress
->header
.dylibsExpectedOnDisk 
) { 
3439                                         uint64_t expectedINode
; 
3440                                         uint64_t expectedMtime
; 
3441                                         if ( shareCacheResults
.image
->hasFileModTimeAndInode(expectedINode
, expectedMtime
) ) { 
3442                                                 if ( (expectedMtime 
== statBuf
.st_mtime
) && (expectedINode 
== statBuf
.st_ino
) ) 
3447                                         if ( !existsOnDisk 
) 
3456 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3457                         if ( gLinkContext
.iOSonMac 
) { 
3458                                 const dyld3::MachOFile
* mf 
= (dyld3::MachOFile
*)shareCacheResults
.mhInCache
; 
3459                                 bool supportsiOSMac 
= mf
->supportsPlatform(dyld3::Platform::iOSMac
); 
3460                                 if ( !supportsiOSMac 
&& iOSonMacDenied(path
) ) { 
3461                                         throw "mach-o, but not built for UIKitForMac"; 
3465                         ImageLoader
* imageLoader 
= ImageLoaderMachO::instantiateFromCache((macho_header
*)shareCacheResults
.mhInCache
, shareCacheResults
.pathInCache
, shareCacheResults
.slideInCache
, statBuf
, gLinkContext
); 
3466                         return checkandAddImage(imageLoader
, context
); 
3470         // not in cache or cache not usable 
3472                 existsOnDisk 
= ( my_stat(path
, &statBuf
) == 0 ); 
3475         if ( existsOnDisk 
) { 
3476                 // in case image was renamed or found via symlinks, check for inode match 
3477                 ImageLoader
* imageLoader 
= findLoadedImage(statBuf
); 
3478                 if ( imageLoader 
!= NULL 
) 
3480                 // do nothing if not already loaded and if RTLD_NOLOAD  
3481                 if ( context
.dontLoad 
) 
3484                 imageLoader 
= loadPhase5open(path
, context
, statBuf
, exceptions
); 
3485                 if ( imageLoader 
!= NULL 
) { 
3486                         if ( shareCacheResults
.image 
!= nullptr ) { 
3487                                 // if image was found in cache, but is overridden by a newer file on disk, record what the image overrides 
3488                                 imageLoader
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum()); 
3494         // just return NULL if file not found, but record any other errors 
3495         if ( (statErrNo 
!= ENOENT
) && (statErrNo 
!= 0) ) { 
3496                 if ( (statErrNo 
== EPERM
) && sandboxBlockedStat(path
) ) 
3497                         exceptions
->push_back(dyld::mkstringf("%s: file system sandbox blocked stat()", path
)); 
3499                         exceptions
->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path
, statErrNo
)); 
3504 // look for path match with existing loaded images 
3505 static ImageLoader
* loadPhase5check(const char* path
, const char* orgPath
, const LoadContext
& context
) 
3507         //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath); 
3508         // search path against load-path and install-path of all already loaded images 
3509         uint32_t hash 
= ImageLoader::hash(path
); 
3510         //dyld::log("check() hash=%d, path=%s\n", hash, path); 
3511         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
3512                 ImageLoader
* anImage 
= *it
; 
3513                 // check hash first to cut down on strcmp calls 
3514                 //dyld::log("    check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath()); 
3515                 if ( anImage
->getPathHash() == hash 
) { 
3516                         if ( strcmp(path
, anImage
->getPath()) == 0 ) { 
3517                                 // if we are looking for a dylib don't return something else 
3518                                 if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) 
3522                 if ( context
.matchByInstallName 
|| anImage
->matchInstallPath() ) { 
3523                         const char* installPath 
= anImage
->getInstallPath(); 
3524                         if ( installPath 
!= NULL
) { 
3525                                 if ( strcmp(path
, installPath
) == 0 ) { 
3526                                         // if we are looking for a dylib don't return something else 
3527                                         if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) 
3532                 // an install name starting with @rpath should match by install name, not just real path 
3533                 if ( (orgPath
[0] == '@') && (strncmp(orgPath
, "@rpath/", 7) == 0) ) { 
3534                         const char* installPath 
= anImage
->getInstallPath(); 
3535                         if ( installPath 
!= NULL
) { 
3536                                 if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) { 
3537                                         if ( strcmp(orgPath
, installPath
) == 0 ) 
3544         //dyld::log("%s(%s) => NULL\n", __func__,   path); 
3549 // open or check existing 
3550 static ImageLoader
* loadPhase5(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3552         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3554         // check for specific dylib overrides 
3555         for (std::vector
<DylibOverride
>::iterator it 
= sDylibOverrides
.begin(); it 
!= sDylibOverrides
.end(); ++it
) { 
3556                 if ( strcmp(it
->installName
, path
) == 0 ) { 
3557                         path 
= it
->override
; 
3562         if ( exceptions 
!= NULL 
)  
3563                 return loadPhase5load(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3565                 return loadPhase5check(path
, orgPath
, context
); 
3568 // try with and without image suffix 
3569 static ImageLoader
* loadPhase4(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3571         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3572         ImageLoader
* image 
= NULL
; 
3573         if ( gLinkContext
.imageSuffix 
!= NULL 
) { 
3574                 for (const char* const* suffix
=gLinkContext
.imageSuffix
; *suffix 
!= NULL
; ++suffix
) { 
3575                         char pathWithSuffix
[strlen(path
)+strlen(*suffix
)+2]; 
3576                         ImageLoader::addSuffix(path
, *suffix
, pathWithSuffix
); 
3577                         image 
= loadPhase5(pathWithSuffix
, orgPath
, context
, cacheIndex
, exceptions
); 
3578                         if ( image 
!= NULL 
) 
3581                 if ( image 
!= NULL 
) { 
3582                         // if original path is in the dyld cache, then mark this one found as an override 
3583                         dyld3::SharedCacheFindDylibResults shareCacheResults
; 
3584                         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) && (shareCacheResults
.image 
!= nullptr) ) 
3585                                 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum()); 
3588         if ( image 
== NULL 
) 
3589                 image 
= loadPhase5(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3593 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
, 
3594                                                            const char* const frameworkPaths
[], const char* const libraryPaths
[], 
3595                                                            unsigned& cacheIndex
, std::vector
<const char*>* exceptions
); // forward reference 
3598 // expand @ variables 
3599 static ImageLoader
* loadPhase3(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3601         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3602         ImageLoader
* image 
= NULL
; 
3603         if ( strncmp(path
, "@executable_path/", 17) == 0 ) { 
3604                 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305 
3605                 if ( !gLinkContext
.allowAtPaths 
) 
3606                         throwf("unsafe use of @executable_path in %s with restricted binary (Codesign main executable with Library Validation to allow @ paths)", context
.origin
); 
3607                 // handle @executable_path path prefix 
3608                 const char* executablePath 
= sExecPath
; 
3609                 char newPath
[strlen(executablePath
) + strlen(path
)]; 
3610                 strcpy(newPath
, executablePath
); 
3611                 char* addPoint 
= strrchr(newPath
,'/'); 
3612                 if ( addPoint 
!= NULL 
) 
3613                         strcpy(&addPoint
[1], &path
[17]); 
3615                         strcpy(newPath
, &path
[17]); 
3616                 image 
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3617                 if ( image 
!= NULL 
) 
3620                 // perhaps main executable path is a sym link, find realpath and retry 
3621                 char resolvedPath
[PATH_MAX
]; 
3622                 if ( realpath(sExecPath
, resolvedPath
) != NULL 
) { 
3623                         char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
3624                         strcpy(newRealPath
, resolvedPath
); 
3625                         addPoint 
= strrchr(newRealPath
,'/'); 
3626                         if ( addPoint 
!= NULL 
) 
3627                                 strcpy(&addPoint
[1], &path
[17]); 
3629                                 strcpy(newRealPath
, &path
[17]); 
3630                         image 
= loadPhase4(newRealPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3631                         if ( image 
!= NULL 
) 
3635         else if ( (strncmp(path
, "@loader_path/", 13) == 0) && (context
.origin 
!= NULL
) ) { 
3636                 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305 
3637                 if ( !gLinkContext
.allowAtPaths  
&& (strcmp(context
.origin
, sExecPath
) == 0) ) 
3638                         throwf("unsafe use of @loader_path in %s with restricted binary (Codesign main executable with Library Validation to allow @ paths)", context
.origin
); 
3639                 // handle @loader_path path prefix 
3640                 char newPath
[strlen(context
.origin
) + strlen(path
)]; 
3641                 strcpy(newPath
, context
.origin
); 
3642                 char* addPoint 
= strrchr(newPath
,'/'); 
3643                 if ( addPoint 
!= NULL 
) 
3644                         strcpy(&addPoint
[1], &path
[13]); 
3646                         strcpy(newPath
, &path
[13]); 
3647                 image 
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3648                 if ( image 
!= NULL 
) 
3651                 // perhaps loader path is a sym link, find realpath and retry 
3652                 char resolvedPath
[PATH_MAX
]; 
3653                 if ( realpath(context
.origin
, resolvedPath
) != NULL 
) { 
3654                         char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
3655                         strcpy(newRealPath
, resolvedPath
); 
3656                         addPoint 
= strrchr(newRealPath
,'/'); 
3657                         if ( addPoint 
!= NULL 
) 
3658                                 strcpy(&addPoint
[1], &path
[13]); 
3660                                 strcpy(newRealPath
, &path
[13]); 
3661                         image 
= loadPhase4(newRealPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3662                         if ( image 
!= NULL 
) 
3666         else if ( context
.implicitRPath 
|| (strncmp(path
, "@rpath/", 7) == 0) ) { 
3667                 const char* trailingPath 
= (strncmp(path
, "@rpath/", 7) == 0) ? &path
[7] : path
; 
3668                 // substitute @rpath with all -rpath paths up the load chain 
3669                 for(const ImageLoader::RPathChain
* rp
=context
.rpath
; rp 
!= NULL
; rp
=rp
->next
) { 
3670                         if (rp
->paths 
!= NULL 
) { 
3671                                 for(std::vector
<const char*>::iterator it
=rp
->paths
->begin(); it 
!= rp
->paths
->end(); ++it
) { 
3672                                         const char* anRPath 
= *it
; 
3673                                         char newPath
[strlen(anRPath
) + strlen(trailingPath
)+2]; 
3674                                         strcpy(newPath
, anRPath
); 
3675                                         if ( newPath
[strlen(newPath
)-1] != '/' ) 
3676                                                 strcat(newPath
, "/"); 
3677                                         strcat(newPath
, trailingPath
);  
3678                                         image 
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3679                                         if ( gLinkContext
.verboseRPaths 
&& (exceptions 
!= NULL
) ) { 
3680                                                 if ( image 
!= NULL 
)  
3681                                                         dyld::log("RPATH successful expansion of %s to: %s\n", orgPath
, newPath
); 
3683                                                         dyld::log("RPATH failed expanding     %s to: %s\n", orgPath
, newPath
); 
3685                                         if ( image 
!= NULL 
)  
3691                 // substitute @rpath with LD_LIBRARY_PATH 
3692                 if ( sEnv
.LD_LIBRARY_PATH 
!= NULL 
) { 
3693                         image 
= loadPhase2(trailingPath
, orgPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, cacheIndex
, exceptions
); 
3694                         if ( image 
!= NULL 
) 
3698                 // if this is the "open" pass, don't try to open @rpath/... as a relative path 
3699                 if ( (exceptions 
!= NULL
) && (trailingPath 
!= path
) ) 
3702         else if ( !gLinkContext
.allowEnvVarsPath 
&& (path
[0] != '/' ) ) { 
3703                 throwf("unsafe use of relative rpath %s in %s with restricted binary", path
, context
.origin
); 
3706         return loadPhase4(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3709 static ImageLoader
* loadPhase2cache(const char* path
, const char *orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) { 
3710         ImageLoader
* image 
= NULL
; 
3711 #if !TARGET_OS_SIMULATOR 
3712         if ( (exceptions 
!= NULL
) && (gLinkContext
.allowEnvVarsPath 
|| !isFileRelativePath(path
)) && (path
[0] != '@') ) { 
3713                 char resolvedPath
[PATH_MAX
]; 
3714                 realpath(path
, resolvedPath
); 
3716                 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT 
3717                 if ( (myerr 
== ENOENT
) || (myerr 
== 0) ) 
3719                         image 
= loadPhase4(resolvedPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3728 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
, 
3729                                                            const char* const frameworkPaths
[], const char* const libraryPaths
[],  
3730                                                            unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3732         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3733         ImageLoader
* image 
= NULL
; 
3734         const char* frameworkPartialPath 
= getFrameworkPartialPath(path
); 
3735         if ( frameworkPaths 
!= NULL 
) { 
3736                 if ( frameworkPartialPath 
!= NULL 
) { 
3737                         const size_t frameworkPartialPathLen 
= strlen(frameworkPartialPath
); 
3738                         for(const char* const* fp 
= frameworkPaths
; *fp 
!= NULL
; ++fp
) { 
3739                                 char npath
[strlen(*fp
)+frameworkPartialPathLen
+8]; 
3742                                 strcat(npath
, frameworkPartialPath
); 
3743                                 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath); 
3744                                 image 
= loadPhase4(npath
, orgPath
, context
, cacheIndex
, exceptions
); 
3745                                 // Look in the cache if appropriate 
3747                                         image 
= loadPhase2cache(npath
, orgPath
, context
, cacheIndex
, exceptions
); 
3748                                 if ( image 
!= NULL 
) { 
3749                                         // if original path is in the dyld cache, then mark this one found as an override 
3750                                         dyld3::SharedCacheFindDylibResults shareCacheResults
; 
3751                                         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) && (shareCacheResults
.image 
!= nullptr) ) 
3752                                                 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum()); 
3758         // <rdar://problem/12649639> An executable with the same name as a framework & DYLD_LIBRARY_PATH pointing to it gets loaded twice 
3759         // <rdar://problem/14160846> Some apps depend on frameworks being found via library paths 
3760         if ( (libraryPaths 
!= NULL
) && ((frameworkPartialPath 
== NULL
) || sFrameworksFoundAsDylibs
) ) { 
3761                 const char* libraryLeafName 
= getLibraryLeafName(path
); 
3762                 const size_t libraryLeafNameLen 
= strlen(libraryLeafName
); 
3763                 for(const char* const* lp 
= libraryPaths
; *lp 
!= NULL
; ++lp
) { 
3764                         char libpath
[strlen(*lp
)+libraryLeafNameLen
+8]; 
3765                         strcpy(libpath
, *lp
); 
3766                         strcat(libpath
, "/"); 
3767                         strcat(libpath
, libraryLeafName
); 
3768                         //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath); 
3769                         image 
= loadPhase4(libpath
, orgPath
, context
, cacheIndex
, exceptions
); 
3770                         // Look in the cache if appropriate 
3772                                 image 
= loadPhase2cache(libpath
, orgPath
, context
, cacheIndex
, exceptions
); 
3773                         if ( image 
!= NULL 
) { 
3774                                 // if original path is in the dyld cache, then mark this one found as an override 
3775                                 dyld3::SharedCacheFindDylibResults shareCacheResults
; 
3776                                 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) && (shareCacheResults
.image 
!= nullptr) ) 
3777                                         image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum()); 
3785 // try search overrides and fallbacks 
3786 static ImageLoader
* loadPhase1(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3788         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3789         ImageLoader
* image 
= NULL
; 
3791         bool pathIsInDyldCacheWhichCannotBeOverridden 
= false; 
3792         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) { 
3793                 pathIsInDyldCacheWhichCannotBeOverridden 
= sSharedCacheLoadInfo
.loadAddress
->hasNonOverridablePath(path
); 
3796         // <rdar://problem/48490116> dyld customer cache cannot be overridden 
3797         if ( !pathIsInDyldCacheWhichCannotBeOverridden 
) { 
3798                 // handle LD_LIBRARY_PATH environment variables that force searching 
3799                 if ( context
.useLdLibraryPath 
&& (sEnv
.LD_LIBRARY_PATH 
!= NULL
) ) { 
3800                         image 
= loadPhase2(path
, orgPath
, context
,  NULL
, sEnv
.LD_LIBRARY_PATH
, cacheIndex
,exceptions
); 
3801                         if ( image 
!= NULL 
) 
3805                 // handle DYLD_ environment variables that force searching 
3806                 if ( context
.useSearchPaths 
&& ((sEnv
.DYLD_FRAMEWORK_PATH 
!= NULL
) || (sEnv
.DYLD_LIBRARY_PATH 
!= NULL
)) ) { 
3807                         image 
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FRAMEWORK_PATH
, sEnv
.DYLD_LIBRARY_PATH
, cacheIndex
, exceptions
); 
3808                         if ( image 
!= NULL 
) 
3814         image 
= loadPhase3(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3815         if ( image 
!= NULL 
) 
3818         // try fallback paths during second time (will open file) 
3819         const char* const* fallbackLibraryPaths 
= sEnv
.DYLD_FALLBACK_LIBRARY_PATH
; 
3820         if ( (fallbackLibraryPaths 
!= NULL
) && !context
.useFallbackPaths 
) 
3821                 fallbackLibraryPaths 
= NULL
; 
3822         if ( !context
.dontLoad  
&& (exceptions 
!= NULL
) && ((sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
!= NULL
) || (fallbackLibraryPaths 
!= NULL
)) ) { 
3823                 image 
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
, fallbackLibraryPaths
, cacheIndex
, exceptions
); 
3824                 if ( image 
!= NULL 
) 
3828         // <rdar://problem/47682983> if hardened app calls dlopen() with a leaf path, dyld should only look in /usr/lib 
3829         if ( context
.useLdLibraryPath 
&& (fallbackLibraryPaths 
== NULL
) ) { 
3830                 const char* stdPaths
[2] = { "/usr/lib", NULL 
}; 
3831                 image 
= loadPhase2(path
, orgPath
, context
, NULL
, stdPaths
, cacheIndex
, exceptions
); 
3832                 if ( image 
!= NULL 
) 
3836 #if SUPPORT_VERSIONED_PATHS 
3837     // <rdar://problem/53215116> DYLD_VERSIONED_FRAMEWORK_PATH fails to load a framework if it does not also exist at the system install path 
3838     // Scan to see if the dylib appears in a versioned path. Don't worry if we find the newest, that will handled later 
3839     if ( !context
.dontLoad  
&& (exceptions 
!= NULL
) && ((sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH 
!= NULL
) || (sEnv
.DYLD_VERSIONED_LIBRARY_PATH 
!= NULL
)) ) { 
3840         image 
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
, sEnv
.DYLD_VERSIONED_LIBRARY_PATH
, cacheIndex
, exceptions
); 
3841         if ( image 
!= NULL 
) 
3849 // try root substitutions 
3850 static ImageLoader
* loadPhase0(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3852         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3854 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3855         // handle macOS dylibs dlopen()ing versioned path which needs to map to flat path in mazipan simulator 
3856         if ( gLinkContext
.iOSonMac 
&& strstr(path
, ".framework/Versions/")) { 
3857                 uintptr_t sourceOffset 
= 0; 
3858                 uintptr_t destOffset 
= 0; 
3859                 size_t sourceLangth 
= strlen(path
); 
3860                 char flatPath
[sourceLangth
]; 
3862                 const char* frameworkBase 
= NULL
; 
3863                 while ((frameworkBase 
= strstr(&path
[sourceOffset
], ".framework/Versions/"))) { 
3864                         uintptr_t foundLength 
= (frameworkBase 
- &path
[sourceOffset
]) + strlen(".framework/") ; 
3865                         strlcat(&flatPath
[destOffset
], &path
[sourceOffset
], foundLength
); 
3866                         sourceOffset 
+= foundLength 
+ strlen("Versions/") + 1; 
3867                         destOffset 
+= foundLength 
- 1; 
3869                 strlcat(&flatPath
[destOffset
], &path
[sourceOffset
], sourceLangth
); 
3870                 ImageLoader
* image 
= loadPhase0(flatPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3871                 if ( image 
!= NULL 
) 
3876 #if SUPPORT_ROOT_PATH 
3877         // handle DYLD_ROOT_PATH which forces absolute paths to use a new root 
3878         if ( (gLinkContext
.rootPaths 
!= NULL
) && (path
[0] == '/') ) { 
3879                 for(const char* const* rootPath 
= gLinkContext
.rootPaths
; *rootPath 
!= NULL
; ++rootPath
) { 
3880                         size_t rootLen 
= strlen(*rootPath
); 
3881                         if ( strncmp(path
, *rootPath
, rootLen
) != 0 ) { 
3882                                 char newPath
[rootLen 
+ strlen(path
)+2]; 
3883                                 strcpy(newPath
, *rootPath
); 
3884                                 strcat(newPath
, path
); 
3885                                 ImageLoader
* image 
= loadPhase1(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3886                                 if ( image 
!= NULL 
) 
3894         return loadPhase1(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3898 // Given all the DYLD_ environment variables, the general case for loading libraries 
3899 // is that any given path expands into a list of possible locations to load.  We 
3900 // also must take care to ensure two copies of the "same" library are never loaded. 
3902 // The algorithm used here is that there is a separate function for each "phase" of the 
3903 // path expansion.  Each phase function calls the next phase with each possible expansion 
3904 // of that phase.  The result is the last phase is called with all possible paths.   
3906 // To catch duplicates the algorithm is run twice.  The first time, the last phase checks 
3907 // the path against all loaded images.  The second time, the last phase calls open() on  
3908 // the path.  Either time, if an image is found, the phases all unwind without checking 
3911 ImageLoader
* load(const char* path
, const LoadContext
& context
, unsigned& cacheIndex
) 
3913         CRSetCrashLogMessage2(path
); 
3914         const char* orgPath 
= path
; 
3915         cacheIndex 
= UINT32_MAX
; 
3917         //dyld::log("%s(%s)\n", __func__ , path); 
3918         char realPath
[PATH_MAX
]; 
3919         // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match 
3920         if ( context
.useSearchPaths 
&& ( gLinkContext
.imageSuffix 
!= NULL 
&& *gLinkContext
.imageSuffix 
!= NULL
) ) { 
3921                 if ( realpath(path
, realPath
) != NULL 
) 
3925         // try all path permutations and check against existing loaded images 
3927         ImageLoader
* image 
= loadPhase0(path
, orgPath
, context
, cacheIndex
, NULL
); 
3928         if ( image 
!= NULL 
) { 
3929                 CRSetCrashLogMessage2(NULL
); 
3933         // try all path permutations and try open() until first success 
3934         std::vector
<const char*> exceptions
; 
3935         image 
= loadPhase0(path
, orgPath
, context
, cacheIndex
, &exceptions
); 
3936 #if !TARGET_OS_SIMULATOR 
3937         // <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache 
3939                 image 
= loadPhase2cache(path
, orgPath
, context
, cacheIndex
, &exceptions
); 
3941     CRSetCrashLogMessage2(NULL
); 
3942         if ( image 
!= NULL 
) { 
3943                 // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables 
3944                 for (std::vector
<const char*>::iterator it 
= exceptions
.begin(); it 
!= exceptions
.end(); ++it
) { 
3947                 // if loaded image is not from cache, but original path is in cache 
3948                 // set gSharedCacheOverridden flag to disable some ObjC optimizations 
3949                 if ( !gSharedCacheOverridden 
&& !image
->inSharedCache() && image
->isDylib() && dyld3::MachOFile::isSharedCacheEligiblePath(path
) && inSharedCache(path
) ) { 
3950                         gSharedCacheOverridden 
= true; 
3954         else if ( exceptions
.size() == 0 ) { 
3955                 if ( context
.dontLoad 
) { 
3959                         throw "image not found"; 
3962                 const char* msgStart 
= "no suitable image found.  Did find:"; 
3963                 const char* delim 
= "\n\t"; 
3964                 size_t allsizes 
= strlen(msgStart
)+8; 
3965                 for (size_t i
=0; i 
< exceptions
.size(); ++i
)  
3966                         allsizes 
+= (strlen(exceptions
[i
]) + strlen(delim
)); 
3967                 char* fullMsg 
= new char[allsizes
]; 
3968                 strcpy(fullMsg
, msgStart
); 
3969                 for (size_t i
=0; i 
< exceptions
.size(); ++i
) { 
3970                         strcat(fullMsg
, delim
); 
3971                         strcat(fullMsg
, exceptions
[i
]); 
3972                         free((void*)exceptions
[i
]); 
3974                 throw (const char*)fullMsg
; 
3982 static void mapSharedCache() 
3984         dyld3::SharedCacheOptions opts
; 
3985         opts
.cacheDirOverride   
= sSharedCacheOverrideDir
; 
3986         opts
.forcePrivate               
= (gLinkContext
.sharedRegionMode 
== ImageLoader::kUsePrivateSharedRegion
); 
3989 #if __x86_64__ && !TARGET_OS_SIMULATOR 
3990         opts
.useHaswell                 
= sHaswell
; 
3992         opts
.useHaswell                 
= false; 
3994         opts
.verbose                    
= gLinkContext
.verboseMapping
; 
3995         loadDyldCache(opts
, &sSharedCacheLoadInfo
); 
3997         // update global state 
3998         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) { 
3999                 gLinkContext
.dyldCache                                                          
= sSharedCacheLoadInfo
.loadAddress
; 
4000                 dyld::gProcessInfo
->processDetachedFromSharedRegion 
= opts
.forcePrivate
; 
4001                 dyld::gProcessInfo
->sharedCacheSlide                
= sSharedCacheLoadInfo
.slide
; 
4002                 dyld::gProcessInfo
->sharedCacheBaseAddress          
= (unsigned long)sSharedCacheLoadInfo
.loadAddress
; 
4003                 sSharedCacheLoadInfo
.loadAddress
->getUUID(dyld::gProcessInfo
->sharedCacheUUID
); 
4004                 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_SHARED_CACHE_A
, sSharedCacheLoadInfo
.path
, (const uuid_t 
*)&dyld::gProcessInfo
->sharedCacheUUID
[0], {0,0}, {{ 0, 0 }}, (const mach_header 
*)sSharedCacheLoadInfo
.loadAddress
); 
4007 //#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
4008 // RAM disk booting does not have shared cache yet 
4009 // Don't make lack of a shared cache fatal in that case 
4010 //      if ( sSharedCacheLoadInfo.loadAddress == nullptr ) { 
4011 //              if ( sSharedCacheLoadInfo.errorMessage != nullptr ) 
4012 //                      halt(sSharedCacheLoadInfo.errorMessage); 
4014 //                      halt("error loading dyld shared cache"); 
4021 // create when NSLinkModule is called for a second time on a bundle 
4022 ImageLoader
* cloneImage(ImageLoader
* image
) 
4024         // open file (automagically closed when this function exits) 
4025         FileOpener 
file(image
->getPath()); 
4027         struct stat stat_buf
; 
4028         if ( fstat(file
.getFileDescriptor(), &stat_buf
) == -1) 
4031         dyld::LoadContext context
; 
4032         context
.useSearchPaths          
= false; 
4033         context
.useFallbackPaths        
= false; 
4034         context
.useLdLibraryPath        
= false; 
4035         context
.implicitRPath           
= false; 
4036         context
.matchByInstallName      
= false; 
4037         context
.dontLoad                        
= false; 
4038         context
.mustBeBundle            
= true; 
4039         context
.mustBeDylib                     
= false; 
4040         context
.canBePIE                        
= false; 
4041         context
.origin                          
= NULL
; 
4042         context
.rpath                           
= NULL
; 
4043         return loadPhase6(file
.getFileDescriptor(), stat_buf
, image
->getPath(), context
); 
4047 ImageLoader
* loadFromMemory(const uint8_t* mem
, uint64_t len
, const char* moduleName
) 
4049         // if fat wrapper, find usable sub-file 
4050         const fat_header
* memStartAsFat 
= (fat_header
*)mem
; 
4051         uint64_t fileOffset 
= 0; 
4052         uint64_t fileLength 
= len
; 
4053         if ( memStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
4054                 if ( fatFindBest(memStartAsFat
, &fileOffset
, &fileLength
) ) { 
4055                         mem 
= &mem
[fileOffset
]; 
4059                         throw "no matching architecture in universal wrapper"; 
4064         if ( isCompatibleMachO(mem
, moduleName
) ) { 
4065                 ImageLoader
* image 
= ImageLoaderMachO::instantiateFromMemory(moduleName
, (macho_header
*)mem
, len
, gLinkContext
); 
4066                 // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
4067                 if ( ! image
->isBundle() )  
4072         // try other file formats here... 
4074         // throw error about what was found 
4075         switch (*(uint32_t*)mem
) { 
4080                         throw "mach-o, but wrong architecture"; 
4082                 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",  
4083                         mem
[0], mem
[1], mem
[2], mem
[3], mem
[4], mem
[5], mem
[6],mem
[7]); 
4088 void registerAddCallback(ImageCallback func
) 
4090         // now add to list to get notified when any more images are added 
4091         sAddImageCallbacks
.push_back(func
); 
4093         // call callback with all existing images 
4094         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4095                 ImageLoader
* image 
= *it
; 
4096                 if ( image
->getState() >= dyld_image_state_bound 
&& image
->getState() < dyld_image_state_terminated 
) { 
4097                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*func
), 0); 
4098                         (*func
)(image
->machHeader(), image
->getSlide()); 
4101 #if SUPPORT_ACCELERATE_TABLES 
4102         if ( sAllCacheImagesProxy 
!= NULL 
) { 
4103                 dyld_image_info infos
[allImagesCount()+1]; 
4104                 unsigned cacheCount 
= sAllCacheImagesProxy
->appendImagesToNotify(dyld_image_state_bound
, true, infos
); 
4105                 for (unsigned i
=0; i 
< cacheCount
; ++i
) { 
4106                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[i
].imageLoadAddress
, (uint64_t)(*func
), 0); 
4107                         (*func
)(infos
[i
].imageLoadAddress
, sSharedCacheLoadInfo
.slide
); 
4113 void registerLoadCallback(LoadImageCallback func
) 
4115         // now add to list to get notified when any more images are added 
4116         sAddLoadImageCallbacks
.push_back(func
); 
4118         // call callback with all existing images 
4119         for (ImageLoader
* image 
: sAllImages
) { 
4120                 if ( image
->getState() >= dyld_image_state_bound 
&& image
->getState() < dyld_image_state_terminated 
) { 
4121                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*func
), 0); 
4122                         (*func
)(image
->machHeader(), image
->getPath(), !image
->neverUnload()); 
4125 #if SUPPORT_ACCELERATE_TABLES 
4126         if ( sAllCacheImagesProxy 
!= NULL 
) { 
4127                 dyld_image_info infos
[allImagesCount()+1]; 
4128                 unsigned cacheCount 
= sAllCacheImagesProxy
->appendImagesToNotify(dyld_image_state_bound
, true, infos
); 
4129                 for (unsigned i
=0; i 
< cacheCount
; ++i
) { 
4130                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[i
].imageLoadAddress
, (uint64_t)(*func
), 0); 
4131                         (*func
)(infos
[i
].imageLoadAddress
, infos
[i
].imageFilePath
, false); 
4137 void registerBulkLoadCallback(LoadImageBulkCallback func
) 
4139         // call callback with all existing images 
4140         unsigned count 
= dyld::gProcessInfo
->infoArrayCount
; 
4141         const dyld_image_info
* infoArray 
= dyld::gProcessInfo
->infoArray
; 
4142         if ( infoArray 
!= NULL 
) { 
4143                 const mach_header
* mhs
[count
]; 
4144                 const char*        paths
[count
]; 
4145                 for (unsigned i
=0; i 
< count
; ++i
) { 
4146                         mhs
[i
]   = infoArray
[i
].imageLoadAddress
; 
4147                         paths
[i
] = infoArray
[i
].imageFilePath
; 
4149                 dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)mhs
[0], (uint64_t)func
, 0); 
4150                 func(count
, mhs
, paths
); 
4153         // now add to list to get notified when any more images are added 
4154         sAddBulkLoadImageCallbacks
.push_back(func
); 
4157 void registerRemoveCallback(ImageCallback func
) 
4159         // <rdar://problem/15025198> ignore calls to register a notification during a notification 
4160         if ( sRemoveImageCallbacksInUse 
) 
4162         sRemoveImageCallbacks
.push_back(func
); 
4165 void clearErrorMessage() 
4167         error_string
[0] = '\0'; 
4170 void setErrorMessage(const char* message
) 
4172         // save off error message in global buffer for CrashReporter to find 
4173         strlcpy(error_string
, message
, sizeof(error_string
)); 
4176 const char* getErrorMessage() 
4178         return error_string
; 
4181 void halt(const char* message
) 
4183         if ( sSharedCacheLoadInfo
.errorMessage 
!= nullptr ) { 
4184                 // <rdar://problem/45957449> if dyld fails with a missing dylib and there is no shared cache, display the shared cache load error message 
4185                 dyld::log("dyld: dyld cache load error: %s\n", sSharedCacheLoadInfo
.errorMessage
); 
4186                 dyld::log("dyld: %s\n", message
); 
4187                 strlcpy(error_string
, "dyld cache load error: ", sizeof(error_string
)); 
4188                 strlcat(error_string
, sSharedCacheLoadInfo
.errorMessage
, sizeof(error_string
)); 
4189                 strlcat(error_string
, "\n", sizeof(error_string
)); 
4190                 strlcat(error_string
, message
, sizeof(error_string
)); 
4193                 dyld::log("dyld: %s\n", message
); 
4194                 strlcpy(error_string
, message
, sizeof(error_string
)); 
4197         dyld::gProcessInfo
->errorMessage 
= error_string
; 
4198         if ( !gLinkContext
.startedInitializingMainExecutable 
) 
4199                 dyld::gProcessInfo
->terminationFlags 
= 1; 
4201                 dyld::gProcessInfo
->terminationFlags 
= 0; 
4203         char payloadBuffer
[EXIT_REASON_PAYLOAD_MAX_LEN
]; 
4204         dyld_abort_payload
* payload 
= (dyld_abort_payload
*)payloadBuffer
; 
4205         payload
->version               
= 1; 
4206         payload
->flags                 
= gLinkContext
.startedInitializingMainExecutable 
? 0 : 1; 
4207         payload
->targetDylibPathOffset 
= 0; 
4208         payload
->clientPathOffset      
= 0; 
4209         payload
->symbolOffset          
= 0; 
4210         int payloadSize 
= sizeof(dyld_abort_payload
); 
4212         if ( dyld::gProcessInfo
->errorTargetDylibPath 
!= NULL 
) { 
4213                 payload
->targetDylibPathOffset 
= payloadSize
; 
4214                 payloadSize 
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorTargetDylibPath
, sizeof(payloadBuffer
)-payloadSize
) + 1; 
4216         if ( dyld::gProcessInfo
->errorClientOfDylibPath 
!= NULL 
) { 
4217                 payload
->clientPathOffset 
= payloadSize
; 
4218                 payloadSize 
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorClientOfDylibPath
, sizeof(payloadBuffer
)-payloadSize
) + 1; 
4220         if ( dyld::gProcessInfo
->errorSymbol 
!= NULL 
) { 
4221                 payload
->symbolOffset 
= payloadSize
; 
4222                 payloadSize 
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorSymbol
, sizeof(payloadBuffer
)-payloadSize
) + 1; 
4224         char truncMessage
[EXIT_REASON_USER_DESC_MAX_LEN
]; 
4225         strlcpy(truncMessage
, error_string
, EXIT_REASON_USER_DESC_MAX_LEN
); 
4226         abort_with_payload(OS_REASON_DYLD
, dyld::gProcessInfo
->errorKind 
? dyld::gProcessInfo
->errorKind 
: DYLD_EXIT_REASON_OTHER
, payloadBuffer
, payloadSize
, truncMessage
, 0); 
4229 static void setErrorStrings(unsigned errorCode
, const char* errorClientOfDylibPath
, 
4230                                                                 const char* errorTargetDylibPath
, const char* errorSymbol
) 
4232         dyld::gProcessInfo
->errorKind 
= errorCode
; 
4233         dyld::gProcessInfo
->errorClientOfDylibPath 
= errorClientOfDylibPath
; 
4234         dyld::gProcessInfo
->errorTargetDylibPath 
= errorTargetDylibPath
; 
4235         dyld::gProcessInfo
->errorSymbol 
= errorSymbol
; 
4239 uintptr_t bindLazySymbol(const mach_header
* mh
, uintptr_t* lazyPointer
) 
4241         uintptr_t result 
= 0; 
4242         // acquire read-lock on dyld's data structures 
4243 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved 
4244         if ( gLibSystemHelpers 
!= NULL 
)  
4245                 (*gLibSystemHelpers
->lockForReading
)(); 
4247         // lookup and bind lazy pointer and get target address 
4249                 ImageLoader
* target
; 
4251                 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer) 
4253                         target 
= dyld::findImageContainingAddress(lazyPointer
); 
4255                         target 
= dyld::findImageByMachHeader(mh
); 
4257                 // note, target should always be mach-o, because only mach-o lazy handler wired up to this 
4258                 target 
= dyld::findImageByMachHeader(mh
); 
4260                 if ( target 
== NULL 
) 
4261                         throwf("image not found for lazy pointer at %p", lazyPointer
); 
4262                 result 
= target
->doBindLazySymbol(lazyPointer
, gLinkContext
); 
4264         catch (const char* message
) { 
4265                 dyld::log("dyld: lazy symbol binding failed: %s\n", message
); 
4268         // release read-lock on dyld's data structures 
4270         if ( gLibSystemHelpers 
!= NULL 
)  
4271                 (*gLibSystemHelpers
->unlockForReading
)(); 
4273         // return target address to glue which jumps to it with real parameters restored 
4278 uintptr_t fastBindLazySymbol(ImageLoader
** imageLoaderCache
, uintptr_t lazyBindingInfoOffset
) 
4280         uintptr_t result 
= 0; 
4282         if ( *imageLoaderCache 
== NULL 
) { 
4284                 *imageLoaderCache 
= dyld::findMappedRange((uintptr_t)imageLoaderCache
); 
4285                 if ( *imageLoaderCache 
== NULL 
) { 
4286 #if SUPPORT_ACCELERATE_TABLES 
4287                 if ( sAllCacheImagesProxy 
!= NULL 
) { 
4288                         const mach_header
* mh
; 
4291                         if ( sAllCacheImagesProxy
->addressInCache(imageLoaderCache
, &mh
, &path
, &index
) ) { 
4292                                 result 
= sAllCacheImagesProxy
->bindLazy(lazyBindingInfoOffset
, gLinkContext
, mh
, index
); 
4293                                 if ( result 
== 0 ) { 
4294                                         halt("dyld: lazy symbol binding failed for image in dyld shared\n"); 
4300                         const char* message 
= "fast lazy binding from unknown image"; 
4301                         dyld::log("dyld: %s\n", message
); 
4306         // bind lazy pointer and return it 
4308                 result 
= (*imageLoaderCache
)->doBindFastLazySymbol((uint32_t)lazyBindingInfoOffset
, gLinkContext
,  
4309                                                                 (dyld::gLibSystemHelpers 
!= NULL
) ? dyld::gLibSystemHelpers
->acquireGlobalDyldLock 
: NULL
, 
4310                                                                 (dyld::gLibSystemHelpers 
!= NULL
) ? dyld::gLibSystemHelpers
->releaseGlobalDyldLock 
: NULL
); 
4312         catch (const char* message
) { 
4313                 dyld::log("dyld: lazy symbol binding failed: %s\n", message
); 
4317         // return target address to glue which jumps to it with real parameters restored 
4323 void registerUndefinedHandler(UndefinedHandler handler
) 
4325         sUndefinedHandler 
= handler
; 
4328 static void undefinedHandler(const char* symboName
) 
4330         if ( sUndefinedHandler 
!= NULL 
) { 
4331                 (*sUndefinedHandler
)(symboName
); 
4335 static bool findExportedSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
, ImageLoader::CoalesceNotifier notifier
=NULL
) 
4337         // search all images in order 
4338         const ImageLoader
* firstWeakImage 
= NULL
; 
4339         const ImageLoader::Symbol
* firstWeakSym 
= NULL
; 
4340         const ImageLoader
* firstNonWeakImage 
= NULL
; 
4341         const ImageLoader::Symbol
* firstNonWeakSym 
= NULL
; 
4342         const size_t imageCount 
= sAllImages
.size(); 
4343         for(size_t i
=0; i 
< imageCount
; ++i
) { 
4344                 ImageLoader
* anImage 
= sAllImages
[i
]; 
4345                 // the use of inserted libraries alters search order 
4346                 // so that inserted libraries are found before the main executable 
4347                 if ( sInsertedDylibCount 
> 0 ) { 
4348                         if ( i 
< sInsertedDylibCount 
) 
4349                                 anImage 
= sAllImages
[i
+1]; 
4350                         else if ( i 
== sInsertedDylibCount 
) 
4351                                 anImage 
= sAllImages
[0]; 
4353                 //dyld::log("findExportedSymbol(%s) looking at %s\n", name, anImage->getPath()); 
4354                 if ( ! anImage
->hasHiddenExports() && (!onlyInCoalesced 
|| anImage
->hasCoalescedExports()) ) { 
4355                         const ImageLoader
* foundInImage
; 
4356                         *sym 
= anImage
->findExportedSymbol(name
, false, &foundInImage
); 
4357                         //dyld::log("findExportedSymbol(%s) found: sym=%p, anImage=%p, foundInImage=%p\n", name, *sym, anImage, foundInImage /*, (foundInImage ? foundInImage->getPath() : "")*/); 
4358                         if ( *sym 
!= NULL 
) { 
4359                                 if ( notifier 
&& (foundInImage 
== anImage
) ) 
4360                                         notifier(*sym
, foundInImage
, foundInImage
->machHeader()); 
4361                                 // if weak definition found, record first one found 
4362                                 if ( (foundInImage
->getExportedSymbolInfo(*sym
) & ImageLoader::kWeakDefinition
) != 0 ) { 
4363                                         if ( firstWeakImage 
== NULL 
) { 
4364                                                 firstWeakImage 
= foundInImage
; 
4365                                                 firstWeakSym 
= *sym
; 
4370                                         if ( !onlyInCoalesced 
) { 
4371                                                 // for flat lookups, return first found 
4372                                                 *image 
= foundInImage
; 
4375                                         if ( firstNonWeakImage 
== NULL 
) { 
4376                                                 firstNonWeakImage 
= foundInImage
; 
4377                                                 firstNonWeakSym 
= *sym
; 
4383         if ( firstNonWeakImage 
!= NULL 
) { 
4384                 // found a weak definition, but no non-weak, so return first weak found 
4385                 *sym 
= firstNonWeakSym
; 
4386                 *image 
= firstNonWeakImage
; 
4389         if ( firstWeakSym 
!= NULL 
) { 
4390                 // found a weak definition, but no non-weak, so return first weak found 
4391                 *sym 
= firstWeakSym
; 
4392                 *image 
= firstWeakImage
; 
4395 #if SUPPORT_ACCELERATE_TABLES 
4396         if ( sAllCacheImagesProxy 
!= NULL 
) { 
4397                 if ( sAllCacheImagesProxy
->flatFindSymbol(name
, onlyInCoalesced
, sym
, image
, notifier
) ) 
4405 bool flatFindExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
4407         return findExportedSymbol(name
, false, sym
, image
); 
4410 bool findCoalescedExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
, ImageLoader::CoalesceNotifier notifier
) 
4412         return findExportedSymbol(name
, true, sym
, image
, notifier
); 
4416 bool flatFindExportedSymbolWithHint(const char* name
, const char* librarySubstring
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
4418         // search all images in order 
4419         const size_t imageCount 
= sAllImages
.size(); 
4420         for(size_t i
=0; i 
< imageCount
; ++i
){ 
4421                 ImageLoader
* anImage 
= sAllImages
[i
]; 
4422                 // only look at images whose paths contain the hint string (NULL hint string is wildcard) 
4423                 if ( ! anImage
->isBundle() && ((librarySubstring
==NULL
) || (strstr(anImage
->getPath(), librarySubstring
) != NULL
)) ) { 
4424                         *sym 
= anImage
->findExportedSymbol(name
, false, image
); 
4425                         if ( *sym 
!= NULL 
) { 
4434 unsigned int getCoalescedImages(ImageLoader
* images
[], unsigned imageIndex
[]) 
4436         unsigned int count 
= 0; 
4437         const size_t imageCount 
= sAllImages
.size(); 
4438         for(size_t i
=0; i 
< imageCount
; ++i
) { 
4439                 ImageLoader
* anImage 
= sAllImages
[i
]; 
4440                 // the use of inserted libraries alters search order 
4441                 // so that inserted libraries are found before the main executable 
4442                 if ( sInsertedDylibCount 
> 0 ) { 
4443                         if ( i 
< sInsertedDylibCount 
) 
4444                                 anImage 
= sAllImages
[i
+1]; 
4445                         else if ( i 
== sInsertedDylibCount 
) 
4446                                 anImage 
= sAllImages
[0]; 
4448                 if ( anImage
->participatesInCoalescing() ) { 
4449                         images
[count
] = anImage
; 
4450                         imageIndex
[count
] = 0; 
4454 #if SUPPORT_ACCELERATE_TABLES 
4455         if ( sAllCacheImagesProxy 
!= NULL 
) { 
4456                 sAllCacheImagesProxy
->appendImagesNeedingCoalescing(images
, imageIndex
, count
); 
4463 static ImageLoader::MappedRegion
* getMappedRegions(ImageLoader::MappedRegion
* regions
) 
4465         ImageLoader::MappedRegion
* end 
= regions
; 
4466         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4467                 (*it
)->getMappedRegions(end
); 
4472 void registerImageStateSingleChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
) 
4474         // mark the image that the handler is in as never-unload because dyld has a reference into it 
4475         ImageLoader
* handlerImage 
= findImageContainingAddress((void*)handler
); 
4476         if ( handlerImage 
!= NULL 
) 
4477                 handlerImage
->setNeverUnload(); 
4479         // add to list of handlers 
4480         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
4481         if ( handlers 
!= NULL 
) { 
4482         // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list 
4483         // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated 
4484         if ( state 
== dyld_image_state_mapped 
) 
4485             handlers
->insert(handlers
->begin(), handler
); 
4487             handlers
->push_back(handler
); 
4489                 // call callback with all existing images 
4490                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4491                         ImageLoader
* image 
= *it
; 
4492                         dyld_image_info  info
; 
4493                         info
.imageLoadAddress   
= image
->machHeader(); 
4494                         info
.imageFilePath              
= image
->getRealPath(); 
4495                         info
.imageFileModDate   
= image
->lastModified(); 
4496                         // should only call handler if state == image->state 
4497                         if ( image
->getState() == state 
) 
4498                                 (*handler
)(state
, 1, &info
); 
4499                         // ignore returned string, too late to do anything 
4504 void registerImageStateBatchChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
) 
4506         // mark the image that the handler is in as never-unload because dyld has a reference into it 
4507         ImageLoader
* handlerImage 
= findImageContainingAddress((void*)handler
); 
4508         if ( handlerImage 
!= NULL 
) 
4509                 handlerImage
->setNeverUnload(); 
4511         // add to list of handlers 
4512         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sBatchHandlers
); 
4513         if ( handlers 
!= NULL 
) { 
4514                 // insert at front, so that gdb handler is always last 
4515                 handlers
->insert(handlers
->begin(), handler
); 
4517                 // call callback with all existing images 
4519                         notifyBatchPartial(state
, true, handler
, false, false); 
4521                 catch (const char* msg
) { 
4522                         // ignore request to abort during registration 
4528 void registerObjCNotifiers(_dyld_objc_notify_mapped mapped
, _dyld_objc_notify_init init
, _dyld_objc_notify_unmapped unmapped
) 
4530         // record functions to call 
4531         sNotifyObjCMapped       
= mapped
; 
4532         sNotifyObjCInit         
= init
; 
4533         sNotifyObjCUnmapped 
= unmapped
; 
4535         // call 'mapped' function with all images mapped so far 
4537                 notifyBatchPartial(dyld_image_state_bound
, true, NULL
, false, true); 
4539         catch (const char* msg
) { 
4540                 // ignore request to abort during registration 
4543         // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem) 
4544         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4545                 ImageLoader
* image 
= *it
; 
4546                 if ( (image
->getState() == dyld_image_state_initialized
) && image
->notifyObjC() ) { 
4547                         dyld3::ScopedTimer 
timer(DBG_DYLD_TIMING_OBJC_INIT
, (uint64_t)image
->machHeader(), 0, 0); 
4548                         (*sNotifyObjCInit
)(image
->getRealPath(), image
->machHeader()); 
4553 bool sharedCacheUUID(uuid_t uuid
) 
4555         if ( sSharedCacheLoadInfo
.loadAddress 
== nullptr ) 
4558         sSharedCacheLoadInfo
.loadAddress
->getUUID(uuid
); 
4562 #if SUPPORT_ACCELERATE_TABLES 
4564 bool dlopenFromCache(const char* path
, int mode
, void** handle
) 
4566         if ( sAllCacheImagesProxy 
== NULL 
) 
4568         char fallbackPath
[PATH_MAX
]; 
4569         bool result 
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, path
, mode
, handle
); 
4570         if ( !result 
&& (strchr(path
, '/') == NULL
) ) { 
4571                 // POSIX says you can call dlopen() with a leaf name (e.g. dlopen("libz.dylb")) 
4572                 strcpy(fallbackPath
, "/usr/lib/"); 
4573                 strlcat(fallbackPath
, path
, PATH_MAX
); 
4574                 result 
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, fallbackPath
, mode
, handle
); 
4576                         path 
= fallbackPath
; 
4579                 // leaf name could be a symlink 
4580                 char resolvedPath
[PATH_MAX
]; 
4581                 realpath(path
, resolvedPath
); 
4582                 int realpathErrno 
= errno
; 
4583                 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT 
4584                 if ( (realpathErrno 
== ENOENT
) || (realpathErrno 
== 0) ) { 
4585                         result 
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, resolvedPath
, mode
, handle
); 
4592 bool makeCacheHandle(ImageLoader
* image
, unsigned cacheIndex
, int mode
, void** result
) 
4594         if ( sAllCacheImagesProxy 
== NULL 
) 
4596         return sAllCacheImagesProxy
->makeCacheHandle(gLinkContext
, cacheIndex
, mode
, result
); 
4599 bool isCacheHandle(void* handle
) 
4601         if ( sAllCacheImagesProxy 
== NULL 
) 
4603         return sAllCacheImagesProxy
->isCacheHandle(handle
, NULL
, NULL
); 
4606 bool isPathInCache(const char* path
) 
4608         if ( sAllCacheImagesProxy 
== NULL 
) 
4611         return sAllCacheImagesProxy
->hasDylib(path
, &index
); 
4614 const char* getPathFromIndex(unsigned cacheIndex
) 
4616         if ( sAllCacheImagesProxy 
== NULL 
) 
4618         return sAllCacheImagesProxy
->getIndexedPath(cacheIndex
); 
4621 void* dlsymFromCache(void* handle
, const char* symName
, unsigned index
) 
4623         if ( sAllCacheImagesProxy 
== NULL 
) 
4625         return sAllCacheImagesProxy
->dlsymFromCache(gLinkContext
, handle
, symName
, index
); 
4628 bool addressInCache(const void* address
, const mach_header
** mh
, const char** path
, unsigned* index
) 
4630         if ( sAllCacheImagesProxy 
== NULL 
) 
4633         return sAllCacheImagesProxy
->addressInCache(address
, mh
, path
, index 
? index 
: &ignore
); 
4636 bool findUnwindSections(const void* addr
, dyld_unwind_sections
* info
) 
4638         if ( sAllCacheImagesProxy 
== NULL 
) 
4640         return sAllCacheImagesProxy
->findUnwindSections(addr
, info
); 
4643 bool dladdrFromCache(const void* address
, Dl_info
* info
) 
4645         if ( sAllCacheImagesProxy 
== NULL 
) 
4647         return sAllCacheImagesProxy
->dladdrFromCache(address
, info
); 
4651 static ImageLoader
* libraryLocator(const char* libraryName
, bool search
, const char* origin
, const ImageLoader::RPathChain
* rpaths
, unsigned& cacheIndex
) 
4653         dyld::LoadContext context
; 
4654         context
.useSearchPaths          
= search
; 
4655         context
.useFallbackPaths        
= search
; 
4656         context
.useLdLibraryPath        
= false; 
4657         context
.implicitRPath           
= false; 
4658         context
.matchByInstallName      
= false; 
4659         context
.dontLoad                        
= false; 
4660         context
.mustBeBundle            
= false; 
4661         context
.mustBeDylib                     
= true; 
4662         context
.canBePIE                        
= false; 
4663         context
.origin                          
= origin
; 
4664         context
.rpath                           
= rpaths
; 
4665         return load(libraryName
, context
, cacheIndex
); 
4668 static const char* basename(const char* path
) 
4670     const char* last 
= path
; 
4671     for (const char* s 
= path
; *s 
!= '\0'; s
++) { 
4678 static void setContext(const macho_header
* mainExecutableMH
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[]) 
4680         gLinkContext
.loadLibrary                        
= &libraryLocator
; 
4681         gLinkContext
.terminationRecorder        
= &terminationRecorder
; 
4682         gLinkContext
.flatExportFinder           
= &flatFindExportedSymbol
; 
4683         gLinkContext
.coalescedExportFinder      
= &findCoalescedExportedSymbol
; 
4684         gLinkContext
.getCoalescedImages         
= &getCoalescedImages
; 
4685         gLinkContext
.undefinedHandler           
= &undefinedHandler
; 
4686         gLinkContext
.getAllMappedRegions        
= &getMappedRegions
; 
4687         gLinkContext
.bindingHandler                     
= NULL
; 
4688         gLinkContext
.notifySingle                       
= ¬ifySingle
; 
4689         gLinkContext
.notifyBatch                        
= ¬ifyBatch
; 
4690         gLinkContext
.removeImage                        
= &removeImage
; 
4691         gLinkContext
.registerDOFs                       
= dyld3::Loader::dtraceUserProbesEnabled() ? ®isterDOFs 
: NULL
; 
4692         gLinkContext
.clearAllDepths                     
= &clearAllDepths
; 
4693         gLinkContext
.printAllDepths                     
= &printAllDepths
; 
4694         gLinkContext
.imageCount                         
= &imageCount
; 
4695         gLinkContext
.setNewProgramVars          
= &setNewProgramVars
; 
4696         gLinkContext
.inSharedCache                      
= &inSharedCache
; 
4697         gLinkContext
.setErrorStrings            
= &setErrorStrings
; 
4698 #if SUPPORT_OLD_CRT_INITIALIZATION 
4699         gLinkContext
.setRunInitialzersOldWay
= &setRunInitialzersOldWay
; 
4701         gLinkContext
.findImageContainingAddress 
= &findImageContainingAddress
; 
4702         gLinkContext
.addDynamicReference        
= &addDynamicReference
; 
4703 #if SUPPORT_ACCELERATE_TABLES 
4704         gLinkContext
.notifySingleFromCache      
= ¬ifySingleFromCache
; 
4705         gLinkContext
.getPreInitNotifyHandler
= &getPreInitNotifyHandler
; 
4706         gLinkContext
.getBoundBatchHandler   
= &getBoundBatchHandler
; 
4708         gLinkContext
.bindingOptions                     
= ImageLoader::kBindingNone
; 
4709         gLinkContext
.argc                                       
= argc
; 
4710         gLinkContext
.argv                                       
= argv
; 
4711         gLinkContext
.envp                                       
= envp
; 
4712         gLinkContext
.apple                                      
= apple
; 
4713         gLinkContext
.progname                           
= (argv
[0] != NULL
) ? basename(argv
[0]) : ""; 
4714         gLinkContext
.programVars
.mh                     
= mainExecutableMH
; 
4715         gLinkContext
.programVars
.NXArgcPtr      
= &gLinkContext
.argc
; 
4716         gLinkContext
.programVars
.NXArgvPtr      
= &gLinkContext
.argv
; 
4717         gLinkContext
.programVars
.environPtr     
= &gLinkContext
.envp
; 
4718         gLinkContext
.programVars
.__prognamePtr
=&gLinkContext
.progname
; 
4719         gLinkContext
.mainExecutable                     
= NULL
; 
4720         gLinkContext
.imageSuffix                        
= NULL
; 
4721         gLinkContext
.dynamicInterposeArray      
= NULL
; 
4722         gLinkContext
.dynamicInterposeCount      
= 0; 
4723         gLinkContext
.prebindUsage                       
= ImageLoader::kUseAllPrebinding
; 
4724         gLinkContext
.sharedRegionMode           
= ImageLoader::kUseSharedRegion
; 
4730 // Look for a special segment in the mach header.  
4731 // Its presences means that the binary wants to have DYLD ignore 
4732 // DYLD_ environment variables. 
4734 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
4735 static bool hasRestrictedSegment(const macho_header
* mh
) 
4737         const uint32_t cmd_count 
= mh
->ncmds
; 
4738         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4739         const struct load_command
* cmd 
= cmds
; 
4740         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4742                         case LC_SEGMENT_COMMAND
: 
4744                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
4746                                 //dyld::log("seg name: %s\n", seg->segname); 
4747                                 if (strcmp(seg
->segname
, "__RESTRICT") == 0) { 
4748                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
4749                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
4750                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
4751                                                 if (strcmp(sect
->sectname
, "__restrict") == 0)  
4758                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4765 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
4766 static bool isFairPlayEncrypted(const macho_header
* mh
) 
4768         const uint32_t cmd_count 
= mh
->ncmds
; 
4769         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4770         const struct load_command
* cmd 
= cmds
; 
4771         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4772                 if ( cmd
->cmd 
== LC_ENCRYPT_COMMAND 
) { 
4773                         const encryption_info_command
* enc 
= (encryption_info_command
*)cmd
; 
4774                         return (enc
->cryptid 
!= 0); 
4776                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4783 #if SUPPORT_VERSIONED_PATHS 
4785 static bool readFirstPage(const char* dylibPath
, uint8_t firstPage
[4096])  
4788         // open file (automagically closed when this function exits) 
4789         FileOpener 
file(dylibPath
); 
4791         if ( file
.getFileDescriptor() == -1 )  
4794         if ( pread(file
.getFileDescriptor(), firstPage
, 4096, 0) != 4096 ) 
4797         // if fat wrapper, find usable sub-file 
4798         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPage
; 
4799         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
4800                 uint64_t fileOffset
; 
4801                 uint64_t fileLength
; 
4802                 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) { 
4803                         if ( pread(file
.getFileDescriptor(), firstPage
, 4096, fileOffset
) != 4096 ) 
4815 // Peeks at a dylib file and returns its current_version and install_name. 
4816 // Returns false on error. 
4818 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
) 
4820         uint8_t firstPage
[4096]; 
4821         const macho_header
* mh 
= (macho_header
*)firstPage
; 
4822         if ( !readFirstPage(dylibPath
, firstPage
) ) { 
4823                 // If file cannot be read, check to see if path is in shared cache 
4824                 const macho_header
* mhInCache
; 
4825                 const char*                     pathInCache
; 
4827                 if ( !findInSharedCacheImage(dylibPath
, true, NULL
, &mhInCache
, &pathInCache
, &slideInCache
) ) 
4832         // check mach-o header 
4833         if ( mh
->magic 
!= sMainExecutableMachHeader
->magic 
)  
4835         if ( mh
->cputype 
!= sMainExecutableMachHeader
->cputype 
) 
4838         // scan load commands for LC_ID_DYLIB 
4839         const uint32_t cmd_count 
= mh
->ncmds
; 
4840         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4841         const struct load_command
* const cmdsReadEnd 
= (struct load_command
*)(((char*)mh
)+4096); 
4842         const struct load_command
* cmd 
= cmds
; 
4843         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4847                                 const struct dylib_command
* id 
= (struct dylib_command
*)cmd
; 
4848                                 *version 
= id
->dylib
.current_version
; 
4849                                 if ( installName 
!= NULL 
) 
4850                                         strlcpy(installName
, (char *)id 
+ id
->dylib
.name
.offset
, PATH_MAX
); 
4855                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4856                 if ( cmd 
> cmdsReadEnd 
) 
4862 #endif // SUPPORT_VERSIONED_PATHS 
4866 static void printAllImages() 
4868         dyld::log("printAllImages()\n"); 
4869         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4870                 ImageLoader
* image 
= *it
; 
4871                 dyld_image_states imageState 
= image
->getState(); 
4872                 dyld::log("  state=%d, dlopen-count=%d, never-unload=%d, in-use=%d, name=%s\n", 
4873                                   imageState
, image
->dlopenCount(), image
->neverUnload(), image
->isMarkedInUse(), image
->getShortName()); 
4878 void link(ImageLoader
* image
, bool forceLazysBound
, bool neverUnload
, const ImageLoader::RPathChain
& loaderRPaths
, unsigned cacheIndex
) 
4880         // add to list of known images.  This did not happen at creation time for bundles 
4881         if ( image
->isBundle() && !image
->isLinked() ) 
4884         // we detect root images as those not linked in yet  
4885         if ( !image
->isLinked() ) 
4886                 addRootImage(image
); 
4890                 const char* path 
= image
->getPath(); 
4891 #if SUPPORT_ACCELERATE_TABLES 
4892                 if ( image 
== sAllCacheImagesProxy 
) 
4893                         path 
= sAllCacheImagesProxy
->getIndexedPath(cacheIndex
); 
4895                 image
->link(gLinkContext
, forceLazysBound
, false, neverUnload
, loaderRPaths
, path
); 
4897         catch (const char* msg
) { 
4898                 garbageCollectImages(); 
4904 void runInitializers(ImageLoader
* image
) 
4906         // do bottom up initialization 
4907         ImageLoader::InitializerTimingList initializerTimes
[allImagesCount()]; 
4908         initializerTimes
[0].count 
= 0; 
4909         image
->runInitializers(gLinkContext
, initializerTimes
[0]); 
4912 // This function is called at the end of dlclose() when the reference count goes to zero. 
4913 // The dylib being unloaded may have brought in other dependent dylibs when it was loaded. 
4914 // Those dependent dylibs need to be unloaded, but only if they are not referenced by 
4915 // something else.  We use a standard mark and sweep garbage collection. 
4917 // The tricky part is that when a dylib is unloaded it may have a termination function that 
4918 // can run and itself call dlclose() on yet another dylib.  The problem is that this 
4919 // sort of gabage collection is not re-entrant.  Instead a terminator's call to dlclose() 
4920 // which calls garbageCollectImages() will just set a flag to re-do the garbage collection 
4921 // when the current pass is done. 
4923 // Also note that this is done within the dyld global lock, so it is always single threaded. 
4925 void garbageCollectImages() 
4927         static bool sDoingGC 
= false; 
4928         static bool sRedo 
= false; 
4931                 // GC is currently being run, just set a flag to have it run again. 
4940                 // mark phase: mark all images not-in-use 
4941                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4942                         ImageLoader
* image 
= *it
; 
4943                         //dyld::log("gc: neverUnload=%d name=%s\n", image->neverUnload(), image->getShortName()); 
4944                         image
->markNotUsed(); 
4947 #pragma clang diagnostic push 
4948 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
4949                 // sweep phase: mark as in-use, images reachable from never-unload or in-use image 
4950                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4951                         ImageLoader
* image 
= *it
; 
4952                         if ( (image
->dlopenCount() != 0) || (image
->neverUnload() && (image
->getState() >= dyld_image_state_bound
)) || (image 
== sMainExecutable
) ) { 
4953                                 OSSpinLockLock(&sDynamicReferencesLock
); 
4954                                         image
->markedUsedRecursive(sDynamicReferences
); 
4955                                 OSSpinLockUnlock(&sDynamicReferencesLock
); 
4958 #pragma clang diagnostic pop 
4960                 // collect phase: build array of images not marked in-use 
4961                 ImageLoader
* deadImages
[sAllImages
.size()]; 
4962                 unsigned deadCount 
= 0; 
4963                 int maxRangeCount 
= 0; 
4964                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4965                         ImageLoader
* image 
= *it
; 
4966                         if ( ! image
->isMarkedInUse() ) { 
4967                                 deadImages
[deadCount
++] = image
; 
4968                                 if (gLogAPIs
) dyld::log("dlclose(), found unused image %p %s\n", image
, image
->getShortName()); 
4969                                 maxRangeCount 
+= image
->segmentCount(); 
4973                 // collect phase: run termination routines for images not marked in-use 
4974                 if ( maxRangeCount 
!= 0 ) { 
4975                         __cxa_range_t ranges
[maxRangeCount
]; 
4977                         for (unsigned i
=0; i 
< deadCount
; ++i
) { 
4978                                 ImageLoader
* image 
= deadImages
[i
]; 
4979                                 for (unsigned int j
=0; j 
< image
->segmentCount(); ++j
) { 
4980                                         if ( !image
->segExecutable(j
) ) 
4982                                         if ( rangeCount 
< maxRangeCount 
) { 
4983                                                 ranges
[rangeCount
].addr 
= (const void*)image
->segActualLoadAddress(j
); 
4984                                                 ranges
[rangeCount
].length 
= image
->segSize(j
); 
4989                                         runImageStaticTerminators(image
); 
4991                                 catch (const char* msg
) { 
4992                                         dyld::warn("problem running terminators for image: %s\n", msg
); 
4996                         // <rdar://problem/14718598> dyld should call __cxa_finalize_ranges() 
4997                         if ( (rangeCount 
> 0) && (gLibSystemHelpers 
!= NULL
) && (gLibSystemHelpers
->version 
>= 13) ) 
4998                                 (*gLibSystemHelpers
->cxa_finalize_ranges
)(ranges
, rangeCount
); 
5001                 // collect phase: delete all images which are not marked in-use 
5004                         mightBeMore 
= false; 
5005                         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
5006                                 ImageLoader
* image 
= *it
; 
5007                                 if ( ! image
->isMarkedInUse() ) { 
5009                                                 if (gLogAPIs
) dyld::log("dlclose(), deleting %p %s\n", image
, image
->getShortName()); 
5011                                                 ImageLoader::deleteImage(image
); 
5013                                                 break;  // interator in invalidated by this removal 
5015                                         catch (const char* msg
) { 
5016                                                 dyld::warn("problem deleting image: %s\n", msg
); 
5020                 } while ( mightBeMore 
); 
5029 static void preflight_finally(ImageLoader
* image
) 
5031         if ( image
->isBundle() ) { 
5032                 removeImageFromAllImages(image
->machHeader()); 
5033                 ImageLoader::deleteImage(image
); 
5035         sBundleBeingLoaded 
= NULL
; 
5036         dyld::garbageCollectImages(); 
5040 void preflight(ImageLoader
* image
, const ImageLoader::RPathChain
& loaderRPaths
, unsigned cacheIndex
) 
5043                 if ( image
->isBundle() )  
5044                         sBundleBeingLoaded 
= image
;     // hack 
5045                 const char* path 
= image
->getPath(); 
5046 #if SUPPORT_ACCELERATE_TABLES 
5047                 if ( image 
== sAllCacheImagesProxy 
) 
5048                         path 
= sAllCacheImagesProxy
->getIndexedPath(cacheIndex
); 
5050                 image
->link(gLinkContext
, false, true, false, loaderRPaths
, path
); 
5052         catch (const char* msg
) {        
5053                 preflight_finally(image
); 
5056         preflight_finally(image
); 
5059 static void loadInsertedDylib(const char* path
) 
5061         unsigned cacheIndex
; 
5063                 LoadContext context
; 
5064                 context
.useSearchPaths          
= false; 
5065                 context
.useFallbackPaths        
= false; 
5066                 context
.useLdLibraryPath        
= false; 
5067                 context
.implicitRPath           
= false; 
5068                 context
.matchByInstallName      
= false; 
5069                 context
.dontLoad                        
= false; 
5070                 context
.mustBeBundle            
= false; 
5071                 context
.mustBeDylib                     
= true; 
5072                 context
.canBePIE                        
= false; 
5073                 context
.origin                          
= NULL
; // can't use @loader_path with DYLD_INSERT_LIBRARIES 
5074                 context
.rpath                           
= NULL
; 
5075                 load(path
, context
, cacheIndex
); 
5077         catch (const char* msg
) { 
5078                 if ( gLinkContext
.allowInsertFailures 
) 
5079                         dyld::log("dyld: warning: could not load inserted library '%s' into hardened process because %s\n", path
, msg
); 
5081                         halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path
, msg
)); 
5084                 halt(dyld::mkstringf("could not load inserted library '%s'\n", path
)); 
5089 static void configureProcessRestrictions(const macho_header
* mainExecutableMH
, const char* envp
[]) 
5091         uint64_t amfiInputFlags 
= 0; 
5092 #if TARGET_OS_SIMULATOR 
5093         amfiInputFlags 
|= AMFI_DYLD_INPUT_PROC_IN_SIMULATOR
; 
5094 #elif __MAC_OS_X_VERSION_MIN_REQUIRED 
5095         if ( hasRestrictedSegment(mainExecutableMH
) ) 
5096                 amfiInputFlags 
|= AMFI_DYLD_INPUT_PROC_HAS_RESTRICT_SEG
; 
5097 #elif __IPHONE_OS_VERSION_MIN_REQUIRED 
5098         if ( isFairPlayEncrypted(mainExecutableMH
) ) 
5099                 amfiInputFlags 
|= AMFI_DYLD_INPUT_PROC_IS_ENCRYPTED
; 
5101         uint64_t amfiOutputFlags 
= 0; 
5102         const char* amfiFake 
= nullptr; 
5103         if ( dyld3::internalInstall() && dyld3::BootArgs::enableDyldTestMode() ) { 
5104                 amfiFake 
= _simple_getenv(envp
, "DYLD_AMFI_FAKE"); 
5106         if ( amfiFake 
!= nullptr ) { 
5107                 amfiOutputFlags 
= hexToUInt64(amfiFake
, nullptr); 
5109         if ( (amfiFake 
!= nullptr) || (amfi_check_dyld_policy_self(amfiInputFlags
, &amfiOutputFlags
) == 0) ) { 
5110                 gLinkContext
.allowAtPaths                               
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_AT_PATH
); 
5111                 gLinkContext
.allowEnvVarsPrint                  
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS
); 
5112                 gLinkContext
.allowEnvVarsPath                   
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS
); 
5113                 gLinkContext
.allowEnvVarsSharedCache    
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE
); 
5114                 gLinkContext
.allowClassicFallbackPaths  
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS
); 
5115                 gLinkContext
.allowInsertFailures        
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION
); 
5116 #ifdef AMFI_RETURNS_INTERPOSING_FLAG 
5117                 gLinkContext
.allowInterposing           
= (amfiOutputFlags 
& AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING
); 
5119                 gLinkContext
.allowInterposing           
= true; 
5123 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5124                 // support chrooting from old kernel 
5125                 bool isRestricted 
= false; 
5126                 bool libraryValidation 
= false; 
5127                 // any processes with setuid or setgid bit set or with __RESTRICT segment is restricted 
5128                 if ( issetugid() || hasRestrictedSegment(mainExecutableMH
) ) { 
5129                         isRestricted 
= true; 
5131                 bool usingSIP 
= (csr_check(CSR_ALLOW_TASK_FOR_PID
) != 0); 
5133                 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) { 
5134                         // On OS X CS_RESTRICT means the program was signed with entitlements 
5135                         if ( ((flags 
& CS_RESTRICT
) == CS_RESTRICT
) && usingSIP 
) { 
5136                                 isRestricted 
= true; 
5138                         // Library Validation loosens searching but requires everything to be code signed 
5139                         if ( flags 
& CS_REQUIRE_LV 
) { 
5140                                 isRestricted 
= false; 
5141                                 libraryValidation 
= true; 
5144                 gLinkContext
.allowAtPaths                
= !isRestricted
; 
5145                 gLinkContext
.allowEnvVarsPrint           
= !isRestricted
; 
5146                 gLinkContext
.allowEnvVarsPath            
= !isRestricted
; 
5147                 gLinkContext
.allowEnvVarsSharedCache     
= !libraryValidation 
|| !usingSIP
; 
5148                 gLinkContext
.allowClassicFallbackPaths   
= !isRestricted
; 
5149                 gLinkContext
.allowInsertFailures         
= false; 
5150                 gLinkContext
.allowInterposing            
= true; 
5152                 halt("amfi_check_dyld_policy_self() failed\n"); 
5157 // called by _dyld_register_driverkit_main() 
5158 void setMainEntry(void (*main
)()) 
5160         if ( sEntryOveride 
== nullptr ) 
5161                 sEntryOveride 
= main
; 
5163                 halt("_dyld_register_driverkit_main() may only be called once"); 
5166 bool processIsRestricted() 
5168 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5169         return !gLinkContext
.allowEnvVarsPath
; 
5176 // <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots 
5177 static void addDyldImageToUUIDList() 
5179         const struct macho_header
* mh 
= (macho_header
*)&__dso_handle
; 
5180         const uint32_t cmd_count 
= mh
->ncmds
; 
5181         const struct load_command
* const cmds 
= (struct load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
5182         const struct load_command
* cmd 
= cmds
; 
5183         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
5186                                 uuid_command
* uc 
= (uuid_command
*)cmd
; 
5187                                 dyld_uuid_info info
; 
5188                                 info
.imageLoadAddress 
= (mach_header
*)mh
; 
5189                                 memcpy(info
.imageUUID
, uc
->uuid
, 16); 
5190                                 addNonSharedCacheImageUUID(info
); 
5194                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
5198 void notifyKernelAboutImage(const struct macho_header
* mh
, const char* fileInfo
) 
5200         const char *endptr 
= nullptr; 
5201         uint64_t tmp 
= hexToUInt64(fileInfo
, &endptr
); 
5202         fsid_t fsid 
= *reinterpret_cast<fsid_t 
*>(&tmp
); 
5203         uint64_t fsobj_id_scalar 
= 0; 
5204         fsobj_id_t fsobj_id 
= {0}; 
5205         if (endptr 
!= nullptr) { 
5206                 fsobj_id_scalar 
= hexToUInt64(endptr
+1, &endptr
); 
5207                 fsobj_id 
= *reinterpret_cast<fsobj_id_t 
*>(&tmp
); 
5209         const uint32_t cmd_count 
= mh
->ncmds
; 
5210         const struct load_command
* const cmds 
= (struct load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
5211         const struct load_command
* cmd 
= cmds
; 
5212         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
5215                                 // Add dyld to the kernel image info 
5216                                 uuid_command
* uc 
= (uuid_command
*)cmd
; 
5217                                 char path
[MAXPATHLEN
]; 
5218                                 if (fsgetpath(path
, MAXPATHLEN
, &fsid
, fsobj_id_scalar
) < 0) { 
5221                                 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A
, path
, (const uuid_t 
*)&uc
->uuid
[0], fsobj_id
, fsid
, (const mach_header 
*)mh
); 
5225                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
5229 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5230 static void* getProcessInfo() { return dyld::gProcessInfo
; } 
5231 static const SyscallHelpers sSysCalls 
= { 
5233                 // added in version 1 
5252                 &pthread_mutex_lock
,  
5253                 &pthread_mutex_unlock
, 
5255                 &mach_port_deallocate
,  
5257                 &mach_timebase_info
, 
5258                 &OSAtomicCompareAndSwapPtrBarrier
,  
5262                 &mach_absolute_time
, 
5263                 // added in version 2 
5265                 // added in version 3 
5269                 // added in version 4 
5270                 &coresymbolication_load_notifier
, 
5271                 &coresymbolication_unload_notifier
, 
5272                 // Added in version 5 
5273                 &proc_regionfilename
, 
5275                 &mach_port_insert_right
, 
5276                 &mach_port_allocate
, 
5278                 // Added in version 6 
5279                 &abort_with_payload
, 
5280                 // Added in version 7 
5281                 &legacy_task_register_dyld_image_infos
, 
5282                 &legacy_task_unregister_dyld_image_infos
, 
5283                 &legacy_task_get_dyld_image_infos
, 
5284                 &legacy_task_register_dyld_shared_cache_image_info
, 
5285                 &legacy_task_register_dyld_set_dyld_state
, 
5286                 &legacy_task_register_dyld_get_process_state
, 
5287                 // Added in version 8 
5292                 // Added in version 9 
5293                 &kdebug_trace_string
, 
5294                 // Added in version 10 
5295                 &amfi_check_dyld_policy_self
, 
5296                 // Added in version 11 
5297                 ¬ifyMonitoringDyldMain
, 
5298                 ¬ifyMonitoringDyld
, 
5299                 // Add in version 12 
5301                 &mach_port_construct
, 
5305 __attribute__((noinline
)) 
5306 static const char* useSimulatorDyld(int fd
, const macho_header
* mainExecutableMH
, const char* dyldPath
, 
5307                                                                 int argc
, const char* argv
[], const char* envp
[], const char* apple
[], 
5308                                                                 uintptr_t* startGlue
, uintptr_t* mainAddr
) 
5313         // <rdar://problem/25311921> simulator does not support restricted processes 
5315         if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) == -1 ) 
5316                 return "csops() failed"; 
5317         if ( (flags 
& CS_RESTRICT
) == CS_RESTRICT 
) 
5318                 return "dyld_sim cannot be loaded in a restricted process"; 
5320                 return "dyld_sim cannot be loaded in a setuid process"; 
5321         if ( hasRestrictedSegment(mainExecutableMH
) ) 
5322                 return "dyld_sim cannot be loaded in a restricted process"; 
5324         // get file size of dyld_sim 
5326         if ( fstat(fd
, &sb
) == -1 ) 
5327                 return "stat(dyld_sim) failed"; 
5329         // read first page of dyld_sim file 
5330         uint8_t firstPage
[4096]; 
5331         if ( pread(fd
, firstPage
, 4096, 0) != 4096 ) 
5332                 return "pread(dyld_sim) failed"; 
5334         // if fat file, pick matching slice 
5335         uint64_t fileOffset 
= 0; 
5336         uint64_t fileLength 
= sb
.st_size
; 
5337         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPage
; 
5338         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
5339                 if ( !fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) )  
5340                         return "no matching arch in dyld_sim"; 
5341                 // re-read buffer from start of mach-o slice in fat file 
5342                 if ( pread(fd
, firstPage
, 4096, fileOffset
) != 4096 ) 
5343                         return "pread(dyld_sim) failed"; 
5345         else if ( !isCompatibleMachO(firstPage
, dyldPath
) ) { 
5346                 return "dyld_sim is not compatible with the loaded process, likely due to architecture mismatch"; 
5349         // calculate total size of dyld segments 
5350         const macho_header
* mh 
= (const macho_header
*)firstPage
; 
5351         struct macho_segment_command
* lastSeg 
= NULL
; 
5352         struct macho_segment_command
* firstSeg 
= NULL
; 
5353         uintptr_t mappingSize 
= 0; 
5354         uintptr_t preferredLoadAddress 
= 0; 
5355         const uint32_t cmd_count 
= mh
->ncmds
; 
5356         if ( mh
->sizeofcmds 
> 4096 ) 
5357                 return "dyld_sim load commands to large"; 
5358         if ( (sizeof(macho_header
) + mh
->sizeofcmds
) > 4096 ) 
5359                 return "dyld_sim load commands to large"; 
5360         struct linkedit_data_command
* codeSigCmd 
= NULL
; 
5361         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
5362         const struct load_command
* const endCmds 
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
); 
5363         const struct load_command
* cmd 
= cmds
; 
5364         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
5365                 uint32_t cmdLength 
= cmd
->cmdsize
; 
5366                 if ( cmdLength 
< 8 ) 
5367                         return "dyld_sim load command too small"; 
5368                 const struct load_command
* const nextCmd 
= (const struct load_command
*)(((char*)cmd
)+cmdLength
); 
5369                 if ( (nextCmd 
> endCmds
) || (nextCmd 
< cmd
) ) 
5370                         return "dyld_sim load command too large"; 
5372                         case LC_SEGMENT_COMMAND
: 
5374                                         struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
5375                                         if ( seg
->vmaddr 
+ seg
->vmsize 
< seg
->vmaddr 
) 
5376                                                 return "dyld_sim seg wraps address space"; 
5377                                         if ( seg
->vmsize 
< seg
->filesize 
) 
5378                                                 return "dyld_sim seg vmsize too small"; 
5379                                         if ( (seg
->fileoff 
+ seg
->filesize
) < seg
->fileoff 
) 
5380                                                 return "dyld_sim seg size wraps address space"; 
5381                                         if ( lastSeg 
== NULL 
) { 
5382                                                 // first segment must be __TEXT and start at beginning of file/slice 
5384                                                 if ( strcmp(seg
->segname
, "__TEXT") != 0 ) 
5385                                                         return "dyld_sim first segment not __TEXT"; 
5386                                                 if ( seg
->fileoff 
!= 0 ) 
5387                                                         return "dyld_sim first segment not at file offset zero"; 
5388                                                 if ( seg
->filesize 
< (sizeof(macho_header
) + mh
->sizeofcmds
) ) 
5389                                                         return "dyld_sim first segment smaller than load commands"; 
5390                                                 preferredLoadAddress 
= seg
->vmaddr
; 
5393                                                 // other sements must be continguous with previous segment and not executable 
5394                                                 if ( lastSeg
->fileoff 
+ lastSeg
->filesize 
!= seg
->fileoff 
) 
5395                                                         return "dyld_sim segments not contiguous"; 
5396                                                 if ( lastSeg
->vmaddr 
+ lastSeg
->vmsize 
!= seg
->vmaddr 
) 
5397                                                         return "dyld_sim segments not address contiguous"; 
5398                                                 if ( (seg
->initprot 
& VM_PROT_EXECUTE
) != 0 ) 
5399                                                         return "dyld_sim non-first segment is executable"; 
5401                                         mappingSize 
+= seg
->vmsize
; 
5405                         case LC_SEGMENT_COMMAND_WRONG
: 
5406                                 return "dyld_sim wrong load segment load command"; 
5407                         case LC_CODE_SIGNATURE
: 
5408                                 codeSigCmd 
= (struct linkedit_data_command
*)cmd
; 
5413         // last segment must be named __LINKEDIT and not writable 
5414         if ( lastSeg 
== NULL 
) 
5415                 return "dyld_sim has no segments"; 
5416         if ( strcmp(lastSeg
->segname
, "__LINKEDIT") != 0 ) 
5417                 return "dyld_sim last segment not __LINKEDIT"; 
5418         if ( lastSeg
->initprot 
& VM_PROT_WRITE 
) 
5419                 return "dyld_sim __LINKEDIT segment writable"; 
5421         // must have code signature which is contained within LINKEDIT segment 
5422         if ( codeSigCmd 
== NULL 
) 
5423                 return "dyld_sim not code signed"; 
5424         if ( codeSigCmd
->dataoff 
< lastSeg
->fileoff 
) 
5425                 return "dyld_sim code signature not in __LINKEDIT"; 
5426         if ( (codeSigCmd
->dataoff 
+ codeSigCmd
->datasize
) <  codeSigCmd
->dataoff 
) 
5427                 return "dyld_sim code signature size wraps"; 
5428         if ( (codeSigCmd
->dataoff 
+ codeSigCmd
->datasize
) > (lastSeg
->fileoff 
+ lastSeg
->filesize
) ) 
5429                 return "dyld_sim code signature extends beyond __LINKEDIT"; 
5431         // register code signature with kernel before mmap()ing segments 
5432         fsignatures_t siginfo
; 
5433         siginfo
.fs_file_start
=fileOffset
;                                                       // start of mach-o slice in fat file 
5434         siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
);       // start of code-signature in mach-o file 
5435         siginfo
.fs_blob_size
=codeSigCmd
->datasize
;                                      // size of code-signature 
5436         int result 
= fcntl(fd
, F_ADDFILESIGS_FOR_DYLD_SIM
, &siginfo
); 
5437         if ( result 
== -1 ) { 
5438                 return mkstringf("dyld_sim fcntl(F_ADDFILESIGS_FOR_DYLD_SIM) failed with errno=%d", errno
); 
5440         // file range covered by code signature must extend up to code signature itself 
5441         if ( siginfo
.fs_file_start 
< codeSigCmd
->dataoff 
) 
5442                 return mkstringf("dyld_sim code signature does not cover all of dyld_sim. Signature covers up to 0x%08lX. Signature starts at 0x%08X", (unsigned long)siginfo
.fs_file_start
, codeSigCmd
->dataoff
); 
5444         // reserve space, then mmap each segment 
5445         vm_address_t loadAddress 
= 0; 
5446         if ( ::vm_allocate(mach_task_self(), &loadAddress
, mappingSize
, VM_FLAGS_ANYWHERE
) != 0 ) 
5447                 return "dyld_sim cannot allocate space"; 
5449         struct source_version_command
*  dyldVersionCmd 
= NULL
; 
5450         struct uuid_command
*                    uuidCmd 
= NULL
; 
5451         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
5453                         case LC_SEGMENT_COMMAND
: 
5455                                         struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
5456                                         uintptr_t requestedLoadAddress 
= seg
->vmaddr 
- preferredLoadAddress 
+ loadAddress
; 
5457                                         void* segAddress 
= ::mmap((void*)requestedLoadAddress
, seg
->filesize
, seg
->initprot
, MAP_FIXED 
| MAP_PRIVATE
, fd
, fileOffset 
+ seg
->fileoff
); 
5458                                         //dyld::log("dyld_sim %s mapped at %p\n", seg->segname, segAddress); 
5459                                         if ( segAddress 
== (void*)(-1) ) 
5460                                                 return "dyld_sim mmap() of segment failed"; 
5461                                         if ( ((uintptr_t)segAddress 
< loadAddress
) || ((uintptr_t)segAddress
+seg
->filesize 
> loadAddress
+mappingSize
) ) 
5462                                                 return "dyld_sim mmap() to wrong location"; 
5465                         case LC_SOURCE_VERSION
: 
5466                                 dyldVersionCmd 
= (struct source_version_command
*)cmd
; 
5469                                 uuidCmd 
= (uuid_command
*)cmd
; 
5473                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
5477         // walk newly mapped dyld_sim __TEXT load commands to find entry point 
5478         uintptr_t entry 
= 0; 
5479         cmd 
= (struct load_command
*)(((char*)loadAddress
)+sizeof(macho_header
)); 
5480         const uint32_t count 
= ((macho_header
*)(loadAddress
))->ncmds
; 
5481         for (uint32_t i 
= 0; i 
< count
; ++i
) { 
5482                 if (cmd
->cmd 
== LC_UNIXTHREAD
) { 
5484                         const i386_thread_state_t
* registers 
= (i386_thread_state_t
*)(((char*)cmd
) + 16); 
5485                         // entry point must be in first segment 
5486                         if ( registers
->__eip 
< firstSeg
->vmaddr 
) 
5487                                 return "dyld_sim entry point not in __TEXT segment"; 
5488                         if ( registers
->__eip 
> (firstSeg
->vmaddr 
+ firstSeg
->vmsize
) ) 
5489                                 return "dyld_sim entry point not in __TEXT segment"; 
5490                         entry 
= (registers
->__eip 
+ loadAddress 
- preferredLoadAddress
); 
5492                         const x86_thread_state64_t
* registers 
= (x86_thread_state64_t
*)(((char*)cmd
) + 16); 
5493                         // entry point must be in first segment 
5494                         if ( registers
->__rip 
< firstSeg
->vmaddr 
) 
5495                                 return "dyld_sim entry point not in __TEXT segment"; 
5496                         if ( registers
->__rip 
> (firstSeg
->vmaddr 
+ firstSeg
->vmsize
) ) 
5497                                 return "dyld_sim entry point not in __TEXT segment"; 
5498                         entry 
= (registers
->__rip 
+ loadAddress 
- preferredLoadAddress
); 
5501                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
5504                 return "dyld_sim entry not found"; 
5506         // notify debugger that dyld_sim is loaded 
5507         dyld_image_info info
; 
5508         info
.imageLoadAddress 
= (mach_header
*)loadAddress
; 
5509         info
.imageFilePath        
= strdup(dyldPath
); 
5510         info
.imageFileModDate 
= sb
.st_mtime
; 
5511         addImagesToAllImages(1, &info
); 
5512         dyld::gProcessInfo
->notification(dyld_image_adding
, 1, &info
); 
5514         fsid_t fsid 
= {{0, 0}}; 
5515         fsobj_id_t fsobj 
= {0}; 
5516         ino_t inode 
= sb
.st_ino
; 
5517         fsobj
.fid_objno 
= (uint32_t)inode
; 
5518         fsobj
.fid_generation 
= (uint32_t)(inode
>>32); 
5519         fsid
.val
[0] = sb
.st_dev
; 
5520         dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A
, dyldPath
, (const uuid_t 
*)&uuidCmd
->uuid
[0], fsobj
, fsid
, (const mach_header 
*)mh
); 
5522         const char** appleParams 
= apple
; 
5524         // <rdar://problem/5077374> have host dyld detach macOS shared cache from process before jumping into dyld_sim 
5525         dyld3::deallocateExistingSharedCache(); 
5527         // jump into new simulator dyld 
5528         typedef uintptr_t (*sim_entry_proc_t
)(int argc
, const char* argv
[], const char* envp
[], const char* apple
[], 
5529                                                                 const macho_header
* mainExecutableMH
, const macho_header
* dyldMH
, uintptr_t dyldSlide
, 
5530                                                                 const dyld::SyscallHelpers
* vtable
, uintptr_t* startGlue
); 
5531         sim_entry_proc_t newDyld 
= (sim_entry_proc_t
)entry
; 
5532         *mainAddr 
= (*newDyld
)(argc
, argv
, envp
, appleParams
, mainExecutableMH
, (macho_header
*)loadAddress
, 
5533                                          loadAddress 
- preferredLoadAddress
,  
5534                                          &sSysCalls
, startGlue
); 
5540 // If the DYLD_SKIP_MAIN environment is set to 1, dyld will return the  
5541 // address of this function instead of main() in the target program which  
5542 // __dyld_start jumps to. Useful for qualifying dyld itself. 
5552 #if !TARGET_OS_SIMULATOR 
5554 static bool envVarMatches(const dyld3::closure::LaunchClosure
* mainClosure
, const char* envp
[], const char* varName
) 
5556         __block 
const char* valueFromClosure 
= nullptr; 
5557         mainClosure
->forEachEnvVar(^(const char* keyEqualValue
, bool& stop
) { 
5558                 size_t keyLen 
= strlen(varName
); 
5559                 if ( (strncmp(varName
, keyEqualValue
, keyLen
) == 0) && (keyEqualValue
[keyLen
] == '=') ) { 
5560                         valueFromClosure 
= &keyEqualValue
[keyLen
+1]; 
5565         const char* valueFromEnv 
= _simple_getenv(envp
, varName
); 
5567         bool inClosure 
= (valueFromClosure 
!= nullptr); 
5568         bool inEnv     
= (valueFromEnv 
!= nullptr); 
5569         if ( inClosure 
!= inEnv 
) 
5571         if ( !inClosure 
&& !inEnv 
) 
5573         return ( strcmp(valueFromClosure
, valueFromEnv
) == 0 ); 
5576 static const char* const sEnvVarsToCheck
[] = { 
5577         "DYLD_LIBRARY_PATH", 
5578         "DYLD_FRAMEWORK_PATH", 
5579         "DYLD_FALLBACK_LIBRARY_PATH", 
5580         "DYLD_FALLBACK_FRAMEWORK_PATH", 
5581         "DYLD_INSERT_LIBRARIES", 
5582         "DYLD_IMAGE_SUFFIX", 
5583         "DYLD_VERSIONED_FRAMEWORK_PATH", 
5584         "DYLD_VERSIONED_LIBRARY_PATH", 
5588 static bool envVarsMatch(const dyld3::closure::LaunchClosure
* mainClosure
, const char* envp
[]) 
5590         for (const char* envVar 
: sEnvVarsToCheck
) { 
5591                 if ( !envVarMatches(mainClosure
, envp
, envVar
) ) { 
5592                         if ( gLinkContext
.verboseWarnings 
) 
5593                                 dyld::log("dyld: closure %p not used because %s changed\n", mainClosure
, envVar
); 
5598         // FIXME: dyld3 doesn't support versioned paths so we need to fall back to dyld2 if we have them. 
5599         // <rdar://problem/37004660> dyld3: support DYLD_VERSIONED_*_PATHs ? 
5600         if ( sEnv
.DYLD_VERSIONED_LIBRARY_PATH 
!= nullptr ) { 
5601                 if ( gLinkContext
.verboseWarnings 
) 
5602                         dyld::log("dyld: closure %p not used because DYLD_VERSIONED_LIBRARY_PATH used\n", mainClosure
); 
5605         if ( sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH 
!= nullptr ) { 
5606                 if ( gLinkContext
.verboseWarnings 
) 
5607                         dyld::log("dyld: closure %p not used because DYLD_VERSIONED_FRAMEWORK_PATH used\n", mainClosure
); 
5614 static bool closureValid(const dyld3::closure::LaunchClosure
* mainClosure
, const dyld3::closure::LoadedFileInfo
& mainFileInfo
, 
5615                                                  const uint8_t* mainExecutableCDHash
, bool closureInCache
, const char* envp
[]) 
5617         if ( closureInCache 
) { 
5618                 // We can only use the cache closure if the cache version is the same as dyld 
5619                 if (sSharedCacheLoadInfo
.loadAddress
->header
.formatVersion 
!= dyld3::closure::kFormatVersion
) { 
5620                         if ( gLinkContext
.verboseWarnings 
) 
5621                                 dyld::log("dyld: dyld closure version 0x%08X does not match dyld cache version 0x%08X\n", 
5622                                                   dyld3::closure::kFormatVersion
, sSharedCacheLoadInfo
.loadAddress
->header
.formatVersion
); 
5625                 if (sForceInvalidSharedCacheClosureFormat
) { 
5626                         if ( gLinkContext
.verboseWarnings 
) 
5627                                 dyld::log("dyld: closure %p dyld cache version forced invalid\n", mainClosure
); 
5631                 // verify current dyld cache is same as expected 
5632                 uuid_t expectedCacheUUID
; 
5633                 if ( mainClosure
->builtAgainstDyldCache(expectedCacheUUID
) ) { 
5634                         if ( sSharedCacheLoadInfo
.loadAddress 
== nullptr ) { 
5635                                 if ( gLinkContext
.verboseWarnings 
) 
5636                                         dyld::log("dyld: closure %p dyld cache not loaded\n", mainClosure
); 
5640                                 uuid_t actualCacheUUID
; 
5641                                 sSharedCacheLoadInfo
.loadAddress
->getUUID(actualCacheUUID
); 
5642                                 if ( memcmp(expectedCacheUUID
, actualCacheUUID
, sizeof(uuid_t
)) != 0 ) { 
5643                                         if ( gLinkContext
.verboseWarnings 
) 
5644                                                 dyld::log("dyld: closure %p not used because built against different dyld cache\n", mainClosure
); 
5650                         // closure built assume there is no dyld cache 
5651                         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) { 
5652                                 if ( gLinkContext
.verboseWarnings 
) 
5653                                         dyld::log("dyld: closure %p built expecting no dyld cache\n", mainClosure
); 
5657 #if __IPHONE_OS_VERSION_MIN_REQUIRED 
5658                 // verify this closure is not from a previous reboot 
5659                 const char* expectedBootUUID 
= mainClosure
->bootUUID(); 
5660                 char actualBootSessionUUID
[256] = { 0 }; 
5661                 size_t bootSize 
= sizeof(actualBootSessionUUID
); 
5662                 bool gotActualBootUUID 
= (sysctlbyname("kern.bootsessionuuid", actualBootSessionUUID
, &bootSize
, NULL
, 0) == 0); 
5663                 if ( gotActualBootUUID 
) { 
5664                         // If we got a boot UUID then we should have also recorded it in the closure 
5665                         if ( expectedBootUUID 
== nullptr) { 
5666                                 // The closure didn't have a UUID but now we do.  This isn't valid. 
5667                                 if ( gLinkContext
.verboseWarnings 
) 
5668                                         dyld::log("dyld: closure %p missing boot-UUID\n", mainClosure
); 
5670                         } else if ( strcmp(expectedBootUUID
, actualBootSessionUUID
) != 0 ) { 
5671                                 if ( gLinkContext
.verboseWarnings 
) 
5672                                         dyld::log("dyld: closure %p built in different boot context\n", mainClosure
); 
5676                         // We didn't get a UUID now, which is ok so long as the closure also doesn't have one. 
5677                         if ( expectedBootUUID 
!= nullptr) { 
5678                                 if ( gLinkContext
.verboseWarnings 
) 
5679                                         dyld::log("dyld: closure %p has boot-UUID\n", mainClosure
); 
5686         // verify all mach-o files have not changed since closure was built 
5687         __block 
bool foundFileThatInvalidatesClosure 
= false; 
5688         mainClosure
->images()->forEachImage(^(const dyld3::closure::Image
* image
, bool& stop
) { 
5689                 __block 
uint64_t expectedInode
; 
5690                 __block 
uint64_t expectedMtime
; 
5691                 if ( image
->hasFileModTimeAndInode(expectedInode
, expectedMtime
) ) { 
5692                         struct stat statBuf
; 
5693                         if ( ::stat(image
->path(), &statBuf
) == 0 ) { 
5694                                 if ( (statBuf
.st_mtime 
!= expectedMtime
) || (statBuf
.st_ino 
!= expectedInode
) ) { 
5695                                         if ( gLinkContext
.verboseWarnings 
) 
5696                                                 dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure
, image
->path()); 
5697                                         foundFileThatInvalidatesClosure 
= true; 
5702                                 if ( gLinkContext
.verboseWarnings 
) 
5703                                         dyld::log("dyld: closure %p not used because '%s' is needed by closure but is missing\n", mainClosure
, image
->path()); 
5704                                 foundFileThatInvalidatesClosure 
= true; 
5709         if ( foundFileThatInvalidatesClosure 
) 
5712         // verify cdHash of main executable is same as recorded in closure 
5713         const dyld3::closure::Image
* mainImage 
= mainClosure
->images()->imageForNum(mainClosure
->topImage()); 
5715         __block 
bool foundCDHash 
= false; 
5716         __block 
bool foundValidCDHash 
= false; 
5717         mainImage
->forEachCDHash(^(const uint8_t *expectedHash
, bool& stop
) { 
5718                 if ( mainExecutableCDHash 
== nullptr ) { 
5719                         if ( gLinkContext
.verboseWarnings 
) 
5720                                 dyld::log("dyld: closure %p not used because main executable is not code signed but was expected to be\n", mainClosure
); 
5725                 if ( memcmp(mainExecutableCDHash
, expectedHash
, 20) == 0 ) { 
5726                         // found a match, so lets use this one. 
5727                         foundValidCDHash 
= true; 
5733         // If we found cd hashes, but they were all invalid, then print them out 
5734         if ( foundCDHash 
&& !foundValidCDHash 
) { 
5735                 auto getCDHashString 
= [](const uint8_t cdHash
[20], char* cdHashBuffer
) { 
5736                         for (int i
=0; i 
< 20; ++i
) { 
5737                                 uint8_t byte 
= cdHash
[i
]; 
5738                                 uint8_t nibbleL 
= byte 
& 0x0F; 
5739                                 uint8_t nibbleH 
= byte 
>> 4; 
5740                                 if ( nibbleH 
< 10 ) { 
5741                                         *cdHashBuffer 
= '0' + nibbleH
; 
5744                                         *cdHashBuffer 
= 'a' + (nibbleH
-10); 
5747                                 if ( nibbleL 
< 10 ) { 
5748                                         *cdHashBuffer 
= '0' + nibbleL
; 
5751                                         *cdHashBuffer 
= 'a' + (nibbleL
-10); 
5756                 if ( gLinkContext
.verboseWarnings 
) { 
5757                         mainImage
->forEachCDHash(^(const uint8_t *expectedHash
, bool &stop
) { 
5758                                 char mainExecutableCDHashBuffer
[128] = { '\0' }; 
5759                                 char expectedCDHashBuffer
[128] = { '\0' }; 
5761                                 getCDHashString(mainExecutableCDHash
, mainExecutableCDHashBuffer
); 
5762                                 getCDHashString(expectedHash
, expectedCDHashBuffer
); 
5764                                 dyld::log("dyld: closure %p not used because main executable cd-hash (%s) changed since closure was built with (%s)\n", 
5765                                                   mainClosure
, mainExecutableCDHashBuffer
, expectedCDHashBuffer
); 
5772         // verify UUID of main executable is same as recorded in closure 
5773         uuid_t expectedUUID
; 
5774         bool hasExpect 
= mainImage
->getUuid(expectedUUID
); 
5776         const dyld3::MachOLoaded
* mainExecutableMH 
= (const dyld3::MachOLoaded
*)mainFileInfo
.fileContent
; 
5777         bool hasActual 
= mainExecutableMH
->getUuid(actualUUID
); 
5778         if ( hasExpect 
!= hasActual 
) { 
5779                 if ( gLinkContext
.verboseWarnings 
) 
5780                         dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosure
); 
5783         if ( hasExpect 
&& hasActual 
&& memcmp(actualUUID
, expectedUUID
, sizeof(uuid_t
)) != 0 ) { 
5784                 if ( gLinkContext
.verboseWarnings 
) 
5785                         dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosure
); 
5789         // verify DYLD_* env vars are same as when closure was built 
5790         if ( !envVarsMatch(mainClosure
, envp
) ) { 
5794         // verify files that are supposed to be missing actually are missing 
5795         mainClosure
->forEachMustBeMissingFile(^(const char* path
, bool& stop
) { 
5796                 struct stat statBuf
; 
5797                 if ( ::stat(path
, &statBuf
) == 0 ) { 
5799                         foundFileThatInvalidatesClosure 
= true; 
5800                         if ( gLinkContext
.verboseWarnings 
) 
5801                                 dyld::log("dyld: closure %p not used because found unexpected file '%s'\n", mainClosure
, path
); 
5805         // verify files that are supposed to exist are there with the 
5806         mainClosure
->forEachSkipIfExistsFile(^(const dyld3::closure::LaunchClosure::SkippedFile 
&file
, bool &stop
) { 
5807                 struct stat statBuf
; 
5808                 if ( ::stat(file
.path
, &statBuf
) == 0 ) { 
5809                         if ( (statBuf
.st_mtime 
!= file
.mtime
) || (statBuf
.st_ino 
!= file
.inode
) ) { 
5810                                 if ( gLinkContext
.verboseWarnings 
) 
5811                                         dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure
, file
.path
); 
5812                                 foundFileThatInvalidatesClosure 
= true; 
5818         // verify closure did not require anything unavailable 
5819         if ( mainClosure
->usedAtPaths() && !gLinkContext
.allowAtPaths 
) { 
5820                 if ( gLinkContext
.verboseWarnings 
) 
5821                         dyld::log("dyld: closure %p not used because is used @paths, but process does not allow that\n", mainClosure
); 
5824         if ( mainClosure
->usedFallbackPaths() && !gLinkContext
.allowClassicFallbackPaths 
) { 
5825                 if ( gLinkContext
.verboseWarnings 
) 
5826                         dyld::log("dyld: closure %p not used because is used default fallback paths, but process does not allow that\n", mainClosure
); 
5829         if ( mainClosure
->usedInterposing() && !gLinkContext
.allowInterposing 
) { 
5830                 if ( gLinkContext
.verboseWarnings 
) 
5831                         dyld::log("dyld: closure %p not used because is uses interposing, but process does not allow that\n", mainClosure
); 
5834         return !foundFileThatInvalidatesClosure
; 
5837 static bool nolog(const char* format
, ...) 
5842 static bool dolog(const char* format
, ...) 
5845         va_start(list
, format
); 
5851 static bool launchWithClosure(const dyld3::closure::LaunchClosure
* mainClosure
, 
5852                                                           const DyldSharedCache
* dyldCache
, 
5853                                                           const dyld3::MachOLoaded
* mainExecutableMH
, uintptr_t mainExecutableSlide
, 
5854                                                           int argc
, const char* argv
[], const char* envp
[], const char* apple
[], 
5855                                                           uintptr_t* entry
, uintptr_t* startGlue
) 
5857         // build list of all known ImageArrays (at most three: cached dylibs, other OS dylibs, and main prog) 
5858         STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray
*, imagesArrays
, 3); 
5859         const dyld3::closure::ImageArray
* mainClosureImages 
= mainClosure
->images(); 
5860         if ( dyldCache 
!= nullptr ) { 
5861                 imagesArrays
.push_back(dyldCache
->cachedDylibsImageArray()); 
5862                 if ( auto others 
= dyldCache
->otherOSImageArray() ) 
5863                         imagesArrays
.push_back(others
); 
5865         imagesArrays
.push_back(mainClosureImages
); 
5867         // allocate space for Array<LoadedImage> 
5868         STACK_ALLOC_ARRAY(dyld3::LoadedImage
, allImages
, mainClosure
->initialLoadCount()); 
5870         // Get the pre-optimized Objective-C so that we can bind the selectors 
5871         const dyld3::closure::ObjCSelectorOpt
*                                  selectorOpt 
= nullptr; 
5872         dyld3::Array
<dyld3::closure::Image::ObjCSelectorImage
>  selectorImages
; 
5873         mainClosure
->selectorHashTable(selectorImages
, selectorOpt
); 
5875         __block 
dyld3::Loader 
loader({}, allImages
, dyldCache
, imagesArrays
, 
5876                                                                  selectorOpt
, selectorImages
, 
5877                                                                  (gLinkContext
.verboseLoading 
? &dolog 
: &nolog
), 
5878                                                                  (gLinkContext
.verboseMapping 
? &dolog 
: &nolog
), 
5879                                                                  (gLinkContext
.verboseBind    
? &dolog 
: &nolog
), 
5880                                                                  (gLinkContext
.verboseDOF     
? &dolog 
: &nolog
)); 
5881         dyld3::closure::ImageNum mainImageNum 
= mainClosure
->topImage(); 
5882         mainClosureImages
->forEachImage(^(const dyld3::closure::Image
* image
, bool& stop
) { 
5883                 if ( image
->imageNum() == mainImageNum 
) { 
5884                         // add main executable (which is already mapped by kernel) to list 
5885                         dyld3::LoadedImage mainLoadedImage 
= dyld3::LoadedImage::make(image
, mainExecutableMH
); 
5886                         mainLoadedImage
.setState(dyld3::LoadedImage::State::mapped
); 
5887                         mainLoadedImage
.markLeaveMapped(); 
5888                         loader
.addImage(mainLoadedImage
); 
5892                         // add inserted library to initial list 
5893                         loader
.addImage(dyld3::LoadedImage::make(image
)); 
5897         // recursively load all dependents and fill in allImages array 
5898         bool someCacheImageOverridden 
= false; 
5900         loader
.completeAllDependents(diag
, someCacheImageOverridden
); 
5901         if ( diag
.noError() ) 
5902                 loader
.mapAndFixupAllImages(diag
, dyld3::Loader::dtraceUserProbesEnabled()); 
5903         if ( diag
.hasError() ) { 
5904                 if ( gLinkContext
.verboseWarnings 
) 
5905                         dyld::log("dyld: %s\n", diag
.errorMessage()); 
5909         //dyld::log("loaded image list:\n"); 
5910         //for (const dyld3::LoadedImage& info : allImages) { 
5911         //      dyld::log("mh=%p, path=%s\n", info.loadedAddress(), info.image()->path()); 
5914         // find libdyld entry 
5915         dyld3::closure::Image::ResolvedSymbolTarget dyldEntry
; 
5916         mainClosure
->libDyldEntry(dyldEntry
); 
5917         const dyld3::LibDyldEntryVector
* libDyldEntry 
= (dyld3::LibDyldEntryVector
*)loader
.resolveTarget(dyldEntry
); 
5919         // send info on all images to libdyld.dylb 
5920         libDyldEntry
->setVars(mainExecutableMH
, argc
, argv
, envp
, apple
); 
5921 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5922         uint32_t progVarsOffset
; 
5923         if ( mainClosure
->hasProgramVars(progVarsOffset
) ) { 
5924                 if ( libDyldEntry
->vectorVersion 
>= 8 ) { 
5925                         // main executable contains globals to hold argc, argv, envp, and progname, but they need to be filled in 
5926                         ProgramVars
* vars 
= (ProgramVars
*)((uint8_t*)mainExecutableMH 
+ progVarsOffset
); 
5927                         *vars
->NXArgcPtr        
= argc
; 
5928                         *vars
->NXArgvPtr        
= argv
; 
5929                         *vars
->environPtr       
= envp
; 
5930                         *vars
->__prognamePtr 
= (argv
[0] != NULL
) ? basename(argv
[0]) : ""; 
5931                         // set up so libSystem gets ProgramVars struct embedded in main executable 
5932                         libDyldEntry
->setProgramVars(vars
); 
5936         if ( libDyldEntry
->vectorVersion 
> 4 ) 
5937                 libDyldEntry
->setRestrictions(gLinkContext
.allowAtPaths
, gLinkContext
.allowEnvVarsPath
, gLinkContext
.allowClassicFallbackPaths
); 
5938         libDyldEntry
->setHaltFunction(&halt
); 
5939         if ( libDyldEntry
->vectorVersion 
> 5 ) { 
5940                 libDyldEntry
->setNotifyMonitoringDyldMain(¬ifyMonitoringDyldMain
); 
5941                 libDyldEntry
->setNotifyMonitoringDyld(¬ifyMonitoringDyld
); 
5944         if ( libDyldEntry
->vectorVersion 
> 6 ) 
5945                 libDyldEntry
->setHasCacheOverrides(someCacheImageOverridden
); 
5947         if ( libDyldEntry
->vectorVersion 
> 2 ) 
5948                 libDyldEntry
->setChildForkFunction(&_dyld_fork_child
); 
5949 #if !TARGET_OS_SIMULATOR 
5950         if ( libDyldEntry
->vectorVersion 
> 3 ) 
5951                 libDyldEntry
->setLogFunction(&dyld::vlog
); 
5953         libDyldEntry
->setOldAllImageInfo(gProcessInfo
); 
5954         dyld3::LoadedImage
* libSys 
= loader
.findImage(mainClosure
->libSystemImageNum()); 
5955         libDyldEntry
->setInitialImageList(mainClosure
, dyldCache
, sSharedCacheLoadInfo
.path
, allImages
, *libSys
); 
5957         CRSetCrashLogMessage("dyld3: launch, running initializers"); 
5958         libDyldEntry
->runInitialzersBottomUp((mach_header
*)mainExecutableMH
); 
5959         //dyld::log("returned from runInitialzersBottomUp()\n"); 
5961         if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) { 
5962                 dyld3::kdebug_trace_dyld_duration_end(launchTraceID
, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, 0, 0, 3); 
5964 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5965         if ( gLinkContext
.driverKit 
) { 
5966                 *entry 
= (uintptr_t)sEntryOveride
; 
5968                         halt("no entry point registered"); 
5969                 *startGlue 
= (uintptr_t)(libDyldEntry
->startFunc
); 
5974                 dyld3::closure::Image::ResolvedSymbolTarget progEntry
; 
5975                 if ( mainClosure
->mainEntry(progEntry
) ) { 
5976                         // modern app with LC_MAIN 
5977                         // set startGlue to "start" function in libdyld.dylib 
5978                         // set entry to "main" function in program 
5979                         *startGlue 
= (uintptr_t)(libDyldEntry
->startFunc
); 
5980                         *entry     
= loader
.resolveTarget(progEntry
); 
5982                 else if ( mainClosure
->startEntry(progEntry
) ) { 
5983                         // old style app linked with crt1.o 
5984                         // entry is "start" function in program 
5986                         *entry     
= loader
.resolveTarget(progEntry
); 
5992         CRSetCrashLogMessage("dyld3 mode"); 
5997 static const char* getTempDir(const char* envp
[]) 
5999         if (const char* tempDir 
= _simple_getenv(envp
, "TMPDIR")) 
6002 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6003         return "/private/tmp/"; 
6005         return "/private/var/tmp/"; 
6009 static const dyld3::closure::LaunchClosure
* mapClosureFile(const char* closurePath
) 
6011         struct stat statbuf
; 
6012         if ( ::stat(closurePath
, &statbuf
) == -1 ) 
6015         // check for tombstone file 
6016         if ( statbuf
.st_size 
== 0 ) 
6019         int fd 
= ::open(closurePath
, O_RDONLY
); 
6023         const dyld3::closure::LaunchClosure
* closure 
= (dyld3::closure::LaunchClosure
*)::mmap(NULL
, (size_t)statbuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0); 
6026         if ( closure 
== MAP_FAILED 
) 
6032 static bool needsDyld2ErrorMessage(const char* msg
) 
6034         if ( strcmp(msg
, "lazy bind opcodes missing binds") == 0 ) 
6040 // Note: buildLaunchClosure calls halt() if there is an error building the closure 
6041 static const dyld3::closure::LaunchClosure
* buildLaunchClosure(const uint8_t* mainExecutableCDHash
, 
6042                                                                                                                            const dyld3::closure::LoadedFileInfo
& mainFileInfo
, const char* envp
[]) 
6044         const dyld3::MachOLoaded
* mainExecutableMH 
= (const dyld3::MachOLoaded
*)mainFileInfo
.fileContent
; 
6045         dyld3::closure::PathOverrides pathOverrides
; 
6046         pathOverrides
.setFallbackPathHandling(gLinkContext
.allowClassicFallbackPaths 
? dyld3::closure::PathOverrides::FallbackPathMode::classic 
: dyld3::closure::PathOverrides::FallbackPathMode::restricted
); 
6047         pathOverrides
.setEnvVars(envp
, mainExecutableMH
, mainFileInfo
.path
); 
6048         STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray
*,  imagesArrays
, 3); 
6049         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) { 
6050                 imagesArrays
.push_back(sSharedCacheLoadInfo
.loadAddress
->cachedDylibsImageArray()); 
6051                 if ( auto others 
= sSharedCacheLoadInfo
.loadAddress
->otherOSImageArray() ) 
6052                         imagesArrays
.push_back(others
); 
6055         char closurePath
[PATH_MAX
]; 
6056         dyld3::closure::ClosureBuilder::LaunchErrorInfo
* errorInfo 
= (dyld3::closure::ClosureBuilder::LaunchErrorInfo
*)&gProcessInfo
->errorKind
; 
6057         dyld3::closure::FileSystemPhysical fileSystem
; 
6058         const dyld3::GradedArchs
& archs 
= dyld3::GradedArchs::forCurrentOS(mainExecutableMH
); 
6059         dyld3::closure::ClosureBuilder::AtPath atPathHanding 
= (gLinkContext
.allowAtPaths 
? dyld3::closure::ClosureBuilder::AtPath::all 
: dyld3::closure::ClosureBuilder::AtPath::none
); 
6060         dyld3::closure::ClosureBuilder 
builder(dyld3::closure::kFirstLaunchClosureImageNum
, fileSystem
, sSharedCacheLoadInfo
.loadAddress
, true, 
6061                                                                                    archs
, pathOverrides
, atPathHanding
, gLinkContext
.allowEnvVarsPath
, errorInfo
); 
6062         if (sForceInvalidSharedCacheClosureFormat
) 
6063                 builder
.setDyldCacheInvalidFormatVersion(); 
6064         if ( !gLinkContext
.allowInterposing 
) 
6065                 builder
.disableInterposing(); 
6066         const dyld3::closure::LaunchClosure
* result 
= builder
.makeLaunchClosure(mainFileInfo
, gLinkContext
.allowInsertFailures
); 
6067         if ( builder
.diagnostics().hasError() ) { 
6068                 const char* errMsg 
= builder
.diagnostics().errorMessage(); 
6069                 // let apps with this error fallback to dyld2 mode 
6070                 if ( needsDyld2ErrorMessage(errMsg
) ) { 
6071                         if ( dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo
.path
, closurePath
, getTempDir(envp
), true) ) { 
6072                                 // create empty file as a tombstone to not keep trying 
6073                                 int fd 
= ::open(closurePath
, O_WRONLY
|O_CREAT
, S_IRUSR
|S_IWUSR
); 
6075                                         ::fchmod(fd
, S_IRUSR
); 
6077                                         if ( gLinkContext
.verboseWarnings 
) 
6078                                                 dyld::log("dyld: just built tombstone closure for %s\n", sExecPath
); 
6079                                         // We only care about closure failures that do not also cause dyld2 to fail, so defer logging 
6080                                         // until after dyld2 has tried to launch the binary 
6081                                         sLogClosureFailure 
= true; 
6086                 // terminate process 
6090         if ( result 
== nullptr ) 
6093         if ( !closureValid(result
, mainFileInfo
, mainExecutableCDHash
, false, envp
) ) { 
6094                 // some how the freshly generated closure is invalid... 
6095                 result
->deallocate(); 
6096                 if ( gLinkContext
.verboseWarnings 
) 
6097                         dyld::log("dyld: somehow just built closure is invalid\n"); 
6100         // try to atomically save closure to disk to speed up next launch 
6101         if ( dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo
.path
, closurePath
, getTempDir(envp
), true) ) { 
6102                 char closurePathTemp
[PATH_MAX
]; 
6103                 strlcpy(closurePathTemp
, closurePath
, PATH_MAX
); 
6104                 int mypid 
= getpid(); 
6108                 putHexByte(mypid 
>> 24, s
); 
6109                 putHexByte(mypid 
>> 16, s
); 
6110                 putHexByte(mypid 
>> 8, s
); 
6111                 putHexByte(mypid
, s
); 
6113                 strlcat(closurePathTemp
, pidBuf
, PATH_MAX
); 
6114 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6115                 int fd 
= ::open(closurePathTemp
, O_WRONLY
|O_CREAT
, S_IRUSR
|S_IWUSR
); 
6117                 int fd 
= ::open_dprotected_np(closurePathTemp
, O_WRONLY
|O_CREAT
, PROTECTION_CLASS_D
, 0, S_IRUSR
|S_IWUSR
); 
6120                         ::ftruncate(fd
, result
->size()); 
6121                         ::write(fd
, result
, result
->size()); 
6122                         ::fchmod(fd
, S_IRUSR
); 
6124                         ::rename(closurePathTemp
, closurePath
); 
6125                         // free built closure and mmap file() to reduce dirty memory 
6126                         result
->deallocate(); 
6127                         result 
= mapClosureFile(closurePath
); 
6129                 else if ( gLinkContext
.verboseWarnings 
) { 
6130                         dyld::log("could not save closure (errno=%d) to: %s\n", errno
, closurePathTemp
); 
6134         if ( gLinkContext
.verboseWarnings 
) 
6135                 dyld::log("dyld: just built closure %p (size=%lu) for %s\n", result
, result
->size(), sExecPath
); 
6140 static const dyld3::closure::LaunchClosure
* findCachedLaunchClosure(const uint8_t* mainExecutableCDHash
, 
6141                                                                                                                                     const dyld3::closure::LoadedFileInfo
& mainFileInfo
, 
6144         char closurePath
[PATH_MAX
]; 
6145         // build base path of $TMPDIR/dyld/<prog-name>- 
6146         if ( !dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo
.path
, closurePath
, getTempDir(envp
), false) ) 
6148         const dyld3::closure::LaunchClosure
* closure 
= mapClosureFile(closurePath
); 
6149         if ( closure 
== nullptr ) 
6152         if ( !closureValid(closure
, mainFileInfo
, mainExecutableCDHash
, false, envp
) ) { 
6153                 ::munmap((void*)closure
, closure
->size()); 
6157         if ( gLinkContext
.verboseWarnings 
) 
6158                 dyld::log("dyld: used cached closure %p (size=%lu) for %s\n", closure
, closure
->size(), sExecPath
); 
6163 #endif // !TARGET_OS_SIMULATOR 
6166 static ClosureMode 
getPlatformDefaultClosureMode() { 
6167 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6169         // rdar://problem/32701418: Don't use dyld3 for i386 for now. 
6170         return ClosureMode::Off
; 
6172         // x86_64 defaults to using the shared cache closures 
6173         return ClosureMode::PreBuiltOnly
; 
6177         // <rdar://problem/33171968> enable dyld3 mode for all OS programs when using customer dyld cache (no roots) 
6178         if ( (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) && (sSharedCacheLoadInfo
.loadAddress
->header
.cacheType 
== kDyldSharedCacheTypeProduction
) ) 
6179                 return ClosureMode::On
; 
6181                 return ClosureMode::Off
; 
6182 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED 
6186 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which 
6187 // sets up some registers and call this function. 
6189 // Returns address of main() in target program which __dyld_start jumps to 
6192 _main(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
,  
6193                 int argc
, const char* argv
[], const char* envp
[], const char* apple
[],  
6194                 uintptr_t* startGlue
) 
6196         if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) { 
6197                 launchTraceID 
= dyld3::kdebug_trace_dyld_duration_start(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, (uint64_t)mainExecutableMH
, 0, 0); 
6200         //Check and see if there are any kernel flags 
6201         dyld3::BootArgs::setFlags(hexToUInt64(_simple_getenv(apple
, "dyld_flags"), nullptr)); 
6203     // Grab the cdHash of the main executable from the environment 
6204         uint8_t mainExecutableCDHashBuffer
[20]; 
6205         const uint8_t* mainExecutableCDHash 
= nullptr; 
6206         if ( hexToBytes(_simple_getenv(apple
, "executable_cdhash"), 40, mainExecutableCDHashBuffer
) ) 
6207                 mainExecutableCDHash 
= mainExecutableCDHashBuffer
; 
6209 #if !TARGET_OS_SIMULATOR 
6210         // Trace dyld's load 
6211         notifyKernelAboutImage((macho_header
*)&__dso_handle
, _simple_getenv(apple
, "dyld_file")); 
6212         // Trace the main executable's load 
6213         notifyKernelAboutImage(mainExecutableMH
, _simple_getenv(apple
, "executable_file")); 
6216         uintptr_t result 
= 0; 
6217         sMainExecutableMachHeader 
= mainExecutableMH
; 
6218         sMainExecutableSlide 
= mainExecutableSlide
; 
6221         // Set the platform ID in the all image infos so debuggers can tell the process type 
6222         // FIXME: This can all be removed once we make the kernel handle it in rdar://43369446 
6223         if (gProcessInfo
->version 
>= 16) { 
6224                 __block 
bool platformFound 
= false; 
6225                 ((dyld3::MachOFile
*)mainExecutableMH
)->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) { 
6226                         if (platformFound
) { 
6227                                 halt("MH_EXECUTE binaries may only specify one platform"); 
6229                         gProcessInfo
->platform 
= (uint32_t)platform
; 
6230                         platformFound 
= true; 
6232                 if (gProcessInfo
->platform 
== (uint32_t)dyld3::Platform::unknown
) { 
6233                         // There were no platforms found in the binary. This may occur on macOS for alternate toolchains and old binaries. 
6234                         // It should never occur on any of our embedded platforms. 
6235 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6236                         gProcessInfo
->platform 
= (uint32_t)dyld3::Platform::macOS
; 
6238                         halt("MH_EXECUTE binaries must specify a minimum supported OS version"); 
6243 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6244         // Check to see if we need to override the platform 
6245         const char* forcedPlatform 
= _simple_getenv(envp
, "DYLD_FORCE_PLATFORM"); 
6246         if (forcedPlatform
) { 
6247                 if (strncmp(forcedPlatform
, "6", 1) != 0) { 
6248                         halt("DYLD_FORCE_PLATFORM is only supported for platform 6"); 
6250                 const dyld3::MachOFile
* mf 
= (dyld3::MachOFile
*)sMainExecutableMachHeader
; 
6251                 if (mf
->allowsAlternatePlatform()) { 
6252                         gProcessInfo
->platform 
= PLATFORM_IOSMAC
; 
6256         // if this is host dyld, check to see if iOS simulator is being run 
6257         const char* rootPath 
= _simple_getenv(envp
, "DYLD_ROOT_PATH"); 
6258         if ( (rootPath 
!= NULL
) ) { 
6259                 // look to see if simulator has its own dyld 
6260                 char simDyldPath
[PATH_MAX
];  
6261                 strlcpy(simDyldPath
, rootPath
, PATH_MAX
); 
6262                 strlcat(simDyldPath
, "/usr/lib/dyld_sim", PATH_MAX
); 
6263                 int fd 
= my_open(simDyldPath
, O_RDONLY
, 0); 
6265                         const char* errMessage 
= useSimulatorDyld(fd
, mainExecutableMH
, simDyldPath
, argc
, argv
, envp
, apple
, startGlue
, &result
); 
6266                         if ( errMessage 
!= NULL 
) 
6272                 ((dyld3::MachOFile
*)mainExecutableMH
)->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) { 
6273                         if ( dyld3::MachOFile::isSimulatorPlatform(platform
) ) 
6274                                 halt("attempt to run simulator program outside simulator (DYLD_ROOT_PATH not set)"); 
6279         CRSetCrashLogMessage("dyld: launch started"); 
6281         setContext(mainExecutableMH
, argc
, argv
, envp
, apple
); 
6283         // Pickup the pointer to the exec path. 
6284         sExecPath 
= _simple_getenv(apple
, "executable_path"); 
6286         // <rdar://problem/13868260> Remove interim apple[0] transition code from dyld 
6287         if (!sExecPath
) sExecPath 
= apple
[0]; 
6289 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR 
6290         // <rdar://54095622> kernel is not passing a real path for main executable 
6291         if ( strncmp(sExecPath
, "/var/containers/Bundle/Application/", 35) == 0 ) { 
6292                 if ( char* newPath 
= (char*)malloc(strlen(sExecPath
)+10) ) { 
6293                         strcpy(newPath
, "/private"); 
6294                         strcat(newPath
, sExecPath
); 
6295                         sExecPath 
= newPath
; 
6300         if ( sExecPath
[0] != '/' ) { 
6301                 // have relative path, use cwd to make absolute 
6302                 char cwdbuff
[MAXPATHLEN
]; 
6303             if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL 
) { 
6304                         // maybe use static buffer to avoid calling malloc so early... 
6305                         char* s 
= new char[strlen(cwdbuff
) + strlen(sExecPath
) + 2]; 
6308                         strcat(s
, sExecPath
); 
6313         // Remember short name of process for later logging 
6314         sExecShortName 
= ::strrchr(sExecPath
, '/'); 
6315         if ( sExecShortName 
!= NULL 
) 
6318                 sExecShortName 
= sExecPath
; 
6320     configureProcessRestrictions(mainExecutableMH
, envp
); 
6322         // Check if we should force dyld3.  Note we have to do this outside of the regular env parsing due to AMFI 
6323         if ( dyld3::internalInstall() ) { 
6324                 if (const char* useClosures 
= _simple_getenv(envp
, "DYLD_USE_CLOSURES")) { 
6325                         if ( strcmp(useClosures
, "0") == 0 ) { 
6326                                 sClosureMode 
= ClosureMode::Off
; 
6327                         } else if ( strcmp(useClosures
, "1") == 0 ) { 
6328 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6331                                 // don't support dyld3 for 32-bit macOS 
6333                                 // Also don't support dyld3 for iOSMac right now 
6334                                 if ( gProcessInfo
->platform 
!= PLATFORM_IOSMAC 
) { 
6335                                         sClosureMode 
= ClosureMode::On
; 
6340                                 sClosureMode 
= ClosureMode::On
; 
6341 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED 
6343                                 dyld::warn("unknown option to DYLD_USE_CLOSURES.  Valid options are: 0 and 1\n"); 
6349 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6350     if ( !gLinkContext
.allowEnvVarsPrint 
&& !gLinkContext
.allowEnvVarsPath 
&& !gLinkContext
.allowEnvVarsSharedCache 
) { 
6351                 pruneEnvironmentVariables(envp
, &apple
); 
6352                 // set again because envp and apple may have changed or moved 
6353                 setContext(mainExecutableMH
, argc
, argv
, envp
, apple
); 
6358                 checkEnvironmentVariables(envp
); 
6359                 defaultUninitializedFallbackPaths(envp
); 
6361 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6362         if ( gProcessInfo
->platform 
== PLATFORM_IOSMAC 
) { 
6363                 gLinkContext
.rootPaths 
= parseColonList("/System/iOSSupport", NULL
); 
6364                 gLinkContext
.iOSonMac 
= true; 
6365                 if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
== sLibraryFallbackPaths 
) 
6366                         sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= sRestrictedLibraryFallbackPaths
; 
6367                 if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
== sFrameworkFallbackPaths 
) 
6368                         sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= sRestrictedFrameworkFallbackPaths
; 
6370         else if ( ((dyld3::MachOFile
*)mainExecutableMH
)->supportsPlatform(dyld3::Platform::driverKit
) ) { 
6371                 gLinkContext
.driverKit 
= true; 
6372                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
6375         if ( sEnv
.DYLD_PRINT_OPTS 
) 
6377         if ( sEnv
.DYLD_PRINT_ENV 
)  
6378                 printEnvironmentVariables(envp
); 
6380         // Parse this envirionment variable outside of the regular logic as we want to accept 
6381         // this on binaries without an entitelment 
6382 #if !TARGET_OS_SIMULATOR 
6383         if ( _simple_getenv(envp
, "DYLD_JUST_BUILD_CLOSURE") != nullptr ) { 
6384 #if TARGET_OS_IPHONE 
6385                 const char* tempDir 
= getTempDir(envp
); 
6386                 if ( (tempDir 
!= nullptr) && (geteuid() != 0) ) { 
6387                         // Use realpath to prevent something like TMPRIR=/tmp/../usr/bin 
6388                         char realPath
[PATH_MAX
]; 
6389                         if ( realpath(tempDir
, realPath
) != NULL 
) 
6391                         if (strncmp(tempDir
, "/private/var/mobile/Containers/", strlen("/private/var/mobile/Containers/")) == 0) { 
6392                                 sJustBuildClosure 
= true; 
6396                 // If we didn't like the format of TMPDIR, just exit.  We don't want to launch the app as that would bring up the UI 
6397                 if (!sJustBuildClosure
) { 
6398                         _exit(EXIT_SUCCESS
); 
6403         if ( sJustBuildClosure 
) 
6404                 sClosureMode 
= ClosureMode::On
; 
6405         getHostInfo(mainExecutableMH
, mainExecutableSlide
); 
6407         // load shared cache 
6408         checkSharedRegionDisable((dyld3::MachOLoaded
*)mainExecutableMH
, mainExecutableSlide
); 
6409         if ( gLinkContext
.sharedRegionMode 
!= ImageLoader::kDontUseSharedRegion 
) { 
6410 #if TARGET_OS_SIMULATOR 
6411                 if ( sSharedCacheOverrideDir
) 
6418         // If we haven't got a closure mode yet, then check the environment and cache type 
6419         if ( sClosureMode 
== ClosureMode::Unset 
) { 
6420                 // First test to see if we forced in dyld2 via a kernel boot-arg 
6421                 if ( dyld3::BootArgs::forceDyld2() ) { 
6422                         sClosureMode 
= ClosureMode::Off
; 
6423                 } else if ( inDenyList(sExecPath
) ) { 
6424                         sClosureMode 
= ClosureMode::Off
; 
6425                 } else if ( sEnv
.hasOverride 
) { 
6426                         sClosureMode 
= ClosureMode::Off
; 
6427                 } else if ( dyld3::BootArgs::forceDyld3() ) { 
6428                         sClosureMode 
= ClosureMode::On
; 
6430                         sClosureMode 
= getPlatformDefaultClosureMode(); 
6434 #if !TARGET_OS_SIMULATOR 
6435         if ( sClosureMode 
== ClosureMode::Off 
) { 
6436                 if ( gLinkContext
.verboseWarnings 
) 
6437                         dyld::log("dyld: not using closure because of DYLD_USE_CLOSURES or -force_dyld2=1 override\n"); 
6439                 const dyld3::closure::LaunchClosure
* mainClosure 
= nullptr; 
6440                 dyld3::closure::LoadedFileInfo mainFileInfo
; 
6441                 mainFileInfo
.fileContent 
= mainExecutableMH
; 
6442                 mainFileInfo
.path 
= sExecPath
; 
6443                 // FIXME: If we are saving this closure, this slice offset/length is probably wrong in the case of FAT files. 
6444                 mainFileInfo
.sliceOffset 
= 0; 
6445                 mainFileInfo
.sliceLen 
= -1; 
6446                 struct stat mainExeStatBuf
; 
6447                 if ( ::stat(sExecPath
, &mainExeStatBuf
) == 0 ) { 
6448                         mainFileInfo
.inode 
= mainExeStatBuf
.st_ino
; 
6449                         mainFileInfo
.mtime 
= mainExeStatBuf
.st_mtime
; 
6451                 // check for closure in cache first 
6452                 if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) { 
6453                         mainClosure 
= sSharedCacheLoadInfo
.loadAddress
->findClosure(sExecPath
); 
6454                         if ( gLinkContext
.verboseWarnings 
&& (mainClosure 
!= nullptr) ) 
6455                                 dyld::log("dyld: found closure %p (size=%lu) in dyld shared cache\n", mainClosure
, mainClosure
->size()); 
6458                 // We only want to try build a closure at runtime if its an iOS third party binary, or a macOS binary from the shared cache 
6459                 bool allowClosureRebuilds 
= false; 
6460                 if ( sClosureMode 
== ClosureMode::On 
) { 
6461                         allowClosureRebuilds 
= true; 
6462                 } else if ( (sClosureMode 
== ClosureMode::PreBuiltOnly
) && (mainClosure 
!= nullptr) ) { 
6463                         allowClosureRebuilds 
= true; 
6466                 if ( (mainClosure 
!= nullptr) && !closureValid(mainClosure
, mainFileInfo
, mainExecutableCDHash
, true, envp
) ) 
6467                         mainClosure 
= nullptr; 
6469                 // If we didn't find a valid cache closure then try build a new one 
6470                 if ( (mainClosure 
== nullptr) && allowClosureRebuilds 
) { 
6471                         // if forcing closures, and no closure in cache, or it is invalid, check for cached closure 
6472                         if ( !sForceInvalidSharedCacheClosureFormat 
) 
6473                                 mainClosure 
= findCachedLaunchClosure(mainExecutableCDHash
, mainFileInfo
, envp
); 
6474                         if ( mainClosure 
== nullptr ) { 
6475                                 // if  no cached closure found, build new one 
6476                                 mainClosure 
= buildLaunchClosure(mainExecutableCDHash
, mainFileInfo
, envp
); 
6480                 // exit dyld after closure is built, without running program 
6481                 if ( sJustBuildClosure 
) 
6482                         _exit(EXIT_SUCCESS
); 
6484                 // try using launch closure 
6485                 if ( mainClosure 
!= nullptr ) { 
6486                         CRSetCrashLogMessage("dyld3: launch started"); 
6487                         bool launched 
= launchWithClosure(mainClosure
, sSharedCacheLoadInfo
.loadAddress
, (dyld3::MachOLoaded
*)mainExecutableMH
, 
6488                                                                                           mainExecutableSlide
, argc
, argv
, envp
, apple
, &result
, startGlue
); 
6489                         if ( !launched 
&& allowClosureRebuilds 
) { 
6490                                 // closure is out of date, build new one 
6491                                 mainClosure 
= buildLaunchClosure(mainExecutableCDHash
, mainFileInfo
, envp
); 
6492                                 if ( mainClosure 
!= nullptr ) { 
6493                                         launched 
= launchWithClosure(mainClosure
, sSharedCacheLoadInfo
.loadAddress
, (dyld3::MachOLoaded
*)mainExecutableMH
, 
6494                                                                                                  mainExecutableSlide
, argc
, argv
, envp
, apple
, &result
, startGlue
); 
6498                                 gLinkContext
.startedInitializingMainExecutable 
= true; 
6499 #if __has_feature(ptrauth_calls) 
6500                                 // start() calls the result pointer as a function pointer so we need to sign it. 
6501                                 result 
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result
, 0, 0); 
6504                                         result 
= (uintptr_t)&fake_main
; 
6508                                 if ( gLinkContext
.verboseWarnings 
) { 
6509                                         dyld::log("dyld: unable to use closure %p\n", mainClosure
); 
6514 #endif // TARGET_OS_SIMULATOR 
6515         // could not use closure info, launch old way 
6519         // install gdb notifier 
6520         stateToHandlers(dyld_image_state_dependents_mapped
, sBatchHandlers
)->push_back(notifyGDB
); 
6521         stateToHandlers(dyld_image_state_mapped
, sSingleHandlers
)->push_back(updateAllImages
); 
6522         // make initial allocations large enough that it is unlikely to need to be re-alloced 
6523         sImageRoots
.reserve(16); 
6524         sAddImageCallbacks
.reserve(4); 
6525         sRemoveImageCallbacks
.reserve(4); 
6526         sAddLoadImageCallbacks
.reserve(4); 
6527         sImageFilesNeedingTermination
.reserve(16); 
6528         sImageFilesNeedingDOFUnregistration
.reserve(8); 
6530 #if !TARGET_OS_SIMULATOR 
6531 #ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE 
6532         // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process 
6533         WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo
->systemOrderFlag
); 
6539                 // add dyld itself to UUID list 
6540                 addDyldImageToUUIDList(); 
6542 #if SUPPORT_ACCELERATE_TABLES 
6544                 // Disable accelerator tables when we have threaded rebase/bind, which is arm64e executables only for now. 
6545                 if (sMainExecutableMachHeader
->cpusubtype 
== CPU_SUBTYPE_ARM64E
) 
6546                         sDisableAcceleratorTables 
= true; 
6548                 bool mainExcutableAlreadyRebased 
= false; 
6549                 if ( (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) && !dylibsCanOverrideCache() && !sDisableAcceleratorTables 
&& (sSharedCacheLoadInfo
.loadAddress
->header
.accelerateInfoAddr 
!= 0) ) { 
6550                         struct stat statBuf
; 
6551                         if ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR 
"no-dyld2-accelerator-tables", &statBuf
) != 0 ) 
6552                                 sAllCacheImagesProxy 
= ImageLoaderMegaDylib::makeImageLoaderMegaDylib(&sSharedCacheLoadInfo
.loadAddress
->header
, sSharedCacheLoadInfo
.slide
, mainExecutableMH
, gLinkContext
); 
6559         #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6560                 gLinkContext
.strictMachORequired 
= false; 
6561         // <rdar://problem/22805519> be less strict about old macOS mach-o binaries 
6562         ((dyld3::MachOFile
*)mainExecutableMH
)->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) { 
6563             if ( (platform 
== dyld3::Platform::macOS
) && (sdk 
>= DYLD_PACKED_VERSION(10,15,0)) ) { 
6564                 gLinkContext
.strictMachORequired 
= true; 
6567             if ( gLinkContext
.iOSonMac 
) 
6568                     gLinkContext
.strictMachORequired 
= true; 
6570                 // simulators, iOS, tvOS, watchOS, are always strict 
6571                 gLinkContext
.strictMachORequired 
= true; 
6575                 CRSetCrashLogMessage(sLoadingCrashMessage
); 
6576                 // instantiate ImageLoader for main executable 
6577                 sMainExecutable 
= instantiateFromLoadedImage(mainExecutableMH
, mainExecutableSlide
, sExecPath
); 
6578                 gLinkContext
.mainExecutable 
= sMainExecutable
; 
6579                 gLinkContext
.mainExecutableCodeSigned 
= hasCodeSignatureLoadCommand(mainExecutableMH
); 
6581 #if TARGET_OS_SIMULATOR 
6582                 // check main executable is not too new for this OS 
6584                         if ( ! isSimulatorBinary((uint8_t*)mainExecutableMH
, sExecPath
) ) { 
6585                                 throwf("program was built for a platform that is not supported by this runtime"); 
6587                         uint32_t mainMinOS 
= sMainExecutable
->minOSVersion(); 
6589                         // dyld is always built for the current OS, so we can get the current OS version 
6590                         // from the load command in dyld itself. 
6591                         uint32_t dyldMinOS 
= ImageLoaderMachO::minOSVersion((const mach_header
*)&__dso_handle
); 
6592                         if ( mainMinOS 
> dyldMinOS 
) { 
6594                                 throwf("app was built for watchOS %d.%d which is newer than this simulator %d.%d", 
6595                                                 mainMinOS 
>> 16, ((mainMinOS 
>> 8) & 0xFF), 
6596                                                 dyldMinOS 
>> 16, ((dyldMinOS 
>> 8) & 0xFF)); 
6598                                 throwf("app was built for tvOS %d.%d which is newer than this simulator %d.%d", 
6599                                                 mainMinOS 
>> 16, ((mainMinOS 
>> 8) & 0xFF), 
6600                                                 dyldMinOS 
>> 16, ((dyldMinOS 
>> 8) & 0xFF)); 
6602                                 throwf("app was built for iOS %d.%d which is newer than this simulator %d.%d", 
6603                                                 mainMinOS 
>> 16, ((mainMinOS 
>> 8) & 0xFF), 
6604                                                 dyldMinOS 
>> 16, ((dyldMinOS 
>> 8) & 0xFF)); 
6611         #if SUPPORT_ACCELERATE_TABLES 
6612                 sAllImages
.reserve((sAllCacheImagesProxy 
!= NULL
) ? 16 : INITIAL_IMAGE_COUNT
); 
6614                 sAllImages
.reserve(INITIAL_IMAGE_COUNT
); 
6617                 // Now that shared cache is loaded, setup an versioned dylib overrides 
6618         #if SUPPORT_VERSIONED_PATHS 
6619                 checkVersionedPaths(); 
6623                 // dyld_all_image_infos image list does not contain dyld 
6624                 // add it as dyldPath field in dyld_all_image_infos 
6625                 // for simulator, dyld_sim is in image list, need host dyld added 
6626 #if TARGET_OS_SIMULATOR 
6627                 // get path of host dyld from table of syscall vectors in host dyld 
6628                 void* addressInDyld 
= gSyscallHelpers
; 
6630                 // get path of dyld itself 
6631                 void*  addressInDyld 
= (void*)&__dso_handle
; 
6633                 char dyldPathBuffer
[MAXPATHLEN
+1]; 
6634                 int len 
= proc_regionfilename(getpid(), (uint64_t)(long)addressInDyld
, dyldPathBuffer
, MAXPATHLEN
); 
6636                         dyldPathBuffer
[len
] = '\0'; // proc_regionfilename() does not zero terminate returned string 
6637                         if ( strcmp(dyldPathBuffer
, gProcessInfo
->dyldPath
) != 0 ) 
6638                                 gProcessInfo
->dyldPath 
= strdup(dyldPathBuffer
); 
6641                 // load any inserted libraries 
6642                 if      ( sEnv
.DYLD_INSERT_LIBRARIES 
!= NULL 
) { 
6643                         for (const char* const* lib 
= sEnv
.DYLD_INSERT_LIBRARIES
; *lib 
!= NULL
; ++lib
)  
6644                                 loadInsertedDylib(*lib
); 
6646                 // record count of inserted libraries so that a flat search will look at  
6647                 // inserted libraries, then main, then others. 
6648                 sInsertedDylibCount 
= sAllImages
.size()-1; 
6650                 // link main executable 
6651                 gLinkContext
.linkingMainExecutable 
= true; 
6652 #if SUPPORT_ACCELERATE_TABLES 
6653                 if ( mainExcutableAlreadyRebased 
) { 
6654                         // previous link() on main executable has already adjusted its internal pointers for ASLR 
6655                         // work around that by rebasing by inverse amount 
6656                         sMainExecutable
->rebase(gLinkContext
, -mainExecutableSlide
); 
6659                 link(sMainExecutable
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, ImageLoader::RPathChain(NULL
, NULL
), -1); 
6660                 sMainExecutable
->setNeverUnloadRecursive(); 
6661                 if ( sMainExecutable
->forceFlat() ) { 
6662                         gLinkContext
.bindFlat 
= true; 
6663                         gLinkContext
.prebindUsage 
= ImageLoader::kUseNoPrebinding
; 
6666                 // link any inserted libraries 
6667                 // do this after linking main executable so that any dylibs pulled in by inserted  
6668                 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses 
6669                 if ( sInsertedDylibCount 
> 0 ) { 
6670                         for(unsigned int i
=0; i 
< sInsertedDylibCount
; ++i
) { 
6671                                 ImageLoader
* image 
= sAllImages
[i
+1]; 
6672                                 link(image
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, ImageLoader::RPathChain(NULL
, NULL
), -1); 
6673                                 image
->setNeverUnloadRecursive(); 
6675                         if ( gLinkContext
.allowInterposing 
) { 
6676                                 // only INSERTED libraries can interpose 
6677                                 // register interposing info after all inserted libraries are bound so chaining works 
6678                                 for(unsigned int i
=0; i 
< sInsertedDylibCount
; ++i
) { 
6679                                         ImageLoader
* image 
= sAllImages
[i
+1]; 
6680                                         image
->registerInterposing(gLinkContext
); 
6685                 if ( gLinkContext
.allowInterposing 
) { 
6686                         // <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES 
6687                         for (long i
=sInsertedDylibCount
+1; i 
< sAllImages
.size(); ++i
) { 
6688                                 ImageLoader
* image 
= sAllImages
[i
]; 
6689                                 if ( image
->inSharedCache() ) 
6691                                 image
->registerInterposing(gLinkContext
); 
6694         #if SUPPORT_ACCELERATE_TABLES 
6695                 if ( (sAllCacheImagesProxy 
!= NULL
) && ImageLoader::haveInterposingTuples() ) { 
6696                         // Accelerator tables cannot be used with implicit interposing, so relaunch with accelerator tables disabled 
6697                         ImageLoader::clearInterposingTuples(); 
6698                         // unmap all loaded dylibs (but not main executable) 
6699                         for (long i
=1; i 
< sAllImages
.size(); ++i
) { 
6700                                 ImageLoader
* image 
= sAllImages
[i
]; 
6701                                 if ( image 
== sMainExecutable 
) 
6703                                 if ( image 
== sAllCacheImagesProxy 
) 
6705                                 image
->setCanUnload(); 
6706                                 ImageLoader::deleteImage(image
); 
6708                         // note: we don't need to worry about inserted images because if DYLD_INSERT_LIBRARIES was set we would not be using the accelerator table 
6710                         sImageRoots
.clear(); 
6711                         sImageFilesNeedingTermination
.clear(); 
6712                         sImageFilesNeedingDOFUnregistration
.clear(); 
6713                         sAddImageCallbacks
.clear(); 
6714                         sRemoveImageCallbacks
.clear(); 
6715                         sAddLoadImageCallbacks
.clear(); 
6716                         sAddBulkLoadImageCallbacks
.clear(); 
6717                         sDisableAcceleratorTables 
= true; 
6718                         sAllCacheImagesProxy 
= NULL
; 
6719                         sMappedRangesStart 
= NULL
; 
6720                         mainExcutableAlreadyRebased 
= true; 
6721                         gLinkContext
.linkingMainExecutable 
= false; 
6723                         goto reloadAllImages
; 
6727                 // apply interposing to initial set of images 
6728                 for(int i
=0; i 
< sImageRoots
.size(); ++i
) { 
6729                         sImageRoots
[i
]->applyInterposing(gLinkContext
); 
6731                 ImageLoader::applyInterposingToDyldCache(gLinkContext
); 
6733                 // Bind and notify for the main executable now that interposing has been registered 
6734                 uint64_t bindMainExecutableStartTime 
= mach_absolute_time(); 
6735                 sMainExecutable
->recursiveBindWithAccounting(gLinkContext
, sEnv
.DYLD_BIND_AT_LAUNCH
, true); 
6736                 uint64_t bindMainExecutableEndTime 
= mach_absolute_time(); 
6737                 ImageLoaderMachO::fgTotalBindTime 
+= bindMainExecutableEndTime 
- bindMainExecutableStartTime
; 
6738                 gLinkContext
.notifyBatch(dyld_image_state_bound
, false); 
6740                 // Bind and notify for the inserted images now interposing has been registered 
6741                 if ( sInsertedDylibCount 
> 0 ) { 
6742                         for(unsigned int i
=0; i 
< sInsertedDylibCount
; ++i
) { 
6743                                 ImageLoader
* image 
= sAllImages
[i
+1]; 
6744                                 image
->recursiveBind(gLinkContext
, sEnv
.DYLD_BIND_AT_LAUNCH
, true); 
6748                 // <rdar://problem/12186933> do weak binding only after all inserted images linked 
6749                 sMainExecutable
->weakBind(gLinkContext
); 
6750                 gLinkContext
.linkingMainExecutable 
= false; 
6752                 sMainExecutable
->recursiveMakeDataReadOnly(gLinkContext
); 
6754                 CRSetCrashLogMessage("dyld: launch, running initializers"); 
6755         #if SUPPORT_OLD_CRT_INITIALIZATION 
6756                 // Old way is to run initializers via a callback from crt1.o 
6757                 if ( ! gRunInitializersOldWay 
)  
6758                         initializeMainExecutable();  
6760                 // run all initializers 
6761                 initializeMainExecutable();  
6764                 // notify any montoring proccesses that this process is about to enter main() 
6765                 notifyMonitoringDyldMain(); 
6766                 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) { 
6767                         dyld3::kdebug_trace_dyld_duration_end(launchTraceID
, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, 0, 0, 2); 
6769                 ARIADNEDBG_CODE(220, 1); 
6771 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
6772                 if ( gLinkContext
.driverKit 
) { 
6773                         result 
= (uintptr_t)sEntryOveride
; 
6775                                 halt("no entry point registered"); 
6776                         *startGlue 
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
; 
6781                         // find entry point for main executable 
6782                         result 
= (uintptr_t)sMainExecutable
->getEntryFromLC_MAIN(); 
6783                         if ( result 
!= 0 ) { 
6784                                 // main executable uses LC_MAIN, we need to use helper in libdyld to call into main() 
6785                                 if ( (gLibSystemHelpers 
!= NULL
) && (gLibSystemHelpers
->version 
>= 9) ) 
6786                                         *startGlue 
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
; 
6788                                         halt("libdyld.dylib support not present for LC_MAIN"); 
6791                                 // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main() 
6792                                 result 
= (uintptr_t)sMainExecutable
->getEntryFromLC_UNIXTHREAD(); 
6796 #if __has_feature(ptrauth_calls) 
6797                 // start() calls the result pointer as a function pointer so we need to sign it. 
6798                 result 
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result
, 0, 0); 
6801         catch(const char* message
) { 
6806                 dyld::log("dyld: launch failed\n"); 
6809         CRSetCrashLogMessage("dyld2 mode"); 
6810 #if !TARGET_OS_SIMULATOR 
6811         if (sLogClosureFailure
) { 
6812                 // We failed to launch in dyld3, but dyld2 can handle it. synthesize a crash report for analytics 
6813                 dyld3::syntheticBacktrace("Could not generate launchClosure, falling back to dyld2", true); 
6818                 notifyMonitoringDyldMain(); 
6819                 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) { 
6820                         dyld3::kdebug_trace_dyld_duration_end(launchTraceID
, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, 0, 0, 2); 
6822                 ARIADNEDBG_CODE(220, 1); 
6823                 result 
= (uintptr_t)&fake_main
; 
6824                 *startGlue 
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
;