1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2007 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@ 
  30 #include <sys/param.h> 
  31 #include <mach/mach_time.h> // mach_absolute_time() 
  32 #include <sys/types.h> 
  34 #include <mach-o/fat.h>  
  35 #include <mach-o/loader.h>  
  36 #include <mach-o/ldsyms.h>  
  37 #include <libkern/OSByteOrder.h>  
  38 #include <mach/mach.h> 
  39 #include <sys/sysctl.h> 
  41 #include <sys/dtrace.h> 
  46 #include "mach-o/dyld_gdb.h" 
  49 #include "ImageLoader.h" 
  50 #include "ImageLoaderMachO.h" 
  51 #include "dyldLibSystemInterface.h" 
  52 #include "dyld_cache_format.h" 
  54 // from _simple.h in libc 
  55 typedef struct _SIMPLE
*         _SIMPLE_STRING
; 
  56 extern "C" void                         _simple_vdprintf(int __fd
, const char *__fmt
, va_list __ap
); 
  57 extern "C" void                         _simple_dprintf(int __fd
, const char *__fmt
, ...); 
  58 extern "C" _SIMPLE_STRING       
_simple_salloc(void); 
  59 extern "C" int                          _simple_vsprintf(_SIMPLE_STRING __b
, const char *__fmt
, va_list __ap
); 
  60 extern "C" void                         _simple_sfree(_SIMPLE_STRING __b
); 
  61 extern "C" char *                       _simple_string(_SIMPLE_STRING __b
); 
  65 // 32-bit ppc is only architecture that uses cpu-sub-types 
  66 #define CPU_SUBTYPES_SUPPORTED __ppc__  
  69 #define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__ 
  72 #define CPU_TYPE_MASK 0x00FFFFFF        /* complement of CPU_ARCH_MASK */ 
  75 /* implemented in dyld_gdb.cpp */ 
  76 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]); 
  77 extern void removeImageFromAllImages(const mach_header
* mh
); 
  78 #if OLD_GDB_DYLD_INTERFACE 
  79 extern void addImageForgdb(const mach_header
* mh
, uintptr_t slide
, const char* physicalPath
, const char* logicalPath
); 
  80 extern void removeImageForgdb(const struct mach_header
* mh
); 
  83 // magic so CrashReporter logs message 
  85         char error_string
[1024]; 
  87 // implemented in dyldStartup.s for CrashReporter 
  88 extern "C" void dyld_fatal_error(const char* errString
) __attribute__((noreturn
)); 
  93 // The file contains the core of dyld used to get a process to main().   
  94 // The API's that dyld supports are implemented in dyldAPIs.cpp. 
 106 // state of all environment variables dyld uses 
 108 struct EnvironmentVariables 
{ 
 109         const char* const *                     DYLD_FRAMEWORK_PATH
; 
 110         const char* const *                     DYLD_FALLBACK_FRAMEWORK_PATH
; 
 111         const char* const *                     DYLD_LIBRARY_PATH
; 
 112         const char* const *                     DYLD_FALLBACK_LIBRARY_PATH
; 
 113         const char*     const *                 DYLD_ROOT_PATH
; 
 114         const char* const *                     DYLD_INSERT_LIBRARIES
; 
 115         const char* const *                     LD_LIBRARY_PATH
;                        // for unix conformance 
 116         bool                                            DYLD_PRINT_LIBRARIES
; 
 117         bool                                            DYLD_PRINT_LIBRARIES_POST_LAUNCH
; 
 118         bool                                            DYLD_BIND_AT_LAUNCH
; 
 119         bool                                            DYLD_PRINT_STATISTICS
; 
 120         bool                                            DYLD_PRINT_OPTS
; 
 122         bool                                            DYLD_DISABLE_DOFS
; 
 123                                                         //      DYLD_IMAGE_SUFFIX                               ==> gLinkContext.imageSuffix 
 124                                                         //      DYLD_PRINT_OPTS                                 ==> gLinkContext.verboseOpts 
 125                                                         //      DYLD_PRINT_ENV                                  ==> gLinkContext.verboseEnv 
 126                                                         //      DYLD_FORCE_FLAT_NAMESPACE               ==> gLinkContext.bindFlat 
 127                                                         //      DYLD_PRINT_INITIALIZERS                 ==> gLinkContext.verboseInit 
 128                                                         //      DYLD_PRINT_SEGMENTS                             ==> gLinkContext.verboseMapping 
 129                                                         //      DYLD_PRINT_BINDINGS                             ==> gLinkContext.verboseBind 
 130                                                         //      DYLD_PRINT_REBASINGS                    ==> gLinkContext.verboseRebase 
 131                                                         //      DYLD_PRINT_DOFS                                 ==> gLinkContext.verboseDOF 
 132                                                         //      DYLD_PRINT_APIS                                 ==> gLogAPIs 
 133                                                         //      DYLD_IGNORE_PREBINDING                  ==> gLinkContext.prebindUsage 
 134                                                         //      DYLD_PREBIND_DEBUG                              ==> gLinkContext.verbosePrebinding 
 135                                                         //      DYLD_NEW_LOCAL_SHARED_REGIONS   ==> gLinkContext.sharedRegionMode 
 136                                                         //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode 
 137                                                         //      DYLD_PRINT_WARNINGS                             ==> gLinkContext.verboseWarnings 
 140 typedef std::vector
<dyld_image_state_change_handler
> StateHandlers
; 
 141 struct RegisteredDOF 
{ const mach_header
* mh
; int registrationID
; }; 
 144 static const char*                                      sExecPath 
= NULL
; 
 145 static const struct mach_header
*        sMainExecutableMachHeader 
= NULL
; 
 146 static cpu_type_t                                       sHostCPU
; 
 147 static cpu_subtype_t                            sHostCPUsubtype
; 
 148 static ImageLoader
*                                     sMainExecutable 
= NULL
; 
 149 static bool                                                     sMainExecutableIsSetuid 
= false; 
 150 static unsigned int                                     sInsertedDylibCount 
= 0; 
 151 static std::vector
<ImageLoader
*>        sAllImages
; 
 152 static std::vector
<ImageLoader
*>        sImageRoots
; 
 153 static std::vector
<ImageLoader
*>        sImageFilesNeedingTermination
; 
 154 static std::vector
<RegisteredDOF
>       sImageFilesNeedingDOFUnregistration
; 
 155 #if IMAGE_NOTIFY_SUPPORT 
 156 static std::vector
<ImageLoader
*>        sImagesToNotifyAboutOtherImages
; 
 158 static std::vector
<ImageCallback
>   sAddImageCallbacks
; 
 159 static std::vector
<ImageCallback
>   sRemoveImageCallbacks
; 
 160 static StateHandlers                            sSingleHandlers
[7]; 
 161 static StateHandlers                            sBatchHandlers
[7]; 
 162 static ImageLoader
*                                     sLastImageByAddressCache
; 
 163 static EnvironmentVariables                     sEnv
; 
 164 static const char*                                      sFrameworkFallbackPaths
[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL 
}; 
 165 static const char*                                      sLibraryFallbackPaths
[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL 
}; 
 166 static BundleNotificationCallBack   sBundleNotifier 
= NULL
; 
 167 static BundleLocatorCallBack            sBundleLocation 
= NULL
; 
 168 static UndefinedHandler                         sUndefinedHandler 
= NULL
; 
 169 static ImageLoader
*                                     sBundleBeingLoaded 
= NULL
;      // hack until OFI is reworked 
 170 #if DYLD_SHARED_CACHE_SUPPORT 
 171 static const dyld_cache_header
*         sSharedCache 
= NULL
; 
 172 bool                                                            gSharedCacheNotFound 
= false; 
 173 bool                                                            gSharedCacheNeedsUpdating 
= false; 
 174 bool                                                            gSharedCacheDontNotify 
= false; 
 176 ImageLoader::LinkContext                        gLinkContext
; 
 177 bool                                                            gLogAPIs 
= false; 
 178 const struct LibSystemHelpers
*          gLibSystemHelpers 
= NULL
; 
 179 #if SUPPORT_OLD_CRT_INITIALIZATION 
 180 bool                                                            gRunInitializersOldWay 
= false; 
 183 static uint32_t                                         sImportSegmentsStart 
= 0; 
 184 static uint32_t                                         sImportSegmentsSize 
= 0; 
 189 const char* mkstringf(const char* format
, ...) 
 192         va_start(list
, format
); 
 193         _SIMPLE_STRING buf 
= _simple_salloc(); 
 194         _simple_vsprintf(buf
, format
, list
); 
 196         const char*     t 
= strdup(_simple_string(buf
)); 
 202 void throwf(const char* format
, ...)  
 205         va_start(list
, format
); 
 206         _SIMPLE_STRING buf 
= _simple_salloc(); 
 207         _simple_vsprintf(buf
, format
, list
); 
 209         const char*     t 
= strdup(_simple_string(buf
)); 
 214 void log(const char* format
, ...)  
 217         va_start(list
, format
); 
 218         _simple_vdprintf(STDERR_FILENO
, format
, list
); 
 222 void warn(const char* format
, ...)  
 224         _simple_dprintf(STDERR_FILENO
, "dyld: warning, "); 
 226         va_start(list
, format
); 
 227         _simple_vdprintf(STDERR_FILENO
, format
, list
); 
 232 // utility class to assure files are closed when an exception is thrown 
 235         FileOpener(const char* path
); 
 237         int getFileDescriptor() { return fd
; } 
 242 FileOpener::FileOpener(const char* path
) 
 245         fd 
= open(path
, O_RDONLY
, 0); 
 248 FileOpener::~FileOpener() 
 255 // forward declaration 
 256 #if __ppc__ || __i386__ 
 261 static void     registerDOFs(const std::vector
<ImageLoader::DOFInfo
>& dofs
) 
 264         // can't dtrace a program running emulated under rosetta rdar://problem/5179640 
 268         const unsigned int dofSectionCount 
= dofs
.size(); 
 269         if ( !sEnv
.DYLD_DISABLE_DOFS 
&& (dofSectionCount 
!= 0) ) { 
 270                 int fd 
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
); 
 272                         //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n"); 
 275                         // allocate a buffer on the stack for the variable length dof_ioctl_data_t type 
 276                         uint8_t buffer
[sizeof(dof_ioctl_data_t
) + dofSectionCount
*sizeof(dof_helper_t
)]; 
 277                         dof_ioctl_data_t
* ioctlData 
= (dof_ioctl_data_t
*)buffer
; 
 279                         // fill in buffer with one dof_helper_t per DOF section 
 280                         ioctlData
->dofiod_count 
= dofSectionCount
; 
 281                         for (unsigned int i
=0; i 
< dofSectionCount
; ++i
) { 
 282                                 strlcpy(ioctlData
->dofiod_helpers
[i
].dofhp_mod
, dofs
[i
].imageShortName
, DTRACE_MODNAMELEN
); 
 283                                 ioctlData
->dofiod_helpers
[i
].dofhp_dof 
= (uintptr_t)(dofs
[i
].dof
); 
 284                                 ioctlData
->dofiod_helpers
[i
].dofhp_addr 
= (uintptr_t)(dofs
[i
].dof
); 
 287                         // tell kernel about all DOF sections en mas 
 288                         // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel 
 289                         user_addr_t val 
= (user_addr_t
)(unsigned long)ioctlData
; 
 290                         if ( ioctl(fd
, DTRACEHIOC_ADDDOF
, &val
) != -1 ) { 
 291                                 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field. 
 292                                 for (unsigned int i
=0; i 
< dofSectionCount
; ++i
) { 
 294                                         info
.mh 
= dofs
[i
].imageHeader
; 
 295                                         info
.registrationID 
= (int)(ioctlData
->dofiod_helpers
[i
].dofhp_dof
); 
 296                                         sImageFilesNeedingDOFUnregistration
.push_back(info
); 
 297                                         if ( gLinkContext
.verboseDOF 
) { 
 298                                                 dyld::log("dyld: registering DOF section 0x%p in %s with dtrace, ID=0x%08X\n",  
 299                                                         dofs
[i
].dof
, dofs
[i
].imageShortName
, info
.registrationID
); 
 304                                 dyld::log( "dyld: ioctl to register dtrace DOF section failed\n"); 
 311 static void     unregisterDOF(int registrationID
) 
 313         int fd 
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
); 
 315                 dyld::warn("can't open /dev/" DTRACEMNR_HELPER 
" to unregister dtrace DOF section\n"); 
 318                 ioctl(fd
, DTRACEHIOC_REMOVE
, registrationID
); 
 320                 if ( gLinkContext
.verboseInit 
) 
 321                         dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID
); 
 327 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification 
 329 static void notifyAddImageCallbacks(ImageLoader
* image
) 
 331         // use guard so that we cannot notify about the same image twice 
 332         if ( ! image
->addFuncNotified() ) { 
 333                 for (std::vector
<ImageCallback
>::iterator it
=sAddImageCallbacks
.begin(); it 
!= sAddImageCallbacks
.end(); it
++) 
 334                         (*it
)(image
->machHeader(), image
->getSlide()); 
 335                 image
->setAddFuncNotified(); 
 340 // notify gdb about these new images 
 341 static const char* notifyGDB(enum dyld_image_states state
, uint32_t infoCount
, const struct dyld_image_info info
[]) 
 343         addImagesToAllImages(infoCount
, info
); 
 347 #if IMAGE_NOTIFY_SUPPORT 
 348 // notify objc about these new images 
 349 static void notifyAdding(const ImageLoader
* const * images
, unsigned int count
) 
 353                 dyld_image_info infos
[count
]; 
 354                 for (unsigned int i
=0; i 
< count
; ++i
) { 
 355                         dyld_image_info
* p 
= &infos
[i
]; 
 356                         const ImageLoader
* image 
= images
[i
]; 
 357                         p
->imageLoadAddress 
= image
->machHeader(); 
 358                         p
->imageFilePath 
= image
->getPath(); 
 359                         p
->imageFileModDate 
= image
->lastModified(); 
 360                         //dyld::log("notifying objc about %s\n", image->getPath()); 
 363                 // tell all interested images (after gdb, so you can debug anything the notification does) 
 364                 for (std::vector
<ImageLoader
*>::iterator it
=sImagesToNotifyAboutOtherImages
.begin(); it 
!= sImagesToNotifyAboutOtherImages
.end(); it
++) { 
 365                         (*it
)->doNotification(dyld_image_adding
, count
, infos
); 
 371 static StateHandlers
* stateToHandlers(dyld_image_states state
, StateHandlers handlersArray
[8])  
 374                 case dyld_image_state_mapped
: 
 375                         return &handlersArray
[0]; 
 377                 case dyld_image_state_dependents_mapped
: 
 378                         return &handlersArray
[1]; 
 380                 case dyld_image_state_rebased
: 
 381                         return &handlersArray
[2]; 
 383                 case dyld_image_state_bound
: 
 384                         return &handlersArray
[3]; 
 386                 case dyld_image_state_dependents_initialized
: 
 387                         return &handlersArray
[4]; 
 389                 case dyld_image_state_initialized
: 
 390                         return &handlersArray
[5]; 
 392                 case dyld_image_state_terminated
: 
 393                         return &handlersArray
[6]; 
 398 static void notifySingle(dyld_image_states state
, const struct mach_header
* mh
, const char* path
, time_t modDate
) 
 400         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
 401         if ( handlers 
!= NULL 
) { 
 402                 dyld_image_info info
; 
 403                 info
.imageLoadAddress   
= mh
; 
 404                 info
.imageFilePath              
= path
; 
 405                 info
.imageFileModDate   
= modDate
; 
 406                 for (std::vector
<dyld_image_state_change_handler
>::iterator it 
= handlers
->begin(); it 
!= handlers
->end(); ++it
) { 
 407                         const char* result 
= (*it
)(state
, 1, &info
); 
 408                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_mapped
) ) { 
 409                                 //fprintf(stderr, "  image rejected by handler=%p\n", *it); 
 410                                 // make copy of thrown string so that later catch clauses can free it 
 411                                 const char* str 
= strdup(result
); 
 420 static int imageSorter(const void* l
, const void* r
) 
 422         const ImageLoader
* left 
= *((ImageLoader
**)l
); 
 423         const ImageLoader
* right
= *((ImageLoader
**)r
); 
 424         return left
->compare(right
); 
 427 static void notifyBatchPartial(dyld_image_states state
, bool orLater
, dyld_image_state_change_handler onlyHandler
) 
 429         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sBatchHandlers
); 
 430         if ( handlers 
!= NULL 
) { 
 431                 // don't use a vector because it will use malloc/free and we want notifcation to be low cost 
 432                 ImageLoader
* images
[sAllImages
.size()+1]; 
 433                 ImageLoader
** end 
= images
; 
 434                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
 435                         dyld_image_states imageState 
= (*it
)->getState(); 
 436                         if ( (imageState 
== state
) || (orLater 
&& (imageState 
> state
)) ) 
 439                 if ( sBundleBeingLoaded 
!= NULL 
) { 
 440                         dyld_image_states imageState 
= sBundleBeingLoaded
->getState(); 
 441                         if ( (imageState 
== state
) || (orLater 
&& (imageState 
> state
)) ) 
 442                                 *end
++ = sBundleBeingLoaded
; 
 444                 unsigned int count 
= end
-images
; 
 445                 if ( end 
!= images 
) { 
 447                         qsort(images
, count
, sizeof(ImageLoader
*), &imageSorter
); 
 449                         dyld_image_info infos
[count
]; 
 450                         for (unsigned int i
=0; i 
< count
; ++i
) { 
 451                                 dyld_image_info
* p 
= &infos
[i
]; 
 452                                 ImageLoader
* image 
= images
[i
]; 
 453                                 //dyld::log("  state=%d, name=%s\n", state, image->getPath()); 
 454                                 p
->imageLoadAddress 
= image
->machHeader(); 
 455                                 p
->imageFilePath 
= image
->getPath(); 
 456                                 p
->imageFileModDate 
= image
->lastModified(); 
 457                                 // special case for add_image hook 
 458                                 if ( state 
== dyld_image_state_bound 
) 
 459                                         notifyAddImageCallbacks(image
); 
 462                         if ( onlyHandler 
!= NULL 
) { 
 463                                 const char* result 
= (*onlyHandler
)(state
, count
, infos
); 
 464                                 if ( (result 
!= NULL
) && (state 
== dyld_image_state_dependents_mapped
) ) { 
 465                                         //fprintf(stderr, "  images rejected by handler=%p\n", onlyHandler); 
 466                                         // make copy of thrown string so that later catch clauses can free it 
 467                                         const char* str 
= strdup(result
); 
 472                                 // call each handler with whole array  
 473                                 for (std::vector
<dyld_image_state_change_handler
>::iterator it 
= handlers
->begin(); it 
!= handlers
->end(); ++it
) { 
 474                                         const char* result 
= (*it
)(state
, count
, infos
); 
 475                                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_dependents_mapped
) ) { 
 476                                                 //fprintf(stderr, "  images rejected by handler=%p\n", *it); 
 477                                                 // make copy of thrown string so that later catch clauses can free it 
 478                                                 const char* str 
= strdup(result
); 
 487 static void notifyBatch(dyld_image_states state
) 
 489         notifyBatchPartial(state
, false, NULL
); 
 492 // In order for register_func_for_add_image() callbacks to to be called bottom up, 
 493 // we need to maintain a list of root images. The main executable is usally the 
 494 // first root. Any images dynamically added are also roots (unless already loaded). 
 495 // If DYLD_INSERT_LIBRARIES is used, those libraries are first. 
 496 static void addRootImage(ImageLoader
* image
) 
 498         //dyld::log("addRootImage(%p, %s)\n", image, image->getPath()); 
 499         // add to list of roots 
 500         sImageRoots
.push_back(image
); 
 503 #if IMAGE_NOTIFY_SUPPORT 
 504 // Objective-C will contain a __DATA/__image_notify section which contains pointers to a function to call 
 505 // whenever any new image is loaded. 
 506 static void addImageNeedingNotification(ImageLoader
* image
) 
 508         sImagesToNotifyAboutOtherImages
.push_back(image
); 
 512 static void clearAllDepths() 
 514         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) 
 518 static unsigned int imageCount() 
 520         return sAllImages
.size(); 
 523 static void notifySharedCacheInvalid() 
 525         gSharedCacheNeedsUpdating 
= true; 
 531 static void makeSharedCacheImportSegmentsWritable(bool writable
) 
 533         // if cache was built with read-only __IMPORT segments 
 534         if ( sImportSegmentsSize 
!= 0 ) { 
 535                 vm_prot_t prot 
= VM_PROT_EXECUTE 
| PROT_READ
; 
 537                         prot 
|= VM_PROT_WRITE
; 
 538                 vm_protect(mach_task_self(), sImportSegmentsStart
, sImportSegmentsSize
, false, prot
); 
 539                 if ( gLinkContext
.verboseMapping 
) { 
 540                         dyld::log("%18s at %p->%p altered permissions to %c%c%c\n", "", (char*)sImportSegmentsStart
, (char*)sImportSegmentsStart
+sImportSegmentsSize
-1, 
 541                                 (prot 
& PROT_READ
) ? 'r' : '.',  (prot 
& PROT_WRITE
) ? 'w' : '.',  (prot 
& PROT_EXEC
) ? 'x' : '.' ); 
 547 static void setNewProgramVars(const ProgramVars
& newVars
) 
 549         // make a copy of the pointers to program variables 
 550         gLinkContext
.programVars 
= newVars
; 
 552         // now set each program global to their initial value 
 553         *gLinkContext
.programVars
.NXArgcPtr 
= gLinkContext
.argc
; 
 554         *gLinkContext
.programVars
.NXArgvPtr 
= gLinkContext
.argv
; 
 555         *gLinkContext
.programVars
.environPtr 
= gLinkContext
.envp
; 
 556         *gLinkContext
.programVars
.__prognamePtr 
= gLinkContext
.progname
; 
 559 #if SUPPORT_OLD_CRT_INITIALIZATION 
 560 static void setRunInitialzersOldWay() 
 562         gRunInitializersOldWay 
= true;           
 566 static void addImage(ImageLoader
* image
) 
 568         // add to master list 
 569         sAllImages
.push_back(image
); 
 571         if ( sEnv
.DYLD_PRINT_LIBRARIES 
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) { 
 572                 dyld::log("dyld: loaded: %s\n", image
->getPath()); 
 575 #if OLD_GDB_DYLD_INTERFACE 
 576         // let gdb find out about this 
 577         addImageForgdb(image
->machHeader(), image
->getSlide(), image
->getPath(), image
->getLogicalPath()); 
 581 void removeImage(ImageLoader
* image
) 
 583         // if in termination list, pull it out and run terminator 
 584         for (std::vector
<ImageLoader
*>::iterator it
=sImageFilesNeedingTermination
.begin(); it 
!= sImageFilesNeedingTermination
.end(); it
++) { 
 585                 if ( *it 
== image 
) { 
 586                         sImageFilesNeedingTermination
.erase(it
); 
 587                         image
->doTermination(gLinkContext
); 
 592         // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration 
 593         for (std::vector
<RegisteredDOF
>::iterator it
=sImageFilesNeedingDOFUnregistration
.begin(); it 
!= sImageFilesNeedingDOFUnregistration
.end(); ) { 
 594                 if ( it
->mh 
== image
->machHeader() ) { 
 595                         unregisterDOF(it
->registrationID
); 
 596                         sImageFilesNeedingDOFUnregistration
.erase(it
); 
 597                         // don't increment iterator, the erase caused next element to be copied to where this iterator points 
 604         // tell all register add image handlers about this 
 605         // do this before removing image from internal data structures so that the callback can query dyld about the image 
 606         if ( image
->getState() >= dyld_image_state_bound 
) { 
 607                 for (std::vector
<ImageCallback
>::iterator it
=sRemoveImageCallbacks
.begin(); it 
!= sRemoveImageCallbacks
.end(); it
++) { 
 608                         (*it
)(image
->machHeader(), image
->getSlide()); 
 612 #if IMAGE_NOTIFY_SUPPORT 
 613         // tell all interested images 
 614         for (std::vector
<ImageLoader
*>::iterator it
=sImagesToNotifyAboutOtherImages
.begin(); it 
!= sImagesToNotifyAboutOtherImages
.end(); it
++) { 
 615                 dyld_image_info info
; 
 616                 info
.imageLoadAddress 
= image
->machHeader(); 
 617                 info
.imageFilePath 
= image
->getPath(); 
 618                 info
.imageFileModDate 
= image
->lastModified(); 
 619                 (*it
)->doNotification(dyld_image_removing
, 1, &info
); 
 623         // remove from master list 
 624         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
 625                 if ( *it 
== image 
) { 
 626                         sAllImages
.erase(it
); 
 631         // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back) 
 632         if ( sLastImageByAddressCache 
== image 
) 
 633                 sLastImageByAddressCache 
= NULL
; 
 635 #if IMAGE_NOTIFY_SUPPORT 
 636         // if in announcement list, pull it out  
 637         for (std::vector
<ImageLoader
*>::iterator it
=sImagesToNotifyAboutOtherImages
.begin(); it 
!= sImagesToNotifyAboutOtherImages
.end(); it
++) { 
 638                 if ( *it 
== image 
) { 
 639                         sImagesToNotifyAboutOtherImages
.erase(it
); 
 645         // if in root list, pull it out  
 646         for (std::vector
<ImageLoader
*>::iterator it
=sImageRoots
.begin(); it 
!= sImageRoots
.end(); it
++) { 
 647                 if ( *it 
== image 
) { 
 648                         sImageRoots
.erase(it
); 
 654         if ( sEnv
.DYLD_PRINT_LIBRARIES 
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) { 
 655                 dyld::log("dyld: unloaded: %s\n", image
->getPath()); 
 659         removeImageFromAllImages(image
->machHeader()); 
 661 #if OLD_GDB_DYLD_INTERFACE 
 663         removeImageForgdb(image
->machHeader()); 
 664         gdb_dyld_state_changed(); 
 669 static void terminationRecorder(ImageLoader
* image
) 
 671         sImageFilesNeedingTermination
.push_back(image
); 
 674 const char* getExecutablePath() 
 680 void initializeMainExecutable() 
 683         // record that we've reached this step 
 684         gLinkContext
.startedInitializingMainExecutable 
= true; 
 687         // make all __IMPORT segments in the shared cache read-only 
 688         // before executing any code 
 689         makeSharedCacheImportSegmentsWritable(false); 
 692         // run initialzers for any inserted dylibs 
 693         const int rootCount 
= sImageRoots
.size(); 
 694         if ( rootCount 
> 1 ) { 
 695                 for(int i
=1; i 
< rootCount
; ++i
) 
 696                         sImageRoots
[i
]->runInitializers(gLinkContext
); 
 699         // run initializers for main executable and everything it brings up  
 700         sMainExecutable
->runInitializers(gLinkContext
); 
 702         // register atexit() handler to run terminators in all loaded images when this process exits 
 703         if ( gLibSystemHelpers 
!= NULL 
)  
 704                 (*gLibSystemHelpers
->cxa_atexit
)(&runTerminators
, NULL
, NULL
); 
 706         // dump info if requested 
 707         if ( sEnv
.DYLD_PRINT_STATISTICS 
) 
 708                 ImageLoaderMachO::printStatistics(sAllImages
.size()); 
 711 bool mainExecutablePrebound() 
 713         return sMainExecutable
->usablePrebinding(gLinkContext
); 
 716 ImageLoader
* mainExecutable() 
 718         return sMainExecutable
; 
 722 void runTerminators(void* extra
) 
 724         const unsigned int imageCount 
= sImageFilesNeedingTermination
.size(); 
 725         for(unsigned int i
=imageCount
; i 
> 0; --i
){ 
 726                 ImageLoader
* image 
= sImageFilesNeedingTermination
[i
-1]; 
 727                 image
->doTermination(gLinkContext
); 
 728                 notifySingle(dyld_image_state_terminated
, image
->machHeader(), image
->getPath(), image
->lastModified()); 
 730         sImageFilesNeedingTermination
.clear(); 
 731         notifyBatch(dyld_image_state_terminated
); 
 736 // Turns a colon separated list of strings 
 737 // into a NULL terminated array of string  
 740 static const char** parseColonList(const char* list
) 
 742         if ( list
[0] == '\0' ) 
 746         for(const char* s
=list
; *s 
!= '\0'; ++s
) { 
 752         const char* start 
= list
; 
 753         char** result 
= new char*[colonCount
+2]; 
 754         for(const char* s
=list
; *s 
!= '\0'; ++s
) { 
 757                         char* str 
= new char[len
+1]; 
 758                         strncpy(str
, start
, len
); 
 761                         result
[index
++] = str
; 
 764         int len 
= strlen(start
); 
 765         char* str 
= new char[len
+1]; 
 767         result
[index
++] = str
; 
 768         result
[index
] = NULL
; 
 770         return (const char**)result
; 
 774 static void paths_expand_roots(const char **paths
, const char *key
, const char *val
) 
 776 //      assert(val != NULL); 
 777 //      assert(paths != NULL); 
 779                 size_t keyLen 
= strlen(key
); 
 780                 for(int i
=0; paths
[i
] != NULL
; ++i
) { 
 781                         if ( strncmp(paths
[i
], key
, keyLen
) == 0 ) { 
 782                                 char* newPath 
= new char[strlen(val
) + (strlen(paths
[i
]) - keyLen
) + 1]; 
 783                                 strcpy(newPath
, val
); 
 784                                 strcat(newPath
, &paths
[i
][keyLen
]); 
 792 static void removePathWithPrefix(const char* paths
[], const char* prefix
) 
 794     size_t prefixLen 
= strlen(prefix
); 
 797     for(i 
= 0; paths
[i
] != NULL
; ++i
) { 
 798         if ( strncmp(paths
[i
], prefix
, prefixLen
) == 0 ) 
 801             paths
[i
-skip
] = paths
[i
]; 
 803     paths
[i
-skip
] = NULL
; 
 808 static void paths_dump(const char **paths
) 
 810 //   assert(paths != NULL); 
 811   const char **strs 
= paths
; 
 814     dyld::log("\"%s\"\n", *strs
); 
 821 static void printOptions(const char* argv
[]) 
 824         while ( NULL 
!= argv
[i
] ) { 
 825                 dyld::log("opt[%i] = \"%s\"\n", i
, argv
[i
]); 
 830 static void printEnvironmentVariables(const char* envp
[]) 
 832         while ( NULL 
!= *envp 
) { 
 833                 dyld::log("%s\n", *envp
); 
 838 void processDyldEnvironmentVarible(const char* key
, const char* value
) 
 840         if ( strcmp(key
, "DYLD_FRAMEWORK_PATH") == 0 ) { 
 841                 sEnv
.DYLD_FRAMEWORK_PATH 
= parseColonList(value
); 
 842                 gSharedCacheDontNotify 
= true; 
 844         else if ( strcmp(key
, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) { 
 845                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= parseColonList(value
); 
 846                 gSharedCacheDontNotify 
= true; 
 848         else if ( strcmp(key
, "DYLD_LIBRARY_PATH") == 0 ) { 
 849                 sEnv
.DYLD_LIBRARY_PATH 
= parseColonList(value
); 
 850                 gSharedCacheDontNotify 
= true; 
 852         else if ( strcmp(key
, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) { 
 853                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= parseColonList(value
); 
 854                 gSharedCacheDontNotify 
= true; 
 856         else if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) ) { 
 857                 gSharedCacheDontNotify 
= true; 
 858                 if ( strcmp(value
, "/") != 0 ) { 
 859                         sEnv
.DYLD_ROOT_PATH 
= parseColonList(value
); 
 860                         for (int i
=0; sEnv
.DYLD_ROOT_PATH
[i
] != NULL
; ++i
) { 
 861                                 if ( sEnv
.DYLD_ROOT_PATH
[i
][0] != '/' ) { 
 862                                         dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n"); 
 863                                         sEnv
.DYLD_ROOT_PATH 
= NULL
; 
 869         else if ( strcmp(key
, "DYLD_IMAGE_SUFFIX") == 0 ) { 
 870                 gSharedCacheDontNotify 
= true; 
 871                 gLinkContext
.imageSuffix 
= value
; 
 873         else if ( strcmp(key
, "DYLD_INSERT_LIBRARIES") == 0 ) { 
 874                 sEnv
.DYLD_INSERT_LIBRARIES 
= parseColonList(value
); 
 875                 gSharedCacheDontNotify 
= true; 
 877         else if ( strcmp(key
, "DYLD_PRINT_OPTS") == 0 ) { 
 878                 sEnv
.DYLD_PRINT_OPTS 
= true; 
 880         else if ( strcmp(key
, "DYLD_PRINT_ENV") == 0 ) { 
 881                 sEnv
.DYLD_PRINT_ENV 
= true; 
 883         else if ( strcmp(key
, "DYLD_DISABLE_DOFS") == 0 ) { 
 884                 sEnv
.DYLD_DISABLE_DOFS 
= true; 
 886         else if ( strcmp(key
, "DYLD_DISABLE_PREFETCH") == 0 ) { 
 887                 gLinkContext
.preFetchDisabled 
= true; 
 889         else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES") == 0 ) { 
 890                 sEnv
.DYLD_PRINT_LIBRARIES 
= true; 
 892         else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) { 
 893                 sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
= true; 
 895         else if ( strcmp(key
, "DYLD_BIND_AT_LAUNCH") == 0 ) { 
 896                 sEnv
.DYLD_BIND_AT_LAUNCH 
= true; 
 898         else if ( strcmp(key
, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) { 
 899                 gLinkContext
.bindFlat 
= true; 
 901         else if ( strcmp(key
, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) { 
 902                 // ignore, no longer relevant but some scripts still set it 
 904         else if ( strcmp(key
, "DYLD_NO_FIX_PREBINDING") == 0 ) { 
 905                 gSharedCacheDontNotify 
= true; 
 907         else if ( strcmp(key
, "DYLD_PREBIND_DEBUG") == 0 ) { 
 908                 gLinkContext
.verbosePrebinding 
= true; 
 910         else if ( strcmp(key
, "DYLD_PRINT_INITIALIZERS") == 0 ) { 
 911                 gLinkContext
.verboseInit 
= true; 
 913         else if ( strcmp(key
, "DYLD_PRINT_DOFS") == 0 ) { 
 914                 gLinkContext
.verboseDOF 
= true; 
 916         else if ( strcmp(key
, "DYLD_PRINT_STATISTICS") == 0 ) { 
 917                 sEnv
.DYLD_PRINT_STATISTICS 
= true; 
 919         else if ( strcmp(key
, "DYLD_PRINT_SEGMENTS") == 0 ) { 
 920                 gLinkContext
.verboseMapping 
= true; 
 922         else if ( strcmp(key
, "DYLD_PRINT_BINDINGS") == 0 ) { 
 923                 gLinkContext
.verboseBind 
= true; 
 925         else if ( strcmp(key
, "DYLD_PRINT_REBASINGS") == 0 ) { 
 926                 gLinkContext
.verboseRebase 
= true; 
 928         else if ( strcmp(key
, "DYLD_PRINT_APIS") == 0 ) { 
 931         else if ( strcmp(key
, "DYLD_PRINT_WARNINGS") == 0 ) { 
 932                 gLinkContext
.verboseWarnings 
= true; 
 934         else if ( strcmp(key
, "DYLD_SHARED_REGION") == 0 ) { 
 935                 gSharedCacheDontNotify 
= true; 
 936                 if ( strcmp(value
, "private") == 0 ) { 
 937                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
 939                 else if ( strcmp(value
, "avoid") == 0 ) { 
 940                         gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
 942                 else if ( strcmp(value
, "use") == 0 ) { 
 943                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUseSharedRegion
; 
 945                 else if ( value
[0] == '\0' ) { 
 946                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUseSharedRegion
; 
 949                         dyld::warn("unknown option to DYLD_SHARED_REGION.  Valid options are: use, private, avoid\n"); 
 952         else if ( strcmp(key
, "DYLD_IGNORE_PREBINDING") == 0 ) { 
 953                 gSharedCacheDontNotify 
= true; 
 954                 if ( strcmp(value
, "all") == 0 ) { 
 955                         gLinkContext
.prebindUsage 
= ImageLoader::kUseNoPrebinding
; 
 957                 else if ( strcmp(value
, "app") == 0 ) { 
 958                         gLinkContext
.prebindUsage 
= ImageLoader::kUseAllButAppPredbinding
; 
 960                 else if ( strcmp(value
, "nonsplit") == 0 ) { 
 961                         gLinkContext
.prebindUsage 
= ImageLoader::kUseSplitSegPrebinding
; 
 963                 else if ( value
[0] == '\0' ) { 
 964                         gLinkContext
.prebindUsage 
= ImageLoader::kUseSplitSegPrebinding
; 
 967                         dyld::warn("unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n"); 
 971                 dyld::warn("unknown environment variable: %s\n", key
); 
 977 // For security, setuid programs ignore DYLD_* environment variables. 
 978 // Additionally, the DYLD_* enviroment variables are removed 
 979 // from the environment, so that any child processes don't see them. 
 981 static void pruneEnvironmentVariables(const char* envp
[], const char*** applep
) 
 983         // setuit binaries don't trigger a cache rebuild 
 984         gSharedCacheDontNotify 
= true; 
 986         // delete all DYLD_* and LD_LIBRARY_PATH environment variables 
 987         int removedCount 
= 0; 
 988         const char** d 
= envp
; 
 989         for(const char** s 
= envp
; *s 
!= NULL
; s
++) { 
 990             if ( (strncmp(*s
, "DYLD_", 5) != 0) && (strncmp(*s
, "LD_LIBRARY_PATH=", 16) != 0) ) { 
 999         // slide apple parameters 
1000         if ( removedCount 
> 0 ) { 
1003                         *d 
= d
[removedCount
]; 
1004                 } while ( *d
++ != NULL 
); 
1007         // disable framework and library fallback paths for setuid binaries rdar://problem/4589305 
1008         sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= NULL
; 
1009         sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= NULL
; 
1013 static void checkEnvironmentVariables(const char* envp
[], bool ignoreEnviron
) 
1015         const char* home 
= NULL
; 
1017         for(p 
= envp
; *p 
!= NULL
; p
++) { 
1018                 const char* keyEqualsValue 
= *p
; 
1019             if ( strncmp(keyEqualsValue
, "DYLD_", 5) == 0 ) { 
1020                         const char* equals 
= strchr(keyEqualsValue
, '='); 
1021                         if ( (equals 
!= NULL
) && !ignoreEnviron 
) { 
1022                                 const char* value 
= &equals
[1]; 
1023                                 const int keyLen 
= equals
-keyEqualsValue
; 
1025                                 strncpy(key
, keyEqualsValue
, keyLen
); 
1027                                 processDyldEnvironmentVarible(key
, value
); 
1030             else if ( strncmp(keyEqualsValue
, "HOME=", 5) == 0 ) { 
1031                         home 
= &keyEqualsValue
[5]; 
1033                 else if ( strncmp(keyEqualsValue
, "LD_LIBRARY_PATH=", 16) == 0 ) { 
1034                         const char* path 
= &keyEqualsValue
[16]; 
1035                         sEnv
.LD_LIBRARY_PATH 
= parseColonList(path
); 
1039         // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment 
1040         if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
== NULL 
) { 
1041                 const char** paths 
= sFrameworkFallbackPaths
; 
1043                         removePathWithPrefix(paths
, "$HOME"); 
1045                         paths_expand_roots(paths
, "$HOME", home
); 
1046                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= paths
; 
1049         // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment 
1050         if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
== NULL 
) { 
1051                 const char** paths 
= sLibraryFallbackPaths
; 
1053                         removePathWithPrefix(paths
, "$HOME"); 
1055                         paths_expand_roots(paths
, "$HOME", home
); 
1056                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= paths
; 
1061 static void getHostInfo() 
1064         struct host_basic_info info
; 
1065         mach_msg_type_number_t count 
= HOST_BASIC_INFO_COUNT
; 
1066         mach_port_t hostPort 
= mach_host_self(); 
1067         kern_return_t result 
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
); 
1068         mach_port_deallocate(mach_task_self(), hostPort
); 
1069         if ( result 
!= KERN_SUCCESS 
) 
1070                 throw "host_info() failed"; 
1072         sHostCPU                
= info
.cpu_type
; 
1073         sHostCPUsubtype 
= info
.cpu_subtype
; 
1075         size_t valSize 
= sizeof(sHostCPU
); 
1076         if (sysctlbyname ("hw.cputype", &sHostCPU
, &valSize
, NULL
, 0) != 0)  
1077                 throw "sysctlbyname(hw.cputype) failed"; 
1078         valSize 
= sizeof(sHostCPUsubtype
); 
1079         if (sysctlbyname ("hw.cpusubtype", &sHostCPUsubtype
, &valSize
, NULL
, 0) != 0)  
1080                 throw "sysctlbyname(hw.cpusubtype) failed"; 
1084 static void checkSharedRegionDisable() 
1086         #if __ppc__ || __i386__ 
1087         // if main executable has segments that overlap the shared region,  
1088         // then disable using the shared region 
1089         if ( sMainExecutable
->overlapsWithAddressRange((void*)0x90000000, (void*)0xAFFFFFFF) ) { 
1090                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
1091                 if ( gLinkContext
.verboseMapping 
) 
1092                         dyld::warn("disabling shared region because main executable overlaps\n"); 
1097 bool validImage(const ImageLoader
* possibleImage
) 
1099         const unsigned int imageCount 
= sAllImages
.size(); 
1100         for(unsigned int i
=0; i 
< imageCount
; ++i
) { 
1101                 if ( possibleImage 
== sAllImages
[i
] ) { 
1108 uint32_t getImageCount() 
1110         return sAllImages
.size(); 
1113 ImageLoader
* getIndexedImage(unsigned int index
) 
1115         if ( index 
< sAllImages
.size() ) 
1116                 return sAllImages
[index
]; 
1120 ImageLoader
* findImageByMachHeader(const struct mach_header
* target
) 
1122         const unsigned int imageCount 
= sAllImages
.size(); 
1123         for(unsigned int i
=0; i 
< imageCount
; ++i
) { 
1124                 ImageLoader
* anImage 
= sAllImages
[i
]; 
1125                 if ( anImage
->machHeader() == target 
) 
1132 ImageLoader
* findImageContainingAddress(const void* addr
) 
1135         static int cacheHit 
= 0;  
1136         static int cacheMiss 
= 0;  
1137         static int cacheNotMacho 
= 0;  
1138         if ( ((cacheHit
+cacheMiss
+cacheNotMacho
) % 100) == 0 ) 
1139                 dyld::log("findImageContainingAddress(): cache hit = %d, miss = %d, unknown = %d\n", cacheHit
, cacheMiss
, cacheNotMacho
); 
1141         // first look in image where last address was found rdar://problem/3685517 
1142         if ( (sLastImageByAddressCache 
!= NULL
) && sLastImageByAddressCache
->containsAddress(addr
) ) { 
1146                 return sLastImageByAddressCache
; 
1148         // do exhastive search  
1149         // todo: consider maintaining a list sorted by address ranges and do a binary search on that 
1150         const unsigned int imageCount 
= sAllImages
.size(); 
1151         for(unsigned int i
=0; i 
< imageCount
; ++i
) { 
1152                 ImageLoader
* anImage 
= sAllImages
[i
]; 
1153                 if ( anImage
->containsAddress(addr
) ) { 
1154                         sLastImageByAddressCache 
= anImage
; 
1167 ImageLoader
* findImageContainingAddressThreadSafe(const void* addr
) 
1169         // do exhastive search  
1170         // todo: consider maintaining a list sorted by address ranges and do a binary search on that 
1171         const unsigned int imageCount 
= sAllImages
.size(); 
1172         for(unsigned int i
=0; i 
< imageCount
; ++i
) { 
1173                 ImageLoader
* anImage 
= sAllImages
[i
]; 
1174                 if ( anImage
->containsAddress(addr
) ) { 
1182 void forEachImageDo( void (*callback
)(ImageLoader
*, void* userData
), void* userData
) 
1184         const unsigned int imageCount 
= sAllImages
.size(); 
1185         for(unsigned int i
=0; i 
< imageCount
; ++i
) { 
1186                 ImageLoader
* anImage 
= sAllImages
[i
]; 
1187                 (*callback
)(anImage
, userData
); 
1191 ImageLoader
* findLoadedImage(const struct stat
& stat_buf
) 
1193         const unsigned int imageCount 
= sAllImages
.size(); 
1194         for(unsigned int i
=0; i 
< imageCount
; ++i
){ 
1195                 ImageLoader
* anImage 
= sAllImages
[i
]; 
1196                 if ( anImage
->statMatch(stat_buf
) ) 
1202 // based on ANSI-C strstr() 
1203 static const char* strrstr(const char* str
, const char* sub
)  
1205         const int sublen 
= strlen(sub
); 
1206         for(const char* p 
= &str
[strlen(str
)]; p 
!= str
; --p
) { 
1207                 if ( strncmp(p
, sub
, sublen
) == 0 ) 
1215 // Find framework path 
1217 //  /path/foo.framework/foo                                                             =>   foo.framework/foo   
1218 //  /path/foo.framework/Versions/A/foo                                  =>   foo.framework/Versions/A/foo 
1219 //  /path/foo.framework/Frameworks/bar.framework/bar    =>   bar.framework/bar 
1220 //  /path/foo.framework/Libraries/bar.dylb                              =>   NULL 
1221 //  /path/foo.framework/bar                                                             =>   NULL 
1223 // Returns NULL if not a framework path 
1225 static const char* getFrameworkPartialPath(const char* path
) 
1227         const char* dirDot 
= strrstr(path
, ".framework/"); 
1228         if ( dirDot 
!= NULL 
) { 
1229                 const char* dirStart 
= dirDot
; 
1230                 for ( ; dirStart 
>= path
; --dirStart
) { 
1231                         if ( (*dirStart 
== '/') || (dirStart 
== path
) ) { 
1232                                 const char* frameworkStart 
= &dirStart
[1]; 
1233                                 if ( dirStart 
== path 
) 
1235                                 int len 
= dirDot 
- frameworkStart
; 
1236                                 char framework
[len
+1]; 
1237                                 strncpy(framework
, frameworkStart
, len
); 
1238                                 framework
[len
] = '\0'; 
1239                                 const char* leaf 
= strrchr(path
, '/'); 
1240                                 if ( leaf 
!= NULL 
) { 
1241                                         if ( strcmp(framework
, &leaf
[1]) == 0 ) { 
1242                                                 return frameworkStart
; 
1244                                         if (  gLinkContext
.imageSuffix 
!= NULL 
) { 
1245                                                 // some debug frameworks have install names that end in _debug 
1246                                                 if ( strncmp(framework
, &leaf
[1], len
) == 0 ) { 
1247                                                         if ( strcmp( gLinkContext
.imageSuffix
, &leaf
[len
+1]) == 0 ) 
1248                                                                 return frameworkStart
; 
1259 static const char* getLibraryLeafName(const char* path
) 
1261         const char* start 
= strrchr(path
, '/'); 
1262         if ( start 
!= NULL 
) 
1269 // only for architectures that use cpu-sub-types 
1270 #if CPU_SUBTYPES_SUPPORTED  
1272 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST 
= -1; 
1276 //      A fat file may contain multiple sub-images for the same CPU type. 
1277 //      In that case, dyld picks which sub-image to use by scanning a table 
1278 //      of preferred cpu-sub-types for the running cpu.   
1280 //      There is one row in the table for each cpu-sub-type on which dyld might run. 
1281 //  The first entry in a row is that cpu-sub-type.  It is followed by all 
1282 //      cpu-sub-types that can run on that cpu, if preferred order.  Each row ends with  
1283 //      a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),  
1284 //  followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row. 
1289 //      32-bit PowerPC sub-type lists 
1291 const int kPPC_RowCount 
= 4; 
1292 static const cpu_subtype_t kPPC32
[kPPC_RowCount
][6] = {  
1293         // G5 can run any code 
1294         {  CPU_SUBTYPE_POWERPC_970
, CPU_SUBTYPE_POWERPC_7450
,  CPU_SUBTYPE_POWERPC_7400
, CPU_SUBTYPE_POWERPC_750
, CPU_SUBTYPE_POWERPC_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
1296         // G4 can run all but G5 code 
1297         {  CPU_SUBTYPE_POWERPC_7450
,  CPU_SUBTYPE_POWERPC_7400
,  CPU_SUBTYPE_POWERPC_750
, CPU_SUBTYPE_POWERPC_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
}, 
1298         {  CPU_SUBTYPE_POWERPC_7400
,  CPU_SUBTYPE_POWERPC_7450
,  CPU_SUBTYPE_POWERPC_750
, CPU_SUBTYPE_POWERPC_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
}, 
1300         // G3 cannot run G4 or G5 code 
1301         { CPU_SUBTYPE_POWERPC_750
,  CPU_SUBTYPE_POWERPC_ALL
, CPU_SUBTYPE_END_OF_LIST
,  CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST 
} 
1306 // scan the tables above to find the cpu-sub-type-list for this machine 
1307 static const cpu_subtype_t
* findCPUSubtypeList(cpu_type_t cpu
, cpu_subtype_t subtype
) 
1310                 case CPU_TYPE_POWERPC
: 
1311                         for (int i
=0; i 
< kPPC_RowCount 
; ++i
) { 
1312                                 if ( kPPC32
[i
][0] == subtype 
) 
1323 // scan fat table-of-contents for best most preferred subtype 
1324 static bool fatFindBestFromOrderedList(cpu_type_t cpu
, const cpu_subtype_t list
[], const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
1326         const fat_arch
* const archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
1327         for (uint32_t subTypeIndex
=0; list
[subTypeIndex
] != CPU_SUBTYPE_END_OF_LIST
; ++subTypeIndex
) { 
1328                 for(uint32_t fatIndex
=0; fatIndex 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++fatIndex
) { 
1329                         if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cputype
) == cpu
)  
1330                                 && (list
[subTypeIndex
] == (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cpusubtype
)) ) { 
1331                                 *offset 
= OSSwapBigToHostInt32(archs
[fatIndex
].offset
); 
1332                                 *len 
= OSSwapBigToHostInt32(archs
[fatIndex
].size
); 
1340 // scan fat table-of-contents for exact match of cpu and cpu-sub-type 
1341 static bool fatFindExactMatch(cpu_type_t cpu
, cpu_subtype_t subtype
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
1343         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
1344         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
1345                 if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) 
1346                         && ((cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == subtype
) ) { 
1347                         *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
1348                         *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
1355 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types 
1356 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
1358         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
1359         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
1360                 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) { 
1362                                 case CPU_TYPE_POWERPC
: 
1363                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_POWERPC_ALL 
) { 
1364                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
1365                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
1375 #endif // CPU_SUBTYPES_SUPPORTED 
1378 // A fat file may contain multiple sub-images for the same cpu-type, 
1379 // each optimized for a different cpu-sub-type (e.g G3 or G5). 
1380 // This routine picks the optimal sub-image. 
1382 static bool fatFindBest(const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
1384 #if CPU_SUBTYPES_SUPPORTED 
1385         // assume all dylibs loaded must have same cpu type as main executable 
1386         const cpu_type_t cpu 
= sMainExecutableMachHeader
->cputype
; 
1388         // We only know the subtype to use if the main executable cpu type matches the host 
1389         if ( (cpu 
& CPU_TYPE_MASK
) == sHostCPU 
) { 
1390                 // get preference ordered list of subtypes 
1391                 const cpu_subtype_t
* subTypePreferenceList 
= findCPUSubtypeList(cpu
, sHostCPUsubtype
); 
1393                 // use ordered list to find best sub-image in fat file 
1394                 if ( subTypePreferenceList 
!= NULL 
)  
1395                         return fatFindBestFromOrderedList(cpu
, subTypePreferenceList
, fh
, offset
, len
); 
1397                 // if running cpu is not in list, try for an exact match 
1398                 if ( fatFindExactMatch(cpu
, sHostCPUsubtype
, fh
, offset
, len
) ) 
1402         // running on an uknown cpu, can only load generic code 
1403         return fatFindRunsOnAllCPUs(cpu
, fh
, offset
, len
); 
1405         // just find first slice with matching architecture 
1406         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
1407         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
1408                 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == sMainExecutableMachHeader
->cputype
) { 
1409                         *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
1410                         *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
1421 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used 
1422 // on the current processor. // 
1423 bool isCompatibleMachO(const uint8_t* firstPage
) 
1425 #if CPU_SUBTYPES_SUPPORTED 
1426         // It is deemed compatible if any of the following are true: 
1427         //  1) mach_header subtype is in list of compatible subtypes for running processor 
1428         //  2) mach_header subtype is same as running processor subtype 
1429         //  3) mach_header subtype runs on all processor variants 
1430         const mach_header
* mh 
= (mach_header
*)firstPage
; 
1431         if ( mh
->magic 
== sMainExecutableMachHeader
->magic 
) { 
1432                 if ( mh
->cputype 
== sMainExecutableMachHeader
->cputype 
) { 
1433                         if ( (mh
->cputype 
& CPU_TYPE_MASK
) == sHostCPU 
) { 
1434                                 // get preference ordered list of subtypes that this machine can use 
1435                                 const cpu_subtype_t
* subTypePreferenceList 
= findCPUSubtypeList(mh
->cputype
, sHostCPUsubtype
); 
1436                                 if ( subTypePreferenceList 
!= NULL 
) { 
1437                                         // if image's subtype is in the list, it is compatible 
1438                                         for (const cpu_subtype_t
* p 
= subTypePreferenceList
; *p 
!= CPU_SUBTYPE_END_OF_LIST
; ++p
) { 
1439                                                 if ( *p 
== mh
->cpusubtype 
) 
1442                                         // have list and not in list, so not compatible 
1443                                         throw "incompatible cpu-subtype"; 
1445                                 // unknown cpu sub-type, but if exact match for current subtype then ok to use 
1446                                 if ( mh
->cpusubtype 
== sHostCPUsubtype 
)  
1450                         // cpu type has no ordered list of subtypes 
1451                         switch (mh
->cputype
) { 
1452                                 case CPU_TYPE_POWERPC
: 
1453                                         // allow _ALL to be used by any client 
1454                                         if ( mh
->cpusubtype 
== CPU_SUBTYPE_POWERPC_ALL 
)  
1457                                 case CPU_TYPE_POWERPC64
: 
1459                                 case CPU_TYPE_X86_64
: 
1460                                         // subtypes are not used or these architectures 
1466         // For architectures that don't support cpu-sub-types 
1467         // this just check the cpu type. 
1468         const mach_header
* mh 
= (mach_header
*)firstPage
; 
1469         if ( mh
->magic 
== sMainExecutableMachHeader
->magic 
) { 
1470                 if ( mh
->cputype 
== sMainExecutableMachHeader
->cputype 
) { 
1481 // The kernel maps in main executable before dyld gets control.  We need to  
1482 // make an ImageLoader* for the already mapped in main executable. 
1483 static ImageLoader
* instantiateFromLoadedImage(const struct mach_header
* mh
, uintptr_t slide
, const char* path
) 
1485         // try mach-o loader 
1486         if ( isCompatibleMachO((const uint8_t*)mh
) ) { 
1487                 ImageLoader
* image 
= new ImageLoaderMachO(mh
, slide
, path
, gLinkContext
); 
1492         throw "main executable not a known format"; 
1495 #if DYLD_SHARED_CACHE_SUPPORT 
1496 static ImageLoader
* findSharedCacheImage(const struct stat
& stat_buf
, const char* path
) 
1498         if ( sSharedCache 
!= NULL 
) { 
1499                 // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired 
1500                 const dyld_cache_image_info
* const start 
= (dyld_cache_image_info
*)((uint8_t*)sSharedCache 
+ sSharedCache
->imagesOffset
); 
1501                 const dyld_cache_image_info
* const end 
= &start
[sSharedCache
->imagesCount
]; 
1502                 for( const dyld_cache_image_info
* p 
= start
; p 
!= end
; ++p
) { 
1503                         // check mtime and inode first because it is fast 
1504                         if ( ((time_t)p
->modTime 
== stat_buf
.st_mtime
) && ((ino_t
)p
->inode 
== stat_buf
.st_ino
) ) { 
1505                                 // mod-time and inode match an image in the shared cache, now check path 
1506                                 const char* pathInCache 
= (char*)sSharedCache 
+ p
->pathFileOffset
; 
1507                                 bool cacheHit 
= (strcmp(path
, pathInCache
) == 0); 
1509                                         // path does not match install name of dylib in cache, but inode and mtime does match 
1510                                         // perhaps path is a symlink to the cached dylib 
1511                                         struct stat pathInCacheStatBuf
; 
1512                                         if ( stat(pathInCache
, &pathInCacheStatBuf
) != -1 ) 
1513                                                 cacheHit 
= ( (pathInCacheStatBuf
.st_dev 
== stat_buf
.st_dev
) && (pathInCacheStatBuf
.st_ino 
== stat_buf
.st_ino
) );         
1516                                         // found image in cache, instantiate an ImageLoader with it 
1517                                         return new ImageLoaderMachO((struct mach_header
*)(p
->address
), pathInCache
, stat_buf
, gLinkContext
); 
1526 static ImageLoader
* checkandAddImage(ImageLoader
* image
, const LoadContext
& context
) 
1528         // now sanity check that this loaded image does not have the same install path as any existing image 
1529         const char* loadedImageInstallPath 
= image
->getInstallPath(); 
1530         if ( image
->isDylib() && (loadedImageInstallPath 
!= NULL
) && (loadedImageInstallPath
[0] == '/') ) { 
1531                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
1532                         ImageLoader
* anImage 
= *it
; 
1533                         const char* installPath 
= anImage
->getInstallPath(); 
1534                         if ( installPath 
!= NULL
) { 
1535                                 if ( strcmp(loadedImageInstallPath
, installPath
) == 0 ) { 
1536                                         //dyld::log("duplicate(%s) => %p\n", installPath, anImage); 
1544         // some API's restrict what they can load 
1545         if ( context
.mustBeBundle 
&& !image
->isBundle() ) 
1546                 throw "not a bundle"; 
1547         if ( context
.mustBeDylib 
&& !image
->isDylib() ) 
1548                 throw "not a dylib"; 
1550         // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
1551         if ( ! image
->isBundle() )  
1557 // map in file and instantiate an ImageLoader 
1558 static ImageLoader
* loadPhase6(int fd
, struct stat
& stat_buf
, const char* path
, const LoadContext
& context
) 
1560         //dyld::log("%s(%s)\n", __func__ , path); 
1561         uint64_t fileOffset 
= 0; 
1562         uint64_t fileLength 
= stat_buf
.st_size
; 
1564         // validate it is a file (not directory) 
1565         if ( (stat_buf
.st_mode 
& S_IFMT
) != S_IFREG 
)  
1568         uint8_t firstPage
[4096]; 
1569         bool shortPage 
= false; 
1571         // min mach-o file is 4K 
1572         if ( fileLength 
< 4096 ) { 
1573                 pread(fd
, firstPage
, fileLength
, 0); 
1577                 pread(fd
, firstPage
, 4096,0); 
1580         // if fat wrapper, find usable sub-file 
1581         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPage
; 
1582         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
1583                 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) { 
1584                         pread(fd
, firstPage
, 4096, fileOffset
); 
1587                         throw "no matching architecture in universal wrapper"; 
1591         // try mach-o loader 
1592         if ( isCompatibleMachO(firstPage
) ) { 
1594                         throw "file too short"; 
1596                 // instantiate an image 
1597                 ImageLoader
* image 
= new ImageLoaderMachO(path
, fd
, firstPage
, fileOffset
, fileLength
, stat_buf
, gLinkContext
); 
1600                 return checkandAddImage(image
, context
); 
1603         // try other file formats here... 
1606         // throw error about what was found 
1607         switch (*(uint32_t*)firstPage
) { 
1612                         throw "mach-o, but wrong architecture"; 
1614                 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",  
1615                         firstPage
[0], firstPage
[1], firstPage
[2], firstPage
[3], firstPage
[4], firstPage
[5], firstPage
[6],firstPage
[7]); 
1621 static ImageLoader
* loadPhase5open(const char* path
, const LoadContext
& context
, std::vector
<const char*>* exceptions
) 
1623         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1624         ImageLoader
* image 
= NULL
; 
1626         // just return NULL if file not found, but record any other errors 
1627         struct stat stat_buf
; 
1628         if ( stat(path
, &stat_buf
) == -1 ) { 
1630                 if ( err 
!= ENOENT 
) { 
1631                         exceptions
->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path
, err
)); 
1636         // in case image was renamed or found via symlinks, check for inode match 
1637         image 
= findLoadedImage(stat_buf
); 
1638         if ( image 
!= NULL 
) 
1641         // do nothing if not already loaded and if RTLD_NOLOAD or NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 
1642         if ( context
.dontLoad 
) 
1645 #if DYLD_SHARED_CACHE_SUPPORT 
1646         // see if this image is in shared cache 
1647         image 
= findSharedCacheImage(stat_buf
, path
); 
1648         if ( image 
!= NULL 
) { 
1649                 return checkandAddImage(image
, context
); 
1653         // open file (automagically closed when this function exits) 
1654         FileOpener 
file(path
); 
1656         // just return NULL if file not found 
1657         if ( file
.getFileDescriptor() == -1 )  
1661                 return loadPhase6(file
.getFileDescriptor(), stat_buf
, path
, context
); 
1663         catch (const char* msg
) { 
1664                 const char* newMsg 
= dyld::mkstringf("%s: %s", path
, msg
); 
1665                 exceptions
->push_back(newMsg
); 
1671 // look for path match with existing loaded images 
1672 static ImageLoader
* loadPhase5check(const char* path
, const LoadContext
& context
) 
1674         //dyld::log("%s(%s)\n", __func__ , path); 
1675         // search path against load-path and install-path of all already loaded images 
1676         uint32_t hash 
= ImageLoader::hash(path
); 
1677         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
1678                 ImageLoader
* anImage 
= *it
; 
1679                 // check has first to cut down on strcmp calls 
1680                 if ( anImage
->getPathHash() == hash 
) 
1681                         if ( strcmp(path
, anImage
->getPath()) == 0 ) { 
1682                                 // if we are looking for a dylib don't return something else 
1683                                 if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) 
1686                 if ( context
.matchByInstallName 
|| anImage
->matchInstallPath() ) { 
1687                         const char* installPath 
= anImage
->getInstallPath(); 
1688                         if ( installPath 
!= NULL
) { 
1689                                 if ( strcmp(path
, installPath
) == 0 ) { 
1690                                         // if we are looking for a dylib don't return something else 
1691                                         if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) 
1698         //dyld::log("%s(%s) => NULL\n", __func__,   path); 
1703 // open or check existing 
1704 static ImageLoader
* loadPhase5(const char* path
, const LoadContext
& context
, std::vector
<const char*>* exceptions
) 
1706         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1707         if ( exceptions 
!= NULL 
)  
1708                 return loadPhase5open(path
, context
, exceptions
); 
1710                 return loadPhase5check(path
, context
); 
1713 // try with and without image suffix 
1714 static ImageLoader
* loadPhase4(const char* path
, const LoadContext
& context
, std::vector
<const char*>* exceptions
) 
1716         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1717         ImageLoader
* image 
= NULL
; 
1718         if (  gLinkContext
.imageSuffix 
!= NULL 
) { 
1719                 char pathWithSuffix
[strlen(path
)+strlen( gLinkContext
.imageSuffix
)+2]; 
1720                 ImageLoader::addSuffix(path
,  gLinkContext
.imageSuffix
, pathWithSuffix
); 
1721                 image 
= loadPhase5(pathWithSuffix
, context
, exceptions
); 
1723         if ( image 
== NULL 
) 
1724                 image 
= loadPhase5(path
, context
, exceptions
); 
1728 static ImageLoader
* loadPhase2(const char* path
, const LoadContext
& context
,  
1729                                                            const char* const frameworkPaths
[], const char* const libraryPaths
[],  
1730                                                            std::vector
<const char*>* exceptions
); // forward reference 
1733 // expand @ variables 
1734 static ImageLoader
* loadPhase3(const char* path
, const LoadContext
& context
, std::vector
<const char*>* exceptions
) 
1736         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1737         ImageLoader
* image 
= NULL
; 
1738         if ( strncmp(path
, "@executable_path/", 17) == 0 ) { 
1739                 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305 
1740                 if ( sMainExecutableIsSetuid 
) { 
1741                         throwf("unsafe use of @executable_path in %s with setuid binary", context
.origin
); 
1743                 // handle @executable_path path prefix 
1744                 const char* executablePath 
= sExecPath
; 
1745                 char newPath
[strlen(executablePath
) + strlen(path
)]; 
1746                 strcpy(newPath
, executablePath
); 
1747                 char* addPoint 
= strrchr(newPath
,'/'); 
1748                 if ( addPoint 
!= NULL 
) 
1749                         strcpy(&addPoint
[1], &path
[17]); 
1751                         strcpy(newPath
, &path
[17]); 
1752                 image 
= loadPhase4(newPath
, context
, exceptions
); 
1753                 if ( image 
!= NULL 
)  
1756                 // perhaps main executable path is a sym link, find realpath and retry 
1757                 char resolvedPath
[PATH_MAX
]; 
1758                 if ( realpath(sExecPath
, resolvedPath
) != NULL 
) { 
1759                         char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
1760                         strcpy(newRealPath
, resolvedPath
); 
1761                         char* addPoint 
= strrchr(newRealPath
,'/'); 
1762                         if ( addPoint 
!= NULL 
) 
1763                                 strcpy(&addPoint
[1], &path
[17]); 
1765                                 strcpy(newRealPath
, &path
[17]); 
1766                         image 
= loadPhase4(newRealPath
, context
, exceptions
); 
1767                         if ( image 
!= NULL 
)  
1771         else if ( (strncmp(path
, "@loader_path/", 13) == 0) && (context
.origin 
!= NULL
) ) { 
1772                 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305 
1773                 if ( sMainExecutableIsSetuid 
&& (strcmp(context
.origin
, sExecPath
) == 0) ) 
1774                         throwf("unsafe use of @loader_path in %s with setuid binary", context
.origin
); 
1776                 // handle @loader_path path prefix 
1777                 char newPath
[strlen(context
.origin
) + strlen(path
)]; 
1778                 strcpy(newPath
, context
.origin
); 
1779                 char* addPoint 
= strrchr(newPath
,'/'); 
1780                 if ( addPoint 
!= NULL 
) 
1781                         strcpy(&addPoint
[1], &path
[13]); 
1783                         strcpy(newPath
, &path
[13]); 
1784                 image 
= loadPhase4(newPath
, context
, exceptions
); 
1785                 if ( image 
!= NULL 
)  
1788                 // perhaps loader path is a sym link, find realpath and retry 
1789                 char resolvedPath
[PATH_MAX
]; 
1790                 if ( realpath(context
.origin
, resolvedPath
) != NULL 
) { 
1791                         char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
1792                         strcpy(newRealPath
, resolvedPath
); 
1793                         char* addPoint 
= strrchr(newRealPath
,'/'); 
1794                         if ( addPoint 
!= NULL 
) 
1795                                 strcpy(&addPoint
[1], &path
[13]); 
1797                                 strcpy(newRealPath
, &path
[13]); 
1798                         image 
= loadPhase4(newRealPath
, context
, exceptions
); 
1799                         if ( image 
!= NULL 
)  
1803         else if ( context
.implicitRPath 
|| (strncmp(path
, "@rpath/", 7) == 0) ) { 
1804                 const char* trailingPath 
= (strncmp(path
, "@rpath/", 7) == 0) ? &path
[7] : path
; 
1805                 // substitute @rpath with all -rpath paths up the load chain 
1806                 for(const ImageLoader::RPathChain
* rp
=context
.rpath
; rp 
!= NULL
; rp
=rp
->next
) { 
1807                         if (rp
->paths 
!= NULL 
) { 
1808                                 for(std::vector
<const char*>::iterator it
=rp
->paths
->begin(); it 
!= rp
->paths
->end(); ++it
) { 
1809                                         const char* anRPath 
= *it
; 
1810                                         char newPath
[strlen(anRPath
) + strlen(trailingPath
)+2]; 
1811                                         strcpy(newPath
, anRPath
); 
1812                                         strcat(newPath
, "/");  
1813                                         strcat(newPath
, trailingPath
);  
1814                                         image 
= loadPhase4(newPath
, context
, exceptions
); 
1815                                         if ( image 
!= NULL 
)  
1821                 // substitute @rpath with LD_LIBRARY_PATH 
1822                 if ( sEnv
.LD_LIBRARY_PATH 
!= NULL 
) { 
1823                         image 
= loadPhase2(trailingPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, exceptions
); 
1824                         if ( image 
!= NULL 
) 
1828                 // if this is the "open" pass, don't try to open @rpath/... as a relative path 
1829                 if ( (exceptions 
!= NULL
) && (trailingPath 
!= path
) ) 
1832         else if ( sMainExecutableIsSetuid 
&& (path
[0] != '/') ) { 
1833                 throwf("unsafe use of relative rpath %s in %s with setuid binary", path
, context
.origin
); 
1836         return loadPhase4(path
, context
, exceptions
); 
1841 static ImageLoader
* loadPhase2(const char* path
, const LoadContext
& context
,  
1842                                                            const char* const frameworkPaths
[], const char* const libraryPaths
[],  
1843                                                            std::vector
<const char*>* exceptions
) 
1845         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1846         ImageLoader
* image 
= NULL
; 
1847         const char* frameworkPartialPath 
= getFrameworkPartialPath(path
); 
1848         if ( frameworkPaths 
!= NULL 
) { 
1849                 if ( frameworkPartialPath 
!= NULL 
) { 
1850                         const int frameworkPartialPathLen 
= strlen(frameworkPartialPath
); 
1851                         for(const char* const* fp 
= frameworkPaths
; *fp 
!= NULL
; ++fp
) { 
1852                                 char npath
[strlen(*fp
)+frameworkPartialPathLen
+8]; 
1855                                 strcat(npath
, frameworkPartialPath
); 
1856                                 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath); 
1857                                 image 
= loadPhase4(npath
, context
, exceptions
); 
1858                                 if ( image 
!= NULL 
) 
1863         if ( libraryPaths 
!= NULL 
) { 
1864                 const char* libraryLeafName 
= getLibraryLeafName(path
); 
1865                 const int libraryLeafNameLen 
= strlen(libraryLeafName
); 
1866                 for(const char* const* lp 
= libraryPaths
; *lp 
!= NULL
; ++lp
) { 
1867                         char libpath
[strlen(*lp
)+libraryLeafNameLen
+8]; 
1868                         strcpy(libpath
, *lp
); 
1869                         strcat(libpath
, "/"); 
1870                         strcat(libpath
, libraryLeafName
); 
1871                         //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath); 
1872                         image 
= loadPhase4(libpath
, context
, exceptions
); 
1873                         if ( image 
!= NULL 
) 
1880 // try search overrides and fallbacks 
1881 static ImageLoader
* loadPhase1(const char* path
, const LoadContext
& context
, std::vector
<const char*>* exceptions
) 
1883         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1884         ImageLoader
* image 
= NULL
; 
1886         // handle LD_LIBRARY_PATH environment variables that force searching 
1887         if ( context
.useLdLibraryPath 
&& (sEnv
.LD_LIBRARY_PATH 
!= NULL
) ) { 
1888                 image 
= loadPhase2(path
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, exceptions
); 
1889                 if ( image 
!= NULL 
) 
1893         // handle DYLD_ environment variables that force searching 
1894         if ( context
.useSearchPaths 
&& ((sEnv
.DYLD_FRAMEWORK_PATH 
!= NULL
) || (sEnv
.DYLD_LIBRARY_PATH 
!= NULL
)) ) { 
1895                 image 
= loadPhase2(path
, context
, sEnv
.DYLD_FRAMEWORK_PATH
, sEnv
.DYLD_LIBRARY_PATH
, exceptions
); 
1896                 if ( image 
!= NULL 
) 
1901         image 
= loadPhase3(path
, context
, exceptions
); 
1902         if ( image 
!= NULL 
) 
1905         // try fallback paths during second time (will open file) 
1906         if ( !context
.dontLoad  
&& (exceptions 
!= NULL
) && ((sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
!= NULL
) || (sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
!= NULL
)) ) { 
1907                 image 
= loadPhase2(path
, context
, sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
, sEnv
.DYLD_FALLBACK_LIBRARY_PATH
, exceptions
); 
1908                 if ( image 
!= NULL 
) 
1915 // try root substitutions 
1916 static ImageLoader
* loadPhase0(const char* path
, const LoadContext
& context
, std::vector
<const char*>* exceptions
) 
1918         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
1920         // handle DYLD_ROOT_PATH which forces absolute paths to use a new root 
1921         if ( (sEnv
.DYLD_ROOT_PATH 
!= NULL
) && (path
[0] == '/') ) { 
1922                 for(const char* const* rootPath 
= sEnv
.DYLD_ROOT_PATH 
; *rootPath 
!= NULL
; ++rootPath
) { 
1923                         char newPath
[strlen(*rootPath
) + strlen(path
)+2]; 
1924                         strcpy(newPath
, *rootPath
); 
1925                         strcat(newPath
, path
); 
1926                         ImageLoader
* image 
= loadPhase1(newPath
, context
, exceptions
); 
1927                         if ( image 
!= NULL 
) 
1933         return loadPhase1(path
, context
, exceptions
); 
1937 // Given all the DYLD_ environment variables, the general case for loading libraries 
1938 // is that any given path expands into a list of possible locations to load.  We 
1939 // also must take care to ensure two copies of the "same" library are never loaded. 
1941 // The algorithm used here is that there is a separate function for each "phase" of the 
1942 // path expansion.  Each phase function calls the next phase with each possible expansion 
1943 // of that phase.  The result is the last phase is called with all possible paths.   
1945 // To catch duplicates the algorithm is run twice.  The first time, the last phase checks 
1946 // the path against all loaded images.  The second time, the last phase calls open() on  
1947 // the path.  Either time, if an image is found, the phases all unwind without checking 
1950 ImageLoader
* load(const char* path
, const LoadContext
& context
) 
1952         //dyld::log("%s(%s)\n", __func__ , path); 
1953         char realPath
[PATH_MAX
]; 
1954         // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match 
1955         if ( context
.useSearchPaths 
&& ( gLinkContext
.imageSuffix 
!= NULL
) ) { 
1956                 if ( realpath(path
, realPath
) != NULL 
) 
1960         // try all path permutations and check against existing loaded images 
1961         ImageLoader
* image 
= loadPhase0(path
, context
, NULL
); 
1962         if ( image 
!= NULL 
) 
1965         // try all path permutations and try open() until first sucesss 
1966         std::vector
<const char*> exceptions
; 
1967         image 
= loadPhase0(path
, context
, &exceptions
); 
1968         if ( image 
!= NULL 
) 
1970         else if ( exceptions
.size() == 0 ) 
1971                 throw "image not found"; 
1973                 const char* msgStart 
= "no suitable image found.  Did find:"; 
1974                 const char* delim 
= "\n\t"; 
1975                 size_t allsizes 
= strlen(msgStart
)+8; 
1976                 for (unsigned int i
=0; i 
< exceptions
.size(); ++i
)  
1977                         allsizes 
+= (strlen(exceptions
[i
]) + strlen(delim
)); 
1978                 char* fullMsg 
= new char[allsizes
]; 
1979                 strcpy(fullMsg
, msgStart
); 
1980                 for (unsigned int i
=0; i 
< exceptions
.size(); ++i
) { 
1981                         strcat(fullMsg
, delim
); 
1982                         strcat(fullMsg
, exceptions
[i
]); 
1983                         free((void*)exceptions
[i
]); 
1985                 throw (const char*)fullMsg
; 
1992 #if DYLD_SHARED_CACHE_SUPPORT 
1995 // hack until dyld no longer needs to run on Leopard kernels that don't have new shared region syscall 
1996 static bool newSharedRegionSyscallAvailable() 
1999         size_t buffer_size 
= sizeof(shreg_version
); 
2000         if ( sysctlbyname("vm.shared_region_version", &shreg_version
, &buffer_size
, NULL
, 0) == 0 ) { 
2001            if ( shreg_version 
== 3 )  
2008 static int __attribute__((noinline
)) _shared_region_check_np(uint64_t* start_address
) 
2010         if ( (gLinkContext
.sharedRegionMode 
== ImageLoader::kUseSharedRegion
) && newSharedRegionSyscallAvailable() )  
2011                 return syscall(294, start_address
); 
2016 static int __attribute__((noinline
)) _shared_region_map_np(int fd
, uint32_t count
, const shared_file_mapping_np mappings
[]) 
2019         if ( (gLinkContext
.sharedRegionMode 
== ImageLoader::kUseSharedRegion
) && newSharedRegionSyscallAvailable() ) { 
2020                 return syscall(295, fd
, count
, mappings
); 
2023         // remove the shared region sub-map 
2024 #if __ppc__ || __i386__ 
2025         vm_address_t addr 
= (vm_address_t
)0x90000000; 
2026         vm_deallocate(mach_task_self(), addr
, 0x20000000); 
2027 #elif __ppc64__ || __x86_64__ 
2028         vm_address_t addr 
= (vm_address_t
)0x7FFF60000000; 
2029         vm_deallocate(mach_task_self(), addr
, 0x80000000); 
2032         // map cache just for this process with mmap() 
2033         bool failed 
= false; 
2034         const shared_file_mapping_np
* start 
= mappings
; 
2035         const shared_file_mapping_np
* end 
= &mappings
[count
]; 
2036         for (const shared_file_mapping_np
* p 
= start
; p 
< end
; ++p 
) { 
2037                 void* mmapAddress 
= (void*)(uintptr_t)(p
->sfm_address
); 
2038                 size_t size 
= p
->sfm_size
; 
2040                 if ( p
->sfm_init_prot 
& VM_PROT_EXECUTE 
) 
2041                         protection   
|= PROT_EXEC
; 
2042                 if ( p
->sfm_init_prot 
& VM_PROT_READ 
) 
2043                         protection   
|= PROT_READ
; 
2044                 if ( p
->sfm_init_prot 
& VM_PROT_WRITE 
) 
2045                         protection   
|= PROT_WRITE
; 
2046                 off_t offset 
= p
->sfm_file_offset
; 
2047                 mmapAddress 
= mmap(mmapAddress
, size
, protection
, MAP_FIXED 
| MAP_PRIVATE
, fd
, offset
); 
2048                 if ( mmap(mmapAddress
, size
, protection
, MAP_FIXED 
| MAP_PRIVATE
, fd
, offset
) != mmapAddress 
) 
2053                 gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
2057                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2058                 if ( gLinkContext
.verboseMapping 
)  
2059                         dyld::log("dyld: shared cached cannot be mapped\n"); 
2068         #define ARCH_NAME                       "ppc" 
2069         #define ARCH_NAME_ROSETTA       "rosetta" 
2070         #define ARCH_VALUE                      CPU_TYPE_POWERPC 
2071         #define ARCH_CACHE_MAGIC        "dyld_v1     ppc" 
2073         #define ARCH_NAME                       "ppc64" 
2074         #define ARCH_VALUE                      CPU_TYPE_POWERPC64 
2075         #define ARCH_CACHE_MAGIC        "dyld_v1   ppc64" 
2077         #define ARCH_NAME                       "i386" 
2078         #define ARCH_VALUE                      CPU_TYPE_I386 
2079         #define ARCH_CACHE_MAGIC        "dyld_v1    i386" 
2081         #define ARCH_NAME                       "x86_64" 
2082         #define ARCH_VALUE                      CPU_TYPE_X86_64 
2083         #define ARCH_CACHE_MAGIC        "dyld_v1  x86_64" 
2086 const void*     imMemorySharedCacheHeader() 
2088         return sSharedCache
; 
2091 int openSharedCacheFile() 
2094                 // rosetta cannot handle optimized _ppc cache, so it use _rosetta cache instead, rdar://problem/5495438 
2096                         return ::open(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_ROSETTA
, O_RDONLY
); 
2099                 return ::open(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
, O_RDONLY
); 
2102 static void mapSharedCache() 
2104         uint64_t cacheBaseAddress
; 
2105         // quick check if a cache is alreay mapped into shared region 
2106         if ( _shared_region_check_np(&cacheBaseAddress
) == 0 ) { 
2107                 sSharedCache 
= (dyld_cache_header
*)cacheBaseAddress
; 
2108                 // if we don't understand the currently mapped shared cache, then ignore 
2109                 if ( strcmp(sSharedCache
->magic
, ARCH_CACHE_MAGIC
) != 0 ) { 
2110                         sSharedCache 
= NULL
; 
2111                         if ( gLinkContext
.verboseMapping 
)  
2112                                 dyld::log("dyld: existing shared cached in memory is not compatible\n"); 
2116                 // <rdar://problem/5925940> Safe Boot should disable dyld shared cache 
2117                 // if we are in safe-boot mode and the cache was not made during this boot cycle, 
2118                 // delete the cache file and let it be regenerated  
2119                 uint32_t        safeBootValue 
= 0; 
2120                 size_t          safeBootValueSize 
= sizeof(safeBootValue
); 
2121                 if ( (sysctlbyname("kern.safeboot", &safeBootValue
, &safeBootValueSize
, NULL
, 0) == 0) && (safeBootValue 
!= 0) ) { 
2122                         // user booted machine in safe-boot mode 
2123                         struct stat dyldCacheStatInfo
; 
2124                         if ( ::stat(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
, &dyldCacheStatInfo
) == 0 ) { 
2125                                 struct timeval bootTimeValue
; 
2126                                 size_t bootTimeValueSize 
= sizeof(bootTimeValue
); 
2127                                 if ( (sysctlbyname("kern.boottime", &bootTimeValue
, &bootTimeValueSize
, NULL
, 0) == 0) && (bootTimeValue
.tv_sec 
!= 0) ) { 
2128                                         // if the cache file was created before this boot, then throw it away and let it rebuild itself 
2129                                         if ( dyldCacheStatInfo
.st_mtime 
< bootTimeValue
.tv_sec 
) { 
2130                                                 ::unlink(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
); 
2131                                                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2132                                                 gSharedCacheNotFound 
= true; 
2138                 // map in shared cache to shared region 
2139                 int fd 
= openSharedCacheFile(); 
2141                         uint8_t firstPage
[4096]; 
2142                         if ( ::read(fd
, firstPage
, 4096) == 4096 ) { 
2143                                 dyld_cache_header
* header 
= (dyld_cache_header
*)firstPage
; 
2144                                 if ( strcmp(header
->magic
, ARCH_CACHE_MAGIC
) == 0 ) { 
2145                                         const shared_file_mapping_np
* mappings 
= (shared_file_mapping_np
*)&firstPage
[header
->mappingOffset
]; 
2146                                         const shared_file_mapping_np
* const end 
= &mappings
[header
->mappingCount
]; 
2147                                         // validate that the cache file has not been truncated 
2148                                         bool goodCache 
= false; 
2149                                         struct stat stat_buf
; 
2150                                         if ( fstat(fd
, &stat_buf
) == 0 ) { 
2152                                                 for (const shared_file_mapping_np
* p 
= mappings
; p 
< end
; ++p
) { 
2153                                                         // rdar://problem/5694507 old update_dyld_shared_cache tool could make a cache file 
2154                                                         // that is not page aligned, but otherwise ok. 
2155                                                         if ( p
->sfm_file_offset
+p
->sfm_size 
> (uint64_t)(stat_buf
.st_size
+4095 & (-4096)) ) 
2160                                                 const shared_file_mapping_np
* mappings 
= (shared_file_mapping_np
*)&firstPage
[header
->mappingOffset
]; 
2161                                                 if (_shared_region_map_np(fd
, header
->mappingCount
, mappings
) == 0) { 
2162                                                         // sucessfully mapped cache into shared region 
2163                                                         sSharedCache 
= (dyld_cache_header
*)mappings
[0].sfm_address
; 
2167                                                 gSharedCacheNeedsUpdating 
= true; 
2168                                                 dyld::log("dyld: shared cached file is corrupt: " DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME 
"\n"); 
2172                                         gSharedCacheNeedsUpdating 
= true; 
2173                                         if ( gLinkContext
.verboseMapping 
)  
2174                                                 dyld::log("dyld: shared cached file is invalid\n"); 
2178                                 gSharedCacheNeedsUpdating 
= true; 
2179                                 if ( gLinkContext
.verboseMapping 
)  
2180                                         dyld::log("dyld: shared cached file cannot be read\n"); 
2185                         gSharedCacheNotFound 
= true; 
2186                         if ( gLinkContext
.verboseMapping 
)  
2187                                 dyld::log("dyld: shared cached file cannot be opened\n"); 
2191         // remember if dyld loaded at same address as when cache built 
2192         if ( sSharedCache 
!= NULL 
) { 
2193                 gLinkContext
.dyldLoadedAtSameAddressNeededBySharedCache 
= ((uintptr_t)(sSharedCache
->dyldBaseAddress
) == (uintptr_t)&_mh_dylinker_header
); 
2196         // tell gdb where the shared cache is 
2197         if ( sSharedCache 
!= NULL 
) { 
2198                 const shared_file_mapping_np
* const start 
= (shared_file_mapping_np
*)((uint8_t*)sSharedCache 
+ sSharedCache
->mappingOffset
); 
2199                 dyld_shared_cache_ranges
.sharedRegionsCount 
= sSharedCache
->mappingCount
; 
2200                 // only room to tell gdb about first four regions 
2201                 if ( dyld_shared_cache_ranges
.sharedRegionsCount 
> 4 ) 
2202                         dyld_shared_cache_ranges
.sharedRegionsCount 
= 4; 
2203                 if ( gLinkContext
.verboseMapping 
) { 
2204                         if ( gLinkContext
.sharedRegionMode 
== ImageLoader::kUseSharedRegion 
) 
2205                                 dyld::log("dyld: Mapping shared cache\n"); 
2206                         else if ( gLinkContext
.sharedRegionMode 
== ImageLoader::kUsePrivateSharedRegion 
) 
2207                                 dyld::log("dyld: Mapping private shared cache\n"); 
2209                 const shared_file_mapping_np
* const end 
= &start
[dyld_shared_cache_ranges
.sharedRegionsCount
]; 
2211                 for (const shared_file_mapping_np
* p 
= start
; p 
< end
; ++p
, ++index 
) { 
2212                         dyld_shared_cache_ranges
.ranges
[index
].start 
= p
->sfm_address
; 
2213                         dyld_shared_cache_ranges
.ranges
[index
].length 
= p
->sfm_size
; 
2214                         if ( gLinkContext
.verboseMapping 
) { 
2215                                 dyld::log("        0x%08llX->0x%08llX %s%s%s init=%x, max=%x\n", p
->sfm_address
, p
->sfm_address
+p
->sfm_size
-1, 
2216                                         ((p
->sfm_init_prot 
& VM_PROT_READ
) ? "read " : ""), 
2217                                         ((p
->sfm_init_prot 
& VM_PROT_WRITE
) ? "write " : ""), 
2218                                         ((p
->sfm_init_prot 
& VM_PROT_EXECUTE
) ? "execute " : ""),  p
->sfm_init_prot
, p
->sfm_max_prot
); 
2221                         // record if a non-writable and executable region is found in the R/W shared region 
2222                         // this is the __IMPORT segments.  dyld will turn write protection on and off as needed 
2223                         if ( (p
->sfm_init_prot 
== (VM_PROT_READ
|VM_PROT_EXECUTE
)) && ((p
->sfm_address 
& 0xF0000000) == 0xA0000000) ) { 
2224                                 sImportSegmentsStart 
= p
->sfm_address
; 
2225                                 sImportSegmentsSize 
= p
->sfm_size
; 
2226                                 makeSharedCacheImportSegmentsWritable(true); 
2233 #endif // #if DYLD_SHARED_CACHE_SUPPORT 
2237 // create when NSLinkModule is called for a second time on a bundle 
2238 ImageLoader
* cloneImage(ImageLoader
* image
) 
2240         const uint64_t offsetInFat 
= image
->getOffsetInFatFile(); 
2242         // open file (automagically closed when this function exits) 
2243         FileOpener 
file(image
->getPath()); 
2245         struct stat stat_buf
; 
2246         if ( fstat(file
.getFileDescriptor(), &stat_buf
) == -1) 
2249         // read first page of file 
2250         uint8_t firstPage
[4096]; 
2251         pread(file
.getFileDescriptor(), firstPage
, 4096, offsetInFat
); 
2253         // fat length is only used for sanity checking, since this image was already loaded once, just use upper bound 
2254         uint64_t lenInFat 
= stat_buf
.st_size 
- offsetInFat
; 
2256         // try mach-o loader 
2257         if ( isCompatibleMachO(firstPage
) ) { 
2258                 ImageLoader
* clone 
= new ImageLoaderMachO(image
->getPath(), file
.getFileDescriptor(), firstPage
, offsetInFat
, lenInFat
, stat_buf
, gLinkContext
); 
2259                 // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
2260                 if ( ! image
->isBundle() )  
2265         // try other file formats... 
2266         throw "can't clone image"; 
2270 ImageLoader
* loadFromMemory(const uint8_t* mem
, uint64_t len
, const char* moduleName
) 
2272         // if fat wrapper, find usable sub-file 
2273         const fat_header
* memStartAsFat 
= (fat_header
*)mem
; 
2274         uint64_t fileOffset 
= 0; 
2275         uint64_t fileLength 
= len
; 
2276         if ( memStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
2277                 if ( fatFindBest(memStartAsFat
, &fileOffset
, &fileLength
) ) { 
2278                         mem 
= &mem
[fileOffset
]; 
2282                         throw "no matching architecture in universal wrapper"; 
2287         if ( isCompatibleMachO(mem
) ) { 
2288                 ImageLoader
* image 
= new ImageLoaderMachO(moduleName
, (mach_header
*)mem
, len
, gLinkContext
); 
2289                 // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
2290                 if ( ! image
->isBundle() )  
2295         // try other file formats here... 
2297         // throw error about what was found 
2298         switch (*(uint32_t*)mem
) { 
2303                         throw "mach-o, but wrong architecture"; 
2305                 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",  
2306                         mem
[0], mem
[1], mem
[2], mem
[3], mem
[4], mem
[5], mem
[6],mem
[7]); 
2311 void registerAddCallback(ImageCallback func
) 
2313         // now add to list to get notified when any more images are added 
2314         sAddImageCallbacks
.push_back(func
); 
2316         // call callback with all existing images 
2317         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2318                 ImageLoader
* image 
= *it
; 
2319                 if ( image
->getState() >= dyld_image_state_bound 
&& image
->getState() < dyld_image_state_terminated 
) 
2320                         (*func
)(image
->machHeader(), image
->getSlide()); 
2324 void registerRemoveCallback(ImageCallback func
) 
2326         sRemoveImageCallbacks
.push_back(func
); 
2329 void clearErrorMessage() 
2331         error_string
[0] = '\0'; 
2334 void setErrorMessage(const char* message
) 
2336         // save off error message in global buffer for CrashReporter to find 
2337         strncpy(error_string
, message
, sizeof(error_string
)-1); 
2338         error_string
[sizeof(error_string
)-1] = '\0'; 
2341 const char* getErrorMessage() 
2343         return error_string
; 
2347 void  halt(const char* message
) 
2349         dyld::log("dyld: %s\n", message
); 
2350         setErrorMessage(message
); 
2351         strncpy(error_string
, message
, sizeof(error_string
)-1); 
2352         error_string
[sizeof(error_string
)-1] = '\0'; 
2353         dyld_fatal_error(error_string
); 
2357 uintptr_t bindLazySymbol(const mach_header
* mh
, uintptr_t* lazyPointer
) 
2359         uintptr_t result 
= 0; 
2360         // acquire read-lock on dyld's data structures 
2361 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved 
2362         if ( gLibSystemHelpers 
!= NULL 
)  
2363                 (*gLibSystemHelpers
->lockForReading
)(); 
2365         // lookup and bind lazy pointer and get target address 
2367                 ImageLoader
* target
; 
2369                 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer) 
2371                         target 
= dyld::findImageContainingAddressThreadSafe(lazyPointer
); 
2373                         target 
= dyld::findImageByMachHeader(mh
); 
2375                 // note, target should always be mach-o, because only mach-o lazy handler wired up to this 
2376                 target 
= dyld::findImageByMachHeader(mh
); 
2378                 if ( target 
== NULL 
) 
2379                         throwf("image not found for lazy pointer at %p", lazyPointer
); 
2380                 result 
= target
->doBindLazySymbol(lazyPointer
, gLinkContext
); 
2382         catch (const char* message
) { 
2383                 dyld::log("dyld: lazy symbol binding failed: %s\n", message
); 
2386         // release read-lock on dyld's data structures 
2388         if ( gLibSystemHelpers 
!= NULL 
)  
2389                 (*gLibSystemHelpers
->unlockForReading
)(); 
2391         // return target address to glue which jumps to it with real parameters restored 
2396 // SPI used by ZeroLink to lazy load bundles 
2397 void registerZeroLinkHandlers(BundleNotificationCallBack notify
, BundleLocatorCallBack locate
) 
2399         sBundleNotifier 
= notify
; 
2400         sBundleLocation 
= locate
; 
2403 void registerUndefinedHandler(UndefinedHandler handler
) 
2405         sUndefinedHandler 
= handler
; 
2408 static void undefinedHandler(const char* symboName
) 
2410         if ( sUndefinedHandler 
!= NULL 
) { 
2411                 (*sUndefinedHandler
)(symboName
); 
2415 static bool findExportedSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
2417         // try ZeroLink short cut to finding bundle which exports this symbol 
2418         if ( sBundleLocation 
!= NULL 
) { 
2419                 ImageLoader
* zlImage 
= (*sBundleLocation
)(name
); 
2420                 if ( zlImage 
== ((ImageLoader
*)(-1)) ) { 
2421                         // -1 is magic value that request symbol is in a bundle not yet linked into process 
2422                         // try calling handler to link in that symbol 
2423                         undefinedHandler(name
); 
2424                         // call locator again 
2425                         zlImage 
= (*sBundleLocation
)(name
); 
2427                 // if still not found, then ZeroLink has no idea where to find it 
2428                 if ( zlImage 
== ((ImageLoader
*)(-1)) )  
2430                 if ( zlImage 
!= NULL 
) { 
2431                         // ZeroLink cache knows where the symbol is 
2432                         if ( onlyInCoalesced 
) { 
2433                                 // but ZeroLink does not know about coalescing weak symbols, so ignore ZeroLink's hint when onlyInCoalesced==true 
2436                                 *sym 
= zlImage
->findExportedSymbol(name
, NULL
, false, image
); 
2437                                 if ( *sym 
!= NULL 
) { 
2444                         // ZeroLink says it is in some bundle already loaded, but not linked, walk them all 
2445                         const unsigned int imageCount 
= sAllImages
.size(); 
2446                         for(unsigned int i
=0; i 
< imageCount
; ++i
){ 
2447                                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2448                                 if ( anImage
->isBundle() && !anImage
->hasHiddenExports() ) { 
2449                                         //dyld::log("dyld: search for %s in %s\n", name, anImage->getPath()); 
2450                                         *sym 
= anImage
->findExportedSymbol(name
, NULL
, false, image
); 
2451                                         if ( *sym 
!= NULL 
) { 
2459         // search all images in order 
2460         const ImageLoader
* firstWeakImage 
= NULL
; 
2461         const ImageLoader::Symbol
* firstWeakSym 
= NULL
; 
2462         const unsigned int imageCount 
= sAllImages
.size(); 
2463         for(unsigned int i
=0; i 
< imageCount
; ++i
) { 
2464                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2465                 // the use of inserted libraries alters search order 
2466                 // so that inserted libraries are found before the main executable 
2467                 if ( sInsertedDylibCount 
> 0 ) { 
2468                         if ( i 
< sInsertedDylibCount 
) 
2469                                 anImage 
= sAllImages
[i
+1]; 
2470                         else if ( i 
== sInsertedDylibCount 
) 
2471                                 anImage 
= sAllImages
[0]; 
2473                 if ( ! anImage
->hasHiddenExports() && (!onlyInCoalesced 
|| anImage
->hasCoalescedExports()) ) { 
2474                         *sym 
= anImage
->findExportedSymbol(name
, NULL
, false, image
); 
2475                         if ( *sym 
!= NULL 
) { 
2476                                 // if weak definition found, record first one found 
2477                                 if ( ((*image
)->getExportedSymbolInfo(*sym
) & ImageLoader::kWeakDefinition
) != 0 ) { 
2478                                         if ( firstWeakImage 
== NULL 
) { 
2479                                                 firstWeakImage 
= *image
; 
2480                                                 firstWeakSym 
= *sym
; 
2484                                         // found non-weak, so immediately return with it 
2490         if ( firstWeakSym 
!= NULL 
) { 
2491                 // found a weak definition, but no non-weak, so return first weak found 
2492                 *sym 
= firstWeakSym
; 
2493                 *image 
= firstWeakImage
; 
2500 bool flatFindExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
2502         return findExportedSymbol(name
, false, sym
, image
); 
2505 bool findCoalescedExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
2507         return findExportedSymbol(name
, true, sym
, image
); 
2511 bool flatFindExportedSymbolWithHint(const char* name
, const char* librarySubstring
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
2513         // search all images in order 
2514         const unsigned int imageCount 
= sAllImages
.size(); 
2515         for(unsigned int i
=0; i 
< imageCount
; ++i
){ 
2516                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2517                 // only look at images whose paths contain the hint string (NULL hint string is wildcard) 
2518                 if ( ! anImage
->isBundle() && ((librarySubstring
==NULL
) || (strstr(anImage
->getPath(), librarySubstring
) != NULL
)) ) { 
2519                         *sym 
= anImage
->findExportedSymbol(name
, NULL
, false, image
); 
2520                         if ( *sym 
!= NULL 
) { 
2528 static ImageLoader::MappedRegion
* getMappedRegions(ImageLoader::MappedRegion
* regions
) 
2530         ImageLoader::MappedRegion
* end 
= regions
; 
2531         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2532                 (*it
)->getMappedRegions(end
); 
2537 void registerImageStateSingleChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
) 
2539         // mark the image that the handler is in as never-unload because dyld has a reference into it 
2540         ImageLoader
* handlerImage 
= findImageContainingAddress((void*)handler
); 
2541         if ( handlerImage 
!= NULL 
) 
2542                 handlerImage
->setNeverUnload(); 
2544         // add to list of handlers 
2545         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
2546         if ( handlers 
!= NULL 
) { 
2547                 handlers
->push_back(handler
); 
2549                 // call callback with all existing images 
2550                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2551                         ImageLoader
* image 
= *it
; 
2552                         dyld_image_info  info
; 
2553                         info
.imageLoadAddress   
= image
->machHeader(); 
2554                         info
.imageFilePath              
= image
->getPath(); 
2555                         info
.imageFileModDate   
= image
->lastModified(); 
2556                         // should only call handler if state == image->state 
2557                         if ( image
->getState() == state 
) 
2558                                 (*handler
)(state
, 1, &info
); 
2559                         // ignore returned string, too late to do anything 
2564 void registerImageStateBatchChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
) 
2566         // mark the image that the handler is in as never-unload because dyld has a reference into it 
2567         ImageLoader
* handlerImage 
= findImageContainingAddress((void*)handler
); 
2568         if ( handlerImage 
!= NULL 
) 
2569                 handlerImage
->setNeverUnload(); 
2571         // add to list of handlers 
2572         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sBatchHandlers
); 
2573         if ( handlers 
!= NULL 
) { 
2574                 // insert at front, so that gdb handler is always last 
2575                 handlers
->insert(handlers
->begin(), handler
); 
2577                 // call callback with all existing images 
2579                         notifyBatchPartial(state
, true, handler
); 
2581                 catch (const char* msg
) { 
2582                         // ignore request to abort during registration 
2587 static ImageLoader
* libraryLocator(const char* libraryName
, bool search
, bool findDLL
, const char* origin
, const ImageLoader::RPathChain
* rpaths
) 
2589         dyld::LoadContext context
; 
2590         context
.useSearchPaths          
= search
; 
2591         context
.useLdLibraryPath        
= false; 
2592         context
.implicitRPath           
= false; 
2593         context
.matchByInstallName      
= false; 
2594         context
.dontLoad                        
= false; 
2595         context
.mustBeBundle            
= false; 
2596         context
.mustBeDylib                     
= true; 
2597         context
.findDLL                         
= findDLL
; 
2598         context
.origin                          
= origin
; 
2599         context
.rpath                           
= rpaths
; 
2600         return load(libraryName
, context
); 
2603 static const char* basename(const char* path
) 
2605     const char* last 
= path
; 
2606     for (const char* s 
= path
; *s 
!= '\0'; s
++) { 
2613 static void setContext(const struct mach_header
* mainExecutableMH
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[]) 
2615         gLinkContext
.loadLibrary                        
= &libraryLocator
; 
2616         gLinkContext
.terminationRecorder        
= &terminationRecorder
; 
2617         gLinkContext
.flatExportFinder           
= &flatFindExportedSymbol
; 
2618         gLinkContext
.coalescedExportFinder      
= &findCoalescedExportedSymbol
; 
2619         gLinkContext
.undefinedHandler           
= &undefinedHandler
; 
2620 #if IMAGE_NOTIFY_SUPPORT 
2621         gLinkContext
.addImageNeedingNotification 
= &addImageNeedingNotification
; 
2622         gLinkContext
.notifyAdding                       
= ¬ifyAdding
; 
2624         gLinkContext
.getAllMappedRegions        
= &getMappedRegions
; 
2625         gLinkContext
.bindingHandler                     
= NULL
; 
2626         gLinkContext
.notifySingle                       
= ¬ifySingle
; 
2627         gLinkContext
.notifyBatch                        
= ¬ifyBatch
; 
2628         gLinkContext
.removeImage                        
= &removeImage
; 
2629         gLinkContext
.registerDOFs                       
= ®isterDOFs
; 
2630         gLinkContext
.clearAllDepths                     
= &clearAllDepths
; 
2631         gLinkContext
.imageCount                         
= &imageCount
; 
2632         gLinkContext
.notifySharedCacheInvalid
= ¬ifySharedCacheInvalid
; 
2634         gLinkContext
.makeSharedCacheImportSegmentsWritable 
= &makeSharedCacheImportSegmentsWritable
; 
2636         gLinkContext
.setNewProgramVars          
= &setNewProgramVars
; 
2637 #if SUPPORT_OLD_CRT_INITIALIZATION 
2638         gLinkContext
.setRunInitialzersOldWay
= &setRunInitialzersOldWay
; 
2640         gLinkContext
.bindingOptions                     
= ImageLoader::kBindingNone
; 
2641         gLinkContext
.argc                                       
= argc
; 
2642         gLinkContext
.argv                                       
= argv
; 
2643         gLinkContext
.envp                                       
= envp
; 
2644         gLinkContext
.apple                                      
= apple
; 
2645         gLinkContext
.progname                           
= (argv
[0] != NULL
) ? basename(argv
[0]) : ""; 
2646         gLinkContext
.programVars
.mh                     
= mainExecutableMH
; 
2647         gLinkContext
.programVars
.NXArgcPtr      
= &gLinkContext
.argc
; 
2648         gLinkContext
.programVars
.NXArgvPtr      
= &gLinkContext
.argv
; 
2649         gLinkContext
.programVars
.environPtr     
= &gLinkContext
.envp
; 
2650         gLinkContext
.programVars
.__prognamePtr
=&gLinkContext
.progname
; 
2651         gLinkContext
.mainExecutable                     
= NULL
; 
2652         gLinkContext
.imageSuffix                        
= NULL
; 
2653         gLinkContext
.prebindUsage                       
= ImageLoader::kUseAllPrebinding
; 
2654         gLinkContext
.sharedRegionMode           
= ImageLoader::kUseSharedRegion
; 
2657 #if __ppc__ || __i386__ 
2660         int mib
[] = { CTL_KERN
, KERN_CLASSIC
, getpid() }; 
2662         size_t len 
= sizeof(int); 
2663         int ret 
= sysctl(mib
, 3, &is_classic
, &len
, NULL
, 0); 
2664         if ((ret 
!= -1) && is_classic
) { 
2665                 // we're running under Rosetta  
2673 static void printAllImages() 
2675         dyld::log("printAllImages()\n"); 
2676         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2677                 ImageLoader
* image 
= *it
; 
2678                 dyld_image_states imageState 
= image
->getState(); 
2679                 dyld::log("  state=%d, refcount=%d, name=%s\n", imageState
, image
->referenceCount(), image
->getShortName()); 
2680                 image
->printReferenceCounts(); 
2686 void link(ImageLoader
* image
, bool forceLazysBound
, const ImageLoader::RPathChain
& loaderRPaths
) 
2688         // add to list of known images.  This did not happen at creation time for bundles 
2689         if ( image
->isBundle() && !image
->isLinked() ) 
2692         // we detect root images as those not linked in yet  
2693         if ( !image
->isLinked() ) 
2694                 addRootImage(image
); 
2696         // notify ZeroLink of new image with concat of logical and physical name 
2697         if ( sBundleNotifier 
!= NULL 
&& image
->isBundle() ) { 
2698                 const int logicalLen 
= strlen(image
->getLogicalPath()); 
2699                 char logAndPhys
[strlen(image
->getPath())+logicalLen
+2]; 
2700                 strcpy(logAndPhys
, image
->getLogicalPath()); 
2701                 strcpy(&logAndPhys
[logicalLen
+1], image
->getPath()); 
2702                 (*sBundleNotifier
)(logAndPhys
, image
); 
2707                 image
->link(gLinkContext
, forceLazysBound
, false, loaderRPaths
); 
2709         catch (const char* msg
) { 
2710                 garbageCollectImages(); 
2714 #if OLD_GDB_DYLD_INTERFACE 
2715         // notify gdb that loaded libraries have changed 
2716         gdb_dyld_state_changed(); 
2721 void runInitializers(ImageLoader
* image
) 
2723         // do bottom up initialization 
2724         image
->runInitializers(gLinkContext
); 
2727 void garbageCollectImages() 
2729         // keep scanning list of images until entire list is scanned with no unreferenced images 
2730         bool mightBeUnreferencedImages 
= true; 
2731         while ( mightBeUnreferencedImages 
) { 
2732                 mightBeUnreferencedImages 
= false; 
2733                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2734                         ImageLoader
* image 
= *it
; 
2735                         if ( (image
->referenceCount() == 0) && !image
->neverUnload() && !image
->isBeingRemoved() ) { 
2737                                         //dyld::log("garbageCollectImages: deleting %s\n", image->getPath()); 
2738                                         image
->setBeingRemoved(); 
2742                                 catch (const char* msg
) { 
2743                                         dyld::warn("problem deleting image: %s\n", msg
); 
2745                                 mightBeUnreferencedImages 
= true; 
2754 static void preflight_finally(ImageLoader
* image
) 
2756         if ( image
->isBundle() ) { 
2757                 removeImageFromAllImages(image
->machHeader()); 
2760         sBundleBeingLoaded 
= NULL
; 
2761         dyld::garbageCollectImages(); 
2765 void preflight(ImageLoader
* image
, const ImageLoader::RPathChain
& loaderRPaths
) 
2768                 if ( image
->isBundle() )  
2769                         sBundleBeingLoaded 
= image
;     // hack 
2770                 image
->link(gLinkContext
, false, true, loaderRPaths
); 
2772         catch (const char* msg
) {        
2773                 preflight_finally(image
); 
2776         preflight_finally(image
); 
2779 static void loadInsertedDylib(const char* path
) 
2781         ImageLoader
* image 
= NULL
; 
2783                 LoadContext context
; 
2784                 context
.useSearchPaths          
= false; 
2785                 context
.useLdLibraryPath        
= false; 
2786                 context
.implicitRPath           
= false; 
2787                 context
.matchByInstallName      
= false; 
2788                 context
.dontLoad                        
= false; 
2789                 context
.mustBeBundle            
= false; 
2790                 context
.mustBeDylib                     
= true; 
2791                 context
.findDLL                         
= false; 
2792                 context
.origin                          
= NULL
; // can't use @loader_path with DYLD_INSERT_LIBRARIES 
2793                 context
.rpath                           
= NULL
; 
2794                 image 
= load(path
, context
); 
2795                 image
->setNeverUnload(); 
2798                 halt(dyld::mkstringf("could not load inserted library: %s\n", path
)); 
2803 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which 
2804 // sets up some registers and call this function. 
2806 // Returns address of main() in target program which __dyld_start jumps to 
2809 _main(const struct mach_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[]) 
2811         setContext(mainExecutableMH
, argc
, argv
, envp
, apple
); 
2813         // Pickup the pointer to the exec path. 
2814         sExecPath 
= apple
[0]; 
2815         bool ignoreEnvironmentVariables 
= false; 
2817         if ( isRosetta() ) { 
2818                 // under Rosetta (x86 side) 
2819                 // When a 32-bit ppc program is run under emulation on an Intel processor, 
2820                 // we want any i386 dylibs (e.g. any used by Rosetta) to not load in the shared region 
2821                 // because the shared region is being used by ppc dylibs 
2822                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2823                 ignoreEnvironmentVariables 
= true; 
2826         if ( sExecPath
[0] != '/' ) { 
2827                 // have relative path, use cwd to make absolute 
2828                 char cwdbuff
[MAXPATHLEN
]; 
2829             if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL 
) { 
2830                         // maybe use static buffer to avoid calling malloc so early... 
2831                         char* s 
= new char[strlen(cwdbuff
) + strlen(sExecPath
) + 2]; 
2834                         strcat(s
, sExecPath
); 
2838         uintptr_t result 
= 0; 
2839         sMainExecutableMachHeader 
= mainExecutableMH
; 
2840         sMainExecutableIsSetuid 
= issetugid(); 
2841         if ( sMainExecutableIsSetuid 
) 
2842                 pruneEnvironmentVariables(envp
, &apple
); 
2844                 checkEnvironmentVariables(envp
, ignoreEnvironmentVariables
); 
2845         if ( sEnv
.DYLD_PRINT_OPTS 
)  
2847         if ( sEnv
.DYLD_PRINT_ENV 
)  
2848                 printEnvironmentVariables(envp
); 
2850         // install gdb notifier 
2851         stateToHandlers(dyld_image_state_dependents_mapped
, sBatchHandlers
)->push_back(notifyGDB
); 
2852         // make initial allocations large enough that it is unlikely to need to be re-alloced 
2853         sAllImages
.reserve(200); 
2854         sImageRoots
.reserve(16); 
2855         sAddImageCallbacks
.reserve(4); 
2856         sRemoveImageCallbacks
.reserve(4); 
2857         sImageFilesNeedingTermination
.reserve(16); 
2858         sImageFilesNeedingDOFUnregistration
.reserve(8); 
2861                 // instantiate ImageLoader for main executable 
2862                 sMainExecutable 
= instantiateFromLoadedImage(mainExecutableMH
, mainExecutableSlide
, sExecPath
); 
2863                 sMainExecutable
->setNeverUnload(); 
2864                 gLinkContext
.mainExecutable 
= sMainExecutable
; 
2865                 // load shared cache 
2866                 checkSharedRegionDisable(); 
2867         #if DYLD_SHARED_CACHE_SUPPORT 
2868                 if ( gLinkContext
.sharedRegionMode 
!= ImageLoader::kDontUseSharedRegion 
) 
2871                 // load any inserted libraries 
2872                 if      ( sEnv
.DYLD_INSERT_LIBRARIES 
!= NULL 
) { 
2873                         for (const char* const* lib 
= sEnv
.DYLD_INSERT_LIBRARIES
; *lib 
!= NULL
; ++lib
)  
2874                                 loadInsertedDylib(*lib
); 
2876                 // record count of inserted libraries so that a flat search will look at  
2877                 // inserted libraries, then main, then others. 
2878                 sInsertedDylibCount 
= sAllImages
.size()-1; 
2880                 // link main executable 
2881                 gLinkContext
.linkingMainExecutable 
= true; 
2882                 link(sMainExecutable
, sEnv
.DYLD_BIND_AT_LAUNCH
, ImageLoader::RPathChain(NULL
, NULL
)); 
2883                 gLinkContext
.linkingMainExecutable 
= false; 
2884                 if ( sMainExecutable
->forceFlat() ) { 
2885                         gLinkContext
.bindFlat 
= true; 
2886                         gLinkContext
.prebindUsage 
= ImageLoader::kUseNoPrebinding
; 
2888                 result 
= (uintptr_t)sMainExecutable
->getMain(); 
2890                 // link any inserted libraries 
2891                 // do this after linking main executable so that any dylibs pulled in by inserted  
2892                 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses 
2893                 if ( sInsertedDylibCount 
> 0 ) { 
2894                         for(unsigned int i
=0; i 
< sInsertedDylibCount
; ++i
) { 
2895                                 ImageLoader
* image 
= sAllImages
[i
+1]; 
2896                                 link(image
, sEnv
.DYLD_BIND_AT_LAUNCH
, ImageLoader::RPathChain(NULL
, NULL
)); 
2900         #if SUPPORT_OLD_CRT_INITIALIZATION 
2901                 // Old way is to run initializers via a callback from crt1.o 
2902                 if ( ! gRunInitializersOldWay 
)  
2904                 initializeMainExecutable(); // run all initializers 
2906         catch(const char* message
) { 
2910                 dyld::log("dyld: launch failed\n");