Loading...
src/dyld.cpp dyld-239.4 dyld-360.17
--- dyld/dyld-239.4/src/dyld.cpp
+++ dyld/dyld-360.17/src/dyld.cpp
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -50,7 +50,9 @@
 #include <libkern/OSAtomic.h>
 #include <Availability.h>
 #include <System/sys/codesign.h>
+#include <System/sys/csr.h>
 #include <_simple.h>
+#include <os/lock_private.h>
 
 
 #ifndef CPU_SUBTYPE_ARM_V5TEJ
@@ -74,6 +76,10 @@
 #ifndef LC_DYLD_ENVIRONMENT
 	#define LC_DYLD_ENVIRONMENT			0x27
 #endif
+
+#ifndef CPU_SUBTYPE_X86_64_H
+	#define CPU_SUBTYPE_X86_64_H		((cpu_subtype_t) 8) 
+#endif	
 
 #ifndef VM_PROT_SLIDE   
     #define VM_PROT_SLIDE 0x20
@@ -92,16 +98,32 @@
 #if DYLD_SHARED_CACHE_SUPPORT
 #include "dyld_cache_format.h"
 #endif
-#if CORESYMBOLICATION_SUPPORT
-#include "coreSymbolicationDyldSupport.hpp"
+#include <coreSymbolicationDyldSupport.h>
+#if TARGET_IPHONE_SIMULATOR
+	extern "C" void xcoresymbolication_load_notifier(void *connection, uint64_t load_timestamp, const char *image_path, const struct mach_header *mach_header);
+	extern "C" void xcoresymbolication_unload_notifier(void *connection, uint64_t unload_timestamp, const char *image_path, const struct mach_header *mach_header);
+	#define coresymbolication_load_notifier(c, t, p, h) xcoresymbolication_load_notifier(c, t, p, h)
+	#define coresymbolication_unload_notifier(c, t, p, h) xcoresymbolication_unload_notifier(c, t, p, h)
 #endif
 
 // not libc header for send() syscall interface
 extern "C" ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
 
 
-// ARM is the only architecture that use cpu-sub-types
-#define CPU_SUBTYPES_SUPPORTED  __arm__
+// ARM and x86_64 are the only architecture that use cpu-sub-types
+#define CPU_SUBTYPES_SUPPORTED  ((__arm__ || __x86_64__) && !TARGET_IPHONE_SIMULATOR)
+
+#if __LP64__
+	#define LC_SEGMENT_COMMAND		LC_SEGMENT_64
+	#define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
+	#define macho_segment_command	segment_command_64
+	#define macho_section			section_64
+#else
+	#define LC_SEGMENT_COMMAND		LC_SEGMENT
+	#define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
+	#define macho_segment_command	segment_command
+	#define macho_section			section
+#endif
 
 
 
@@ -123,7 +145,7 @@
 extern "C" void dyld_fatal_error(const char* errString) __attribute__((noreturn));
 
 // magic linker symbol for start of dyld binary
-extern "C" void* __dso_handle;
+extern "C" const macho_header __dso_handle;
 
 
 //
@@ -211,30 +233,38 @@
 #endif
 static ImageLoader*					sMainExecutable = NULL;
 static bool							sProcessIsRestricted = false;
+static bool							sProcessRequiresLibraryValidation = false;
 static RestrictedReason				sRestrictedReason = restrictedNot;
-static unsigned int					sInsertedDylibCount = 0;
+static size_t						sInsertedDylibCount = 0;
 static std::vector<ImageLoader*>	sAllImages;
 static std::vector<ImageLoader*>	sImageRoots;
 static std::vector<ImageLoader*>	sImageFilesNeedingTermination;
 static std::vector<RegisteredDOF>	sImageFilesNeedingDOFUnregistration;
 static std::vector<ImageCallback>   sAddImageCallbacks;
 static std::vector<ImageCallback>   sRemoveImageCallbacks;
+static bool							sRemoveImageCallbacksInUse = false;
 static void*						sSingleHandlers[7][3];
 static void*						sBatchHandlers[7][3];
 static ImageLoader*					sLastImageByAddressCache;
 static EnvironmentVariables			sEnv;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 static const char*					sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
 static const char*					sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL };
+#else
+static const char*					sFrameworkFallbackPaths[] = { "/System/Library/Frameworks", NULL };
+static const char*					sLibraryFallbackPaths[] = { "/usr/local/lib", "/usr/lib", NULL };
+#endif
 static UndefinedHandler				sUndefinedHandler = NULL;
 static ImageLoader*					sBundleBeingLoaded = NULL;	// hack until OFI is reworked
 #if DYLD_SHARED_CACHE_SUPPORT
 static const dyld_cache_header*		sSharedCache = NULL;
 static long							sSharedCacheSlide = 0;
 static bool							sSharedCacheIgnoreInodeAndTimeStamp = false;
-#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
-	bool							gSharedCacheOverridden = false;
+	   bool							gSharedCacheOverridden = false;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
 	static const char*				sSharedCacheDir = IPHONE_DYLD_SHARED_CACHE_DIR;
 	static bool						sDylibsOverrideCache = false;
+	#define ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE 1024
 #else
 	static const char*				sSharedCacheDir = MACOSX_DYLD_SHARED_CACHE_DIR;
 #endif
@@ -250,9 +280,13 @@
 static int							sLogSocket = -1;
 #endif
 static bool							sFrameworksFoundAsDylibs = false;
- 
+#if __x86_64__
+static bool							sHaswell = false;
+#endif
 static std::vector<ImageLoader::DynamicReference> sDynamicReferences;
-	
+static OSSpinLock					sDynamicReferencesLock = 0;
+static bool							sLogToFile = false;
+static char							sLoadingCrashMessage[1024] = "dyld: launch, loading dependent libraries";
 
 //
 // The MappedRanges structure is used for fast address->image lookups.
@@ -368,7 +402,6 @@
 }
 
 
-//#define ALTERNATIVE_LOGFILE "/dev/console"
 #if !TARGET_IPHONE_SIMULATOR
 static int sLogfile = STDERR_FILENO;
 #endif
@@ -456,10 +489,11 @@
 
 void vlog(const char* format, va_list list)
 {
-	if ( useSyslog() ) 
+	if ( !sLogToFile && useSyslog() ) 
 		socket_syslogv(LOG_ERR, format, list);
-	else
+	else {
 		_simple_vdprintf(sLogfile, format, list);
+	}
 }
 
 void log(const char* format, ...)
@@ -491,25 +525,18 @@
 
 // <rdar://problem/8867781> control access to sAllImages through a lock 
 // because global dyld lock is not held during initialization phase of dlopen()
-static long sAllImagesLock = 0;
+// <rdar://problem/16145518> Use OSSpinLockLock to allow yielding
+static OSSpinLock sAllImagesLock = 0;
 
 static void allImagesLock()
 {
-    //dyld::log("allImagesLock()\n");
-	while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)0, (void*)1, (void**)&sAllImagesLock) ) {
-        // spin
-    }
+	OSSpinLockLock(&sAllImagesLock);
 }
 
 static void allImagesUnlock()
 {
-    //dyld::log("allImagesUnlock()\n");
-	while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)1, (void*)0, (void**)&sAllImagesLock) ) {
-        // spin
-   }
-}
-
-
+	OSSpinLockUnlock(&sAllImagesLock);
+}
 
 
 // utility class to assure files are closed when an exception is thrown
@@ -537,7 +564,7 @@
 
 static void	registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
 {
-	const unsigned int dofSectionCount = dofs.size();
+	const size_t dofSectionCount = dofs.size();
 	if ( !sEnv.DYLD_DISABLE_DOFS && (dofSectionCount != 0) ) {
 		int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
 		if ( fd < 0 ) {
@@ -573,7 +600,7 @@
 				}
 			}
 			else {
-				dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
+				//dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
 			}
 			close(fd);
 		}
@@ -676,20 +703,17 @@
 			}
 		}
 	}
-#if CORESYMBOLICATION_SUPPORT
-    // mach message csdlc about dynamically loaded images 
+    // mach message csdlc about dynamically unloaded images
 	if ( image->addFuncNotified() && (state == dyld_image_state_terminated) ) {
+		uint64_t loadTimestamp = mach_absolute_time();
 		if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
-			dyld::log("dyld core symbolication unload notification: %p %s\n", image->machHeader(), image->getPath());
+			dyld::log("dyld: coresymbolication_unload_notifier(%p, 0x%016llX, %p, %s)\n",
+					  dyld::gProcessInfo->coreSymbolicationShmPage, loadTimestamp, image->machHeader(), image->getPath());
 		}
 		if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
-			CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
-			if ( connection->is_valid_version() ) {
-				coresymbolication_unload_image(connection, image);
-			}
-		}
-	}
-#endif
+			coresymbolication_unload_notifier(dyld::gProcessInfo->coreSymbolicationShmPage, loadTimestamp, image->getPath(), image->machHeader());
+		}
+	}
 }
 
 
@@ -759,7 +783,7 @@
 				*end++ = sBundleBeingLoaded;
 		}
         const char* dontLoadReason = NULL;
-		unsigned int count = end-images;
+		uint32_t count = (uint32_t)(end-images);
 		if ( end != images ) {
 			// sort bottom up
 			qsort(images, count, sizeof(ImageLoader*), &imageSorter);
@@ -797,34 +821,22 @@
 					}
 				}
 			}
+			if ( (state == dyld_image_state_dependents_mapped) && ((dyld::gProcessInfo->coreSymbolicationShmPage != NULL) || sEnv.DYLD_PRINT_CS_NOTIFICATIONS) ) {
+				// mach message csdlc about loaded images
+				uint64_t loadTimestamp = mach_absolute_time();
+				for (unsigned j=0; j < count; ++j) {
+					if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
+						dyld::log("dyld: coresymbolication_load_notifier(%p, 0x%016llX, %p, %s)\n",
+								  dyld::gProcessInfo->coreSymbolicationShmPage, loadTimestamp, infos[j].imageLoadAddress, infos[j].imageFilePath);
+					}
+					coresymbolication_load_notifier(dyld::gProcessInfo->coreSymbolicationShmPage, loadTimestamp, infos[j].imageFilePath, infos[j].imageLoadAddress);
+				}
+			}
 		}
         allImagesUnlock();
         if ( dontLoadReason != NULL )
             throw dontLoadReason;
 	}
-#if CORESYMBOLICATION_SUPPORT
-	if ( state == dyld_image_state_rebased ) {
-		if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
-			for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-				dyld_image_states imageState = (*it)->getState();
-				if ( (imageState == dyld_image_state_rebased) || (orLater && (imageState > dyld_image_state_rebased)) )
-					dyld::log("dyld core symbolication load notification: %p %s\n", (*it)->machHeader(), (*it)->getPath());
-			}
-		}
-		if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
-			CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
-			if ( connection->is_valid_version() ) {
-				// This needs to be captured now
-				uint64_t load_timestamp = mach_absolute_time();
-				for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-					dyld_image_states imageState = (*it)->getState();
-					if ( (imageState == state) || (orLater && (imageState > state)) )
-						coresymbolication_load_image(connection, *it, load_timestamp);
-				}
-			}
-		}
-	}
-#endif
 }
 
 
@@ -861,7 +873,7 @@
 
 static unsigned int imageCount()
 {
-	return sAllImages.size();
+	return (unsigned int)sAllImages.size();
 }
 
 
@@ -896,17 +908,22 @@
 		return;
 	
 	// don't add if this combination already exists
+	OSSpinLockLock(&sDynamicReferencesLock);
 	for (std::vector<ImageLoader::DynamicReference>::iterator it=sDynamicReferences.begin(); it != sDynamicReferences.end(); ++it) {
-		if ( (it->from == from) && (it->to == to) )
+		if ( (it->from == from) && (it->to == to) ) {
+			OSSpinLockUnlock(&sDynamicReferencesLock);
 			return;
-	}
+		}
+	}
+
 	//dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName());
 	ImageLoader::DynamicReference t;
 	t.from = from;
 	t.to = to;
 	sDynamicReferences.push_back(t);
-}
-	
+	OSSpinLockUnlock(&sDynamicReferencesLock);
+}
+
 static void addImage(ImageLoader* image)
 {
 	// add to master list
@@ -976,9 +993,11 @@
 	// tell all registered remove image handlers about this
 	// do this before removing image from internal data structures so that the callback can query dyld about the image
 	if ( image->getState() >= dyld_image_state_bound ) {
+		sRemoveImageCallbacksInUse = true; // This only runs inside dyld's global lock, so ok to use a global for the in-use flag.
 		for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
 			(*it)(image->machHeader(), image->getSlide());
 		}
+		sRemoveImageCallbacksInUse = false;
 	}
 	
 	// notify 
@@ -998,7 +1017,9 @@
     allImagesUnlock();
 	
 	// remove from sDynamicReferences
-	sDynamicReferences.erase(std::remove_if(sDynamicReferences.begin(), sDynamicReferences.end(), RefUsesImage(image)), sDynamicReferences.end());
+	OSSpinLockLock(&sDynamicReferencesLock);
+		sDynamicReferences.erase(std::remove_if(sDynamicReferences.begin(), sDynamicReferences.end(), RefUsesImage(image)), sDynamicReferences.end());
+	OSSpinLockUnlock(&sDynamicReferencesLock);
 
 	// flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
 	if ( sLastImageByAddressCache == image )
@@ -1022,7 +1043,7 @@
 }
 
 
-void runImageTerminators(ImageLoader* image)
+void runImageStaticTerminators(ImageLoader* image)
 {
 	// if in termination list, pull it out and run terminator
 	bool mightBeMore;
@@ -1031,17 +1052,13 @@
 		for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
 			if ( *it == image ) {
 				sImageFilesNeedingTermination.erase(it);
+				if (gLogAPIs) dyld::log("dlclose(), running static terminators for %p %s\n", image, image->getShortName());
 				image->doTermination(gLinkContext);
 				mightBeMore = true;
 				break;
 			}
 		}
 	} while ( mightBeMore );
-
-	// <rdar://problem/7740779> dyld should directly call __cxa_finalize()
-	if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 8) )
-		(*gLibSystemHelpers->cxa_finalize)(image->machHeader());
-	
 }
 
 static void terminationRecorder(ImageLoader* image)
@@ -1054,6 +1071,21 @@
 	return sExecPath;
 }
 
+static void runAllStaticTerminators(void* extra)
+{
+	try {
+		const size_t imageCount = sImageFilesNeedingTermination.size();
+		for(size_t i=imageCount; i > 0; --i){
+			ImageLoader* image = sImageFilesNeedingTermination[i-1];
+			image->doTermination(gLinkContext);
+		}
+		sImageFilesNeedingTermination.clear();
+		notifyBatch(dyld_image_state_terminated);
+	}
+	catch (const char* msg) {
+		halt(msg);
+	}
+}
 
 void initializeMainExecutable()
 {
@@ -1062,25 +1094,24 @@
 
 	// run initialzers for any inserted dylibs
 	ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
-	const int rootCount = sImageRoots.size();
+	initializerTimes[0].count = 0;
+	const size_t rootCount = sImageRoots.size();
 	if ( rootCount > 1 ) {
-		for(int i=1; i < rootCount; ++i) {
-			initializerTimes[0].count = 0;
+		for(size_t i=1; i < rootCount; ++i) {
 			sImageRoots[i]->runInitializers(gLinkContext, initializerTimes[0]);
 		}
 	}
 	
 	// run initializers for main executable and everything it brings up 
-	initializerTimes[0].count = 0;
 	sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]);
 	
-	// register atexit() handler to run terminators in all loaded images when this process exits
+	// register cxa_atexit() handler to run static terminators in all loaded images when this process exits
 	if ( gLibSystemHelpers != NULL ) 
-		(*gLibSystemHelpers->cxa_atexit)(&runTerminators, NULL, NULL);
+		(*gLibSystemHelpers->cxa_atexit)(&runAllStaticTerminators, NULL, NULL);
 
 	// dump info if requested
 	if ( sEnv.DYLD_PRINT_STATISTICS )
-		ImageLoaderMachO::printStatistics(sAllImages.size(), initializerTimes[0]);
+		ImageLoaderMachO::printStatistics((unsigned int)sAllImages.size(), initializerTimes[0]);
 }
 
 bool mainExecutablePrebound()
@@ -1094,21 +1125,6 @@
 }
 
 
-void runTerminators(void* extra)
-{
-	try {
-		const unsigned int imageCount = sImageFilesNeedingTermination.size();
-		for(unsigned int i=imageCount; i > 0; --i){
-			ImageLoader* image = sImageFilesNeedingTermination[i-1];
-			image->doTermination(gLinkContext);
-		}
-		sImageFilesNeedingTermination.clear();
-		notifyBatch(dyld_image_state_terminated);
-	}
-	catch (const char* msg) {
-		halt(msg);
-	}
-}
 
 
 #if SUPPORT_VERSIONED_PATHS
@@ -1126,7 +1142,7 @@
 	//dyld::log("checkDylibOverride('%s')\n", dylibFile);
 	uint32_t altVersion;
  	char sysInstallName[PATH_MAX];
-	if ( getDylibVersionAndInstallname(dylibFile, &altVersion, sysInstallName) ) {
+	if ( getDylibVersionAndInstallname(dylibFile, &altVersion, sysInstallName) && (sysInstallName[0] =='/') ) {
 		//dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName);
 		uint32_t sysVersion;
 		if ( getDylibVersionAndInstallname(sysInstallName, &sysVersion, NULL) ) {
@@ -1174,8 +1190,8 @@
 {
 	//dyld::log("checkDylibOverridesInDir('%s')\n", dirPath);
 	char dylibPath[PATH_MAX];
-	int dirPathLen = strlen(dirPath);
-	strlcpy(dylibPath, dirPath, PATH_MAX); 
+	if ( strlcpy(dylibPath, dirPath, PATH_MAX) >= PATH_MAX )
+		return;
 	DIR* dirp = opendir(dirPath);
 	if ( dirp != NULL) {
 		dirent entry;
@@ -1185,9 +1201,9 @@
 				break;
 			if ( entp->d_type != DT_REG ) 
 				continue;
-			dylibPath[dirPathLen] = '/';     
-			dylibPath[dirPathLen+1] = '\0';     
-			if ( strlcat(dylibPath, entp->d_name, PATH_MAX) > PATH_MAX ) 
+			if ( strlcat(dylibPath, "/", PATH_MAX) >= PATH_MAX )
+				continue;
+			if ( strlcat(dylibPath, entp->d_name, PATH_MAX) >= PATH_MAX )
 				continue;
 			checkDylibOverride(dylibPath);
 		}
@@ -1200,8 +1216,8 @@
 {
 	//dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath);
 	char frameworkPath[PATH_MAX];
-	int dirPathLen = strlen(dirPath);
-	strlcpy(frameworkPath, dirPath, PATH_MAX); 
+	if ( strlcpy(frameworkPath, dirPath, PATH_MAX) >= PATH_MAX )
+		return;
 	DIR* dirp = opendir(dirPath);
 	if ( dirp != NULL) {
 		dirent entry;
@@ -1211,18 +1227,18 @@
 				break;
 			if ( entp->d_type != DT_DIR ) 
 				continue;
-			frameworkPath[dirPathLen] = '/';     
-			frameworkPath[dirPathLen+1] = '\0';
+			if ( strlcat(frameworkPath, "/", PATH_MAX) >= PATH_MAX )
+				continue;
 			int dirNameLen = strlen(entp->d_name);
 			if ( dirNameLen < 11 )
 				continue;
 			if ( strcmp(&entp->d_name[dirNameLen-10], ".framework") != 0 )
 				continue;
-			if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) > PATH_MAX ) 
+			if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) >= PATH_MAX )
 				continue;
-			if ( strlcat(frameworkPath, "/", PATH_MAX) > PATH_MAX ) 
+			if ( strlcat(frameworkPath, "/", PATH_MAX) >= PATH_MAX )
 				continue;
-			if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) > PATH_MAX ) 
+			if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) >= PATH_MAX )
 				continue;
 			frameworkPath[strlen(frameworkPath)-10] = '\0';
 			checkDylibOverride(frameworkPath);
@@ -1256,9 +1272,9 @@
 	char** result = new char*[colonCount+2];
 	for(const char* s=list; *s != '\0'; ++s) {
 		if (*s == ':') {
-			int len = s-start;
+			size_t len = s-start;
 			if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
-				int mainExecDirLen = strlen(mainExecutableDir);
+				size_t mainExecDirLen = strlen(mainExecutableDir);
 				char* str = new char[mainExecDirLen+len+1];
 				strcpy(str, mainExecutableDir);
 				strlcat(str, &start[13], mainExecDirLen+len+1);
@@ -1267,7 +1283,7 @@
 				result[index++] = str;
 			}
 			else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
-				int mainExecDirLen = strlen(mainExecutableDir);
+				size_t mainExecDirLen = strlen(mainExecutableDir);
 				char* str = new char[mainExecDirLen+len+1];
 				strcpy(str, mainExecutableDir);
 				strlcat(str, &start[17], mainExecDirLen+len+1);
@@ -1284,9 +1300,9 @@
 			}
 		}
 	}
-	int len = strlen(start);
+	size_t len = strlen(start);
 	if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
-		int mainExecDirLen = strlen(mainExecutableDir);
+		size_t mainExecDirLen = strlen(mainExecutableDir);
 		char* str = new char[mainExecDirLen+len+1];
 		strcpy(str, mainExecutableDir);
 		strlcat(str, &start[13], mainExecDirLen+len+1);
@@ -1294,7 +1310,7 @@
 		result[index++] = str;
 	}
 	else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
-		int mainExecDirLen = strlen(mainExecutableDir);
+		size_t mainExecDirLen = strlen(mainExecutableDir);
 		char* str = new char[mainExecDirLen+len+1];
 		strcpy(str, mainExecutableDir);
 		strlcat(str, &start[17], mainExecDirLen+len+1);
@@ -1559,6 +1575,18 @@
 		appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_FRAMEWORK_PATH);
 	}
 #endif
+#if !TARGET_IPHONE_SIMULATOR
+	else if ( (strcmp(key, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir == NULL) ) {
+		int fd = open(value, O_WRONLY | O_CREAT | O_APPEND, 0644);
+		if ( fd != -1 ) {
+			sLogfile = fd;
+			sLogToFile = true;
+		}
+		else {
+			dyld::log("dyld: could not open DYLD_PRINT_TO_FILE='%s', errno=%d\n", value, errno);
+		}
+	}
+#endif
 	else {
 		dyld::warn("unknown environment variable: %s\n", key);
 	}
@@ -1578,7 +1606,7 @@
 			{
 				const struct dylinker_command* envcmd = (struct dylinker_command*)cmd;
 				const char* keyEqualsValue = (char*)envcmd + envcmd->name.offset;
-				char mainExecutableDir[strlen(sExecPath)];
+				char mainExecutableDir[strlen(sExecPath)+2];
 				strcpy(mainExecutableDir, sExecPath);
 				char* lastSlash = strrchr(mainExecutableDir, '/');
 				if ( lastSlash != NULL)
@@ -1589,7 +1617,7 @@
 					if ( equals != NULL ) {
 						if ( strncmp(&equals[-5], "_PATH", 5) == 0 ) {
 							const char* value = &equals[1];
-							const int keyLen = equals-keyEqualsValue;
+							const size_t keyLen = equals-keyEqualsValue;
 							char key[keyLen+1];
 							strncpy(key, keyEqualsValue, keyLen);
 							key[keyLen] = '\0';
@@ -1693,29 +1721,62 @@
 	// disable framework and library fallback paths for setuid binaries rdar://problem/4589305
 	sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = NULL;
 	sEnv.DYLD_FALLBACK_LIBRARY_PATH = NULL;
-}
-
-
-static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
-{
-	const char* home = NULL;
+
+	if ( removedCount > 0 )
+		strlcat(sLoadingCrashMessage, ", ignoring DYLD_* env vars", sizeof(sLoadingCrashMessage));
+}
+
+static void defaultUninitializedFallbackPaths(const char* envp[])
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+	// default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
+	const char* home = _simple_getenv(envp, "HOME");;
+	if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
+		const char** fpaths = sFrameworkFallbackPaths;
+		if ( home == NULL )
+			removePathWithPrefix(fpaths, "$HOME");
+		else
+			paths_expand_roots(fpaths, "$HOME", home);
+		sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = fpaths;
+	}
+
+    // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
+	if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
+		const char** lpaths = sLibraryFallbackPaths;
+		if ( home == NULL )
+			removePathWithPrefix(lpaths, "$HOME");
+		else
+			paths_expand_roots(lpaths, "$HOME", home);
+		sEnv.DYLD_FALLBACK_LIBRARY_PATH = lpaths;
+	}
+#else
+	if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL )
+		sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sFrameworkFallbackPaths;
+
+	if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL )
+		sEnv.DYLD_FALLBACK_LIBRARY_PATH = sLibraryFallbackPaths;
+#endif
+}
+
+
+static void checkEnvironmentVariables(const char* envp[])
+{
 	const char** p;
 	for(p = envp; *p != NULL; p++) {
 		const char* keyEqualsValue = *p;
 	    if ( strncmp(keyEqualsValue, "DYLD_", 5) == 0 ) {
 			const char* equals = strchr(keyEqualsValue, '=');
-			if ( (equals != NULL) && !ignoreEnviron ) {
+			if ( equals != NULL ) {
+				strlcat(sLoadingCrashMessage, "\n", sizeof(sLoadingCrashMessage));
+				strlcat(sLoadingCrashMessage, keyEqualsValue, sizeof(sLoadingCrashMessage));
 				const char* value = &equals[1];
-				const int keyLen = equals-keyEqualsValue;
+				const size_t keyLen = equals-keyEqualsValue;
 				char key[keyLen+1];
 				strncpy(key, keyEqualsValue, keyLen);
 				key[keyLen] = '\0';
 				processDyldEnvironmentVariable(key, value, NULL);
 			}
 		}
-	    else if ( strncmp(keyEqualsValue, "HOME=", 5) == 0 ) {
-			home = &keyEqualsValue[5];
-		}
 		else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) {
 			const char* path = &keyEqualsValue[16];
 			sEnv.LD_LIBRARY_PATH = parseColonList(path, NULL);
@@ -1725,43 +1786,50 @@
 #if SUPPORT_LC_DYLD_ENVIRONMENT
 	checkLoadCommandEnvironmentVariables();
 #endif // SUPPORT_LC_DYLD_ENVIRONMENT	
-	
-	// default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
-	if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
-		const char** paths = sFrameworkFallbackPaths;
-		if ( home == NULL )
-			removePathWithPrefix(paths, "$HOME");
-		else
-			paths_expand_roots(paths, "$HOME", home);
-		sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = paths;
-	}
-
-	// default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
-	if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
-		const char** paths = sLibraryFallbackPaths;
-		if ( home == NULL ) 
-			removePathWithPrefix(paths, "$HOME");
-		else
-			paths_expand_roots(paths, "$HOME", home);
-		sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
-	}
 	
 	// <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together
 	if ( (gLinkContext.imageSuffix != NULL) && (gLinkContext.rootPaths != NULL) ) {
 		dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n");
 		gLinkContext.imageSuffix = NULL;
 	}
-	
-#if SUPPORT_VERSIONED_PATHS
-	checkVersionedPaths();
-#endif	
-}
-
-
-static void getHostInfo()
+}
+
+#if __x86_64__
+static bool isGCProgram(const macho_header* mh, uintptr_t slide)
+{
+	const uint32_t cmd_count = mh->ncmds;
+	const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
+	const struct load_command* cmd = cmds;
+	for (uint32_t i = 0; i < cmd_count; ++i) {
+		switch (cmd->cmd) {
+			case LC_SEGMENT_COMMAND:
+			{
+				const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+				if (strcmp(seg->segname, "__DATA") == 0) {
+					const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+					const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+					for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+						if (strncmp(sect->sectname, "__objc_imageinfo", 16) == 0) {
+							const uint32_t*  objcInfo = (uint32_t*)(sect->addr + slide);
+							return (objcInfo[1] & 6); // 6 = (OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC)
+						}
+					}
+				}
+			}
+			break;
+		}
+		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+	}
+	return false;
+}
+#endif
+static void getHostInfo(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide)
 {
 #if CPU_SUBTYPES_SUPPORTED
-#if __ARM_ARCH_7A__
+#if __ARM_ARCH_7K__
+	sHostCPU		= CPU_TYPE_ARM;
+	sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
+#elif __ARM_ARCH_7A__
 	sHostCPU		= CPU_TYPE_ARM;
 	sHostCPUsubtype = CPU_SUBTYPE_ARM_V7;
 #elif __ARM_ARCH_6K__
@@ -1773,9 +1841,6 @@
 #elif __ARM_ARCH_7S__
 	sHostCPU		= CPU_TYPE_ARM;
 	sHostCPUsubtype = CPU_SUBTYPE_ARM_V7S;
-#elif __ARM_ARCH_7K__
-	sHostCPU		= CPU_TYPE_ARM;
-	sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
 #else
 	struct host_basic_info info;
 	mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
@@ -1785,6 +1850,23 @@
 		throw "host_info() failed";
 	sHostCPU		= info.cpu_type;
 	sHostCPUsubtype = info.cpu_subtype;
+	mach_port_deallocate(mach_task_self(), hostPort);
+  #if __x86_64__
+	#if TARGET_IPHONE_SIMULATOR
+	  sHaswell = false;
+	#else
+	  sHaswell = (sHostCPUsubtype == CPU_SUBTYPE_X86_64_H);
+	  // <rdar://problem/18528074> x86_64h: Fall back to the x86_64 slice if an app requires GC.
+	  if ( sHaswell ) {
+		if ( isGCProgram(mainExecutableMH, mainExecutableSlide) ) {
+			// When running a GC program on a haswell machine, don't use and 'h slices
+			sHostCPUsubtype = CPU_SUBTYPE_X86_64_ALL;
+			sHaswell = false;
+			gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
+		}
+	  }
+	#endif
+  #endif
 #endif
 #endif
 }
@@ -1799,14 +1881,20 @@
 		if ( gLinkContext.verboseMapping )
 			dyld::warn("disabling shared region because main executable overlaps\n");
 	}
+#if __i386__
+	if ( sProcessIsRestricted ) {
+		// <rdar://problem/15280847> use private or no shared region for suid processes
+		gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
+	}
+#endif
 #endif
 	// iPhoneOS cannot run without shared region
 }
 
 bool validImage(const ImageLoader* possibleImage)
 {
-    const unsigned int imageCount = sAllImages.size();
-    for(unsigned int i=0; i < imageCount; ++i) {
+    const size_t imageCount = sAllImages.size();
+    for(size_t i=0; i < imageCount; ++i) {
         if ( possibleImage == sAllImages[i] ) {
             return true;
         }
@@ -1816,7 +1904,7 @@
 
 uint32_t getImageCount()
 {
-	return sAllImages.size();
+	return (uint32_t)sAllImages.size();
 }
 
 ImageLoader* getIndexedImage(unsigned int index)
@@ -1852,8 +1940,8 @@
 
 void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData)
 {
-	const unsigned int imageCount = sAllImages.size();
-	for(unsigned int i=0; i < imageCount; ++i) {
+	const size_t imageCount = sAllImages.size();
+	for(size_t i=0; i < imageCount; ++i) {
 		ImageLoader* anImage = sAllImages[i];
 		(*callback)(anImage, userData);
 	}
@@ -1861,8 +1949,8 @@
 
 ImageLoader* findLoadedImage(const struct stat& stat_buf)
 {
-	const unsigned int imageCount = sAllImages.size();
-	for(unsigned int i=0; i < imageCount; ++i){
+	const size_t imageCount = sAllImages.size();
+	for(size_t i=0; i < imageCount; ++i){
 		ImageLoader* anImage = sAllImages[i];
 		if ( anImage->statMatch(stat_buf) )
 			return anImage;
@@ -1873,7 +1961,7 @@
 // based on ANSI-C strstr()
 static const char* strrstr(const char* str, const char* sub) 
 {
-	const int sublen = strlen(sub);
+	const size_t sublen = strlen(sub);
 	for(const char* p = &str[strlen(str)]; p != str; --p) {
 		if ( strncmp(p, sub, sublen) == 0 )
 			return p;
@@ -1903,7 +1991,7 @@
 				const char* frameworkStart = &dirStart[1];
 				if ( dirStart == path )
 					--frameworkStart;
-				int len = dirDot - frameworkStart;
+				size_t len = dirDot - frameworkStart;
 				char framework[len+1];
 				strncpy(framework, frameworkStart, len);
 				framework[len] = '\0';
@@ -1966,11 +2054,11 @@
 	// armv7f can run: v7f, v7, v6, v5, and v4
 	{  CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
 
-	// armv7k can run: v7k, v6, v5, and v4
-	{  CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+	// armv7k can run: v7k
+	{  CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_END_OF_LIST },
 
 	// armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4
-	{  CPU_SUBTYPE_ARM_V7S, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+	{  CPU_SUBTYPE_ARM_V7S, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
 
 	// armv7 can run: v7, v6, v5, and v4
 	{  CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
@@ -1986,6 +2074,22 @@
 
 	// armv4 can run: v4
 	{  CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
+};
+#endif
+
+#if __x86_64__
+//      
+//     x86_64 sub-type lists
+//
+const int kX86_64_RowCount = 2;
+static const cpu_subtype_t kX86_64[kX86_64_RowCount][5] = {
+
+	// x86_64h can run: x86_64h, x86_64h(lib), x86_64(lib), and x86_64
+	{ CPU_SUBTYPE_X86_64_H, CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_H, CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_X86_64_ALL,  CPU_SUBTYPE_END_OF_LIST },
+
+	// x86_64 can run: x86_64(lib) and x86_64
+	{ CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_END_OF_LIST },
+
 };
 #endif
 
@@ -1999,6 +2103,14 @@
 			for (int i=0; i < kARM_RowCount ; ++i) {
 				if ( kARM[i][0] == subtype )
 					return kARM[i];
+			}
+			break;
+#endif
+#if __x86_64__
+		case CPU_TYPE_X86_64:
+			for (int i=0; i < kX86_64_RowCount ; ++i) {
+				if ( kX86_64[i][0] == subtype )
+					return kX86_64[i];
 			}
 			break;
 #endif
@@ -2051,6 +2163,15 @@
 #if __arm__
 				case CPU_TYPE_ARM:
 					if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_ARM_ALL ) {
+						*offset = OSSwapBigToHostInt32(archs[i].offset);
+						*len = OSSwapBigToHostInt32(archs[i].size);
+						return true;
+					}
+					break;
+#endif
+#if __x86_64__
+				case CPU_TYPE_X86_64:
+					if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_X86_64_ALL ) {
 						*offset = OSSwapBigToHostInt32(archs[i].offset);
 						*len = OSSwapBigToHostInt32(archs[i].size);
 						return true;
@@ -2179,7 +2300,7 @@
 
 
 #if DYLD_SHARED_CACHE_SUPPORT
-static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
+static bool findInSharedCacheImage(const char* path, bool searchByPath, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
 {
 	if ( sSharedCache != NULL ) {
 #if __MAC_OS_X_VERSION_MIN_REQUIRED	
@@ -2192,13 +2313,24 @@
 			stat_buf = &statb;
 		}
 #endif
+#if __IPHONE_OS_VERSION_MIN_REQUIRED	
+		uint64_t hash = 0;
+		for (const char* s=path; *s != '\0'; ++s)
+			hash += hash*4 + *s;
+#endif
+
 		// walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
 		const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
 		const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
+#if __IPHONE_OS_VERSION_MIN_REQUIRED	
+		const bool cacheHasHashInfo = (start->modTime == 0);
+#endif
 		for( const dyld_cache_image_info* p = start; p != end; ++p) {
 #if __IPHONE_OS_VERSION_MIN_REQUIRED	
 			// just check path
 			const char* aPath = (char*)sSharedCache + p->pathFileOffset;
+			if ( cacheHasHashInfo && (p->inode != hash) )
+				continue;
 			if ( strcmp(path, aPath) == 0 ) {
 				// found image in cache
 				*mh = (macho_header*)(p->address+sSharedCacheSlide);
@@ -2208,12 +2340,12 @@
 			}
 #elif __MAC_OS_X_VERSION_MIN_REQUIRED
 			// check mtime and inode first because it is fast
-			if ( sSharedCacheIgnoreInodeAndTimeStamp 
-				|| ( ((time_t)p->modTime == stat_buf->st_mtime) && ((ino_t)p->inode == stat_buf->st_ino) ) ) {
+			bool inodeMatch = ( ((time_t)p->modTime == stat_buf->st_mtime) && ((ino_t)p->inode == stat_buf->st_ino) );
+			if ( searchByPath || sSharedCacheIgnoreInodeAndTimeStamp || inodeMatch ) {
 				// mod-time and inode match an image in the shared cache, now check path
 				const char* aPath = (char*)sSharedCache + p->pathFileOffset;
 				bool cacheHit = (strcmp(path, aPath) == 0);
-				if ( ! cacheHit ) {
+				if ( inodeMatch && !cacheHit ) {
 					// path does not match install name of dylib in cache, but inode and mtime does match
 					// perhaps path is a symlink to the cached dylib
 					struct stat pathInCacheStatBuf;
@@ -2241,7 +2373,7 @@
 	const macho_header* mhInCache;
 	const char*			pathInCache;
 	long				slide;
-	return findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slide);
+	return findInSharedCacheImage(path, true, NULL, &mhInCache, &pathInCache, &slide);
 }
 
 #endif
@@ -2284,6 +2416,34 @@
 	return image;
 }
 
+#if TARGET_IPHONE_SIMULATOR	
+static bool isSimulatorBinary(const uint8_t* firstPage, const char* path)
+{
+	const macho_header* mh = (macho_header*)firstPage;
+	const uint32_t cmd_count = mh->ncmds;
+	const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
+	const struct load_command* const cmdsReadEnd = (struct load_command*)(((char*)mh)+4096);
+	const struct load_command* cmd = cmds;
+	for (uint32_t i = 0; i < cmd_count; ++i) {
+		switch (cmd->cmd) {
+			case LC_VERSION_MIN_IPHONEOS:
+			case LC_VERSION_MIN_TVOS:
+			case LC_VERSION_MIN_WATCHOS:
+				return true;
+			case LC_VERSION_MIN_MACOSX:
+				// grandfather in a few libSystem dylibs
+				if (strstr(path, "/usr/lib/system") || strstr(path, "/usr/lib/libSystem"))
+ 					return true;
+				return false;
+		}
+		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+		if ( cmd > cmdsReadEnd )
+			return true;
+	}
+	return false;
+}
+#endif
+
 // map in file and instantiate an ImageLoader
 static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char* path, const LoadContext& context)
 {
@@ -2337,7 +2497,18 @@
 			default:
 				throw "mach-o, but wrong filetype";
 		}
-		
+
+#if TARGET_IPHONE_SIMULATOR	
+	#if TARGET_OS_WATCH || TARGET_OS_TV
+		// disable error during bring up of these simulators
+	#else
+		// <rdar://problem/14168872> dyld_sim should restrict loading osx binaries
+		if ( !isSimulatorBinary(firstPage, path) ) {
+			throw "mach-o, but not built for iOS simulator";
+		}
+	#endif
+#endif
+
 		// instantiate an image
 		ImageLoader* image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
 		
@@ -2421,7 +2592,7 @@
 	const macho_header* mhInCache;
 	const char*			pathInCache;
 	long				slideInCache;
-	if ( findInSharedCacheImage(path, &stat_buf, &mhInCache, &pathInCache, &slideInCache) ) {
+	if ( findInSharedCacheImage(path, false, &stat_buf, &mhInCache, &pathInCache, &slideInCache) ) {
 		image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
 		return checkandAddImage(image, context);
 	}
@@ -2483,7 +2654,7 @@
 	const macho_header* mhInCache;
 	const char*			pathInCache;
 	long				slideInCache;
-	if ( findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
+	if ( findInSharedCacheImage(path, true, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
 		// see if this image in the cache was already loaded via a different path
 		for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
 			ImageLoader* anImage = *it;
@@ -2611,7 +2782,7 @@
 	ImageLoader* image = NULL;
 	if ( strncmp(path, "@executable_path/", 17) == 0 ) {
 		// executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305
-		if ( sProcessIsRestricted ) 
+		if ( sProcessIsRestricted && !sProcessRequiresLibraryValidation )
 			throwf("unsafe use of @executable_path in %s with restricted binary", context.origin);
 		// handle @executable_path path prefix
 		const char* executablePath = sExecPath;
@@ -2643,7 +2814,7 @@
 	}
 	else if ( (strncmp(path, "@loader_path/", 13) == 0) && (context.origin != NULL) ) {
 		// @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305
-		if ( sProcessIsRestricted && (strcmp(context.origin, sExecPath) == 0) )
+		if ( sProcessIsRestricted && (strcmp(context.origin, sExecPath) == 0) && !sProcessRequiresLibraryValidation )
 			throwf("unsafe use of @loader_path in %s with restricted binary", context.origin);
 		// handle @loader_path path prefix
 		char newPath[strlen(context.origin) + strlen(path)];
@@ -2707,7 +2878,7 @@
 		if ( (exceptions != NULL) && (trailingPath != path) )
 			return NULL;
 	}
-	else if (sProcessIsRestricted && (path[0] != '/' )) {
+	else if (sProcessIsRestricted && (path[0] != '/' ) && !sProcessRequiresLibraryValidation) {
 		throwf("unsafe use of relative rpath %s in %s with restricted binary", path, context.origin);
 	}
 	
@@ -2725,7 +2896,7 @@
 	const char* frameworkPartialPath = getFrameworkPartialPath(path);
 	if ( frameworkPaths != NULL ) {
 		if ( frameworkPartialPath != NULL ) {
-			const int frameworkPartialPathLen = strlen(frameworkPartialPath);
+			const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
 			for(const char* const* fp = frameworkPaths; *fp != NULL; ++fp) {
 				char npath[strlen(*fp)+frameworkPartialPathLen+8];
 				strcpy(npath, *fp);
@@ -2742,7 +2913,7 @@
 	// <rdar://problem/14160846> Some apps depend on frameworks being found via library paths
 	if ( (libraryPaths != NULL) && ((frameworkPartialPath == NULL) || sFrameworksFoundAsDylibs) ) {
 		const char* libraryLeafName = getLibraryLeafName(path);
-		const int libraryLeafNameLen = strlen(libraryLeafName);
+		const size_t libraryLeafNameLen = strlen(libraryLeafName);
 		for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) {
 			char libpath[strlen(*lp)+libraryLeafNameLen+8];
 			strcpy(libpath, *lp);
@@ -2815,6 +2986,16 @@
 	// try raw path
 	return loadPhase1(path, orgPath, context, exceptions);
 }
+
+#if DYLD_SHARED_CACHE_SUPPORT
+	static bool cacheablePath(const char* path) {
+		if (strncmp(path, "/usr/lib/", 9) == 0)
+			return true;
+		if (strncmp(path, "/System/Library/", 16) == 0)
+			return true;
+		return false;
+	}
+#endif
 
 //
 // Given all the DYLD_ environment variables, the general case for loading libraries
@@ -2853,19 +3034,44 @@
 	// try all path permutations and try open() until first success
 	std::vector<const char*> exceptions;
 	image = loadPhase0(path, orgPath, context, &exceptions);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT && !TARGET_IPHONE_SIMULATOR
+	// <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache
+	if ( (image == NULL) && cacheablePath(path) && !context.dontLoad ) {
+		char resolvedPath[PATH_MAX];
+		realpath(path, resolvedPath);
+		int myerr = errno;
+		// If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
+		if ( (myerr == ENOENT) || (myerr == 0) )
+		{
+			// see if this image is in shared cache
+			const macho_header* mhInCache;
+			const char*			pathInCache;
+			long				slideInCache;
+			if ( findInSharedCacheImage(resolvedPath, false, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
+				struct stat stat_buf;
+				bzero(&stat_buf, sizeof(stat_buf));
+				try {
+					image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
+					image = checkandAddImage(image, context);
+				}
+				catch (...) {
+					image = NULL;
+				}
+			}
+		}
+	}
+#endif
     CRSetCrashLogMessage2(NULL);
 	if ( image != NULL ) {
 		// <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
 		for (std::vector<const char*>::iterator it = exceptions.begin(); it != exceptions.end(); ++it) {
 			free((void*)(*it));
 		}
-#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
+#if DYLD_SHARED_CACHE_SUPPORT
 		// if loaded image is not from cache, but original path is in cache
 		// set gSharedCacheOverridden flag to disable some ObjC optimizations
-		if ( !gSharedCacheOverridden ) {
-			if ( !image->inSharedCache() && inSharedCache(path) ) {
-				gSharedCacheOverridden = true;
-			}
+		if ( !gSharedCacheOverridden && !image->inSharedCache() && image->isDylib() && cacheablePath(path) && inSharedCache(path) ) {
+			gSharedCacheOverridden = true;
 		}
 #endif
 		return image;
@@ -2881,11 +3087,11 @@
 		const char* msgStart = "no suitable image found.  Did find:";
 		const char* delim = "\n\t";
 		size_t allsizes = strlen(msgStart)+8;
-		for (unsigned int i=0; i < exceptions.size(); ++i) 
+		for (size_t i=0; i < exceptions.size(); ++i) 
 			allsizes += (strlen(exceptions[i]) + strlen(delim));
 		char* fullMsg = new char[allsizes];
 		strcpy(fullMsg, msgStart);
-		for (unsigned int i=0; i < exceptions.size(); ++i) {
+		for (size_t i=0; i < exceptions.size(); ++i) {
 			strcat(fullMsg, delim);
 			strcat(fullMsg, exceptions[i]);
 			free((void*)exceptions[i]);
@@ -2906,6 +3112,8 @@
 #elif __x86_64__
 	#define ARCH_NAME			"x86_64"
 	#define ARCH_CACHE_MAGIC	"dyld_v1  x86_64"
+	#define ARCH_NAME_H			"x86_64h"
+	#define ARCH_CACHE_MAGIC_H	"dyld_v1 x86_64h"
 #elif __ARM_ARCH_5TEJ__
 	#define ARCH_NAME			"armv5"
 	#define ARCH_CACHE_MAGIC	"dyld_v1   armv5"
@@ -2915,15 +3123,18 @@
 #elif __ARM_ARCH_7F__
 	#define ARCH_NAME			"armv7f"
 	#define ARCH_CACHE_MAGIC	"dyld_v1  armv7f"
+#elif __ARM_ARCH_7K__
+	#define ARCH_NAME			"armv7k"
+	#define ARCH_CACHE_MAGIC	"dyld_v1  armv7k"
 #elif __ARM_ARCH_7A__
 	#define ARCH_NAME			"armv7"
 	#define ARCH_CACHE_MAGIC	"dyld_v1   armv7"
 #elif __ARM_ARCH_7S__
 	#define ARCH_NAME			"armv7s"
 	#define ARCH_CACHE_MAGIC	"dyld_v1  armv7s"
-#elif __ARM_ARCH_7K__
-	#define ARCH_NAME			"armv7k"
-	#define ARCH_CACHE_MAGIC	"dyld_v1  armv7k"
+#elif __arm64__
+	#define ARCH_NAME			"arm64"
+	#define ARCH_CACHE_MAGIC	"dyld_v1   arm64"
 #endif
 
 
@@ -2936,7 +3147,7 @@
 
 
 static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[],
-												int codeSignatureMappingIndex, int slide, void* slideInfo, uint32_t slideInfoSize)
+												int codeSignatureMappingIndex, long slide, void* slideInfo, unsigned long slideInfoSize)
 {
 	// register code signature blob for whole dyld cache
 	if ( codeSignatureMappingIndex != -1 ) {
@@ -3029,13 +3240,63 @@
 	return sSharedCache;
 }
 
+const char* getStandardSharedCacheFilePath()
+{
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+	return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME;
+#else
+  #if __x86_64__
+	if ( sHaswell ) {
+		const char* path2 = MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_H;
+		struct stat statBuf;
+		if ( my_stat(path2, &statBuf) == 0 )
+			return path2;
+	}
+  #endif
+	return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME;
+#endif
+}
+
 int openSharedCacheFile()
 {
 	char path[MAXPATHLEN];
 	strlcpy(path, sSharedCacheDir, MAXPATHLEN);
 	strlcat(path, "/", MAXPATHLEN);
+#if __x86_64__
+	if ( sHaswell ) {
+		strlcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_H, MAXPATHLEN);
+		int fd = my_open(path, O_RDONLY, 0);
+		if ( fd != -1 ) {
+			if ( gLinkContext.verboseMapping ) 
+				dyld::log("dyld: Mapping%s shared cache from %s\n", (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion) ? " private": "", path);
+			return fd;
+		}
+		strlcpy(path, sSharedCacheDir, MAXPATHLEN);
+	}
+#endif
 	strlcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, MAXPATHLEN);
+	if ( gLinkContext.verboseMapping ) 
+		dyld::log("dyld: Mapping%s shared cache from %s\n", (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion) ? " private": "", path);
 	return my_open(path, O_RDONLY, 0);
+}
+
+
+static void getCacheBounds(uint32_t mappingsCount, const shared_file_mapping_np mappings[], uint64_t& lowAddress, uint64_t& highAddress)
+{
+	lowAddress = 0;
+	highAddress = 0;
+	for(uint32_t i=0; i < mappingsCount; ++i) {
+		if ( lowAddress == 0 ) {
+			lowAddress = mappings[i].sfm_address;
+			highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
+		}
+		else {
+			if ( mappings[i].sfm_address < lowAddress )
+				lowAddress = mappings[i].sfm_address;
+			if ( (mappings[i].sfm_address + mappings[i].sfm_size) > highAddress )
+				highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
+		}
+	}
 }
 
 static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappings[])
@@ -3068,26 +3329,15 @@
 	// else fall through to handle old style cache
 #endif
 	// get bounds of cache
-	uint64_t lowAddress = 0;
-	uint64_t highAddress = 0;
-	for(uint32_t i=0; i < mappingsCount; ++i) {
-		if ( lowAddress == 0 ) {
-			lowAddress = mappings[i].sfm_address;
-			highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
-		}
-		else {
-			if ( mappings[i].sfm_address < lowAddress )
-				lowAddress = mappings[i].sfm_address;
-			if ( (mappings[i].sfm_address + mappings[i].sfm_size) > highAddress )
-				highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
-		}
-	}
+	uint64_t lowAddress;
+	uint64_t highAddress;
+	getCacheBounds(mappingsCount, mappings, lowAddress, highAddress);
 	
 	// find slop space
 	const uint64_t space = (SHARED_REGION_BASE + SHARED_REGION_SIZE) - highAddress;
 	
 	// choose new random slide
-	long slide = (arc4random() % space) & (-4096);
+	long slide = dyld_page_trunc(arc4random() % space);
 	//dyld::log("slideSpace=0x%0llX\n", space);
 	//dyld::log("slide=0x%0lX\n", slide);
 	
@@ -3102,11 +3352,16 @@
 static void mapSharedCache()
 {
 	uint64_t cacheBaseAddress = 0;
-	// quick check if a cache is alreay mapped into shared region
+	// quick check if a cache is already mapped into shared region
 	if ( _shared_region_check_np(&cacheBaseAddress) == 0 ) {
 		sSharedCache = (dyld_cache_header*)cacheBaseAddress;
 		// if we don't understand the currently mapped shared cache, then ignore
-		if ( strcmp(sSharedCache->magic, ARCH_CACHE_MAGIC) != 0 ) {
+#if __x86_64__
+		const char* magic = (sHaswell ? ARCH_CACHE_MAGIC_H : ARCH_CACHE_MAGIC);
+#else
+		const char* magic = ARCH_CACHE_MAGIC;
+#endif
+		if ( strcmp(sSharedCache->magic, magic) != 0 ) {
 			sSharedCache = NULL;
 			if ( gLinkContext.verboseMapping ) {
 				dyld::log("dyld: existing shared cached in memory is not compatible\n");
@@ -3127,6 +3382,10 @@
 		// if cache has a uuid, copy it 
 		if ( header->mappingOffset >= 0x68 ) {
 			memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
+		}
+		// verbose logging
+		if ( gLinkContext.verboseMapping ) {
+			dyld::log("dyld: re-using existing shared cache mapping\n");
 		}
 	}
 	else {
@@ -3160,7 +3419,12 @@
 			uint8_t firstPages[8192];
 			if ( ::read(fd, firstPages, 8192) == 8192 ) {
 				dyld_cache_header* header = (dyld_cache_header*)firstPages;
-				if ( strcmp(header->magic, ARCH_CACHE_MAGIC) == 0 ) {
+		#if __x86_64__
+				const char* magic = (sHaswell ? ARCH_CACHE_MAGIC_H : ARCH_CACHE_MAGIC);
+		#else
+				const char* magic = ARCH_CACHE_MAGIC;
+		#endif
+				if ( strcmp(header->magic, magic) == 0 ) {
 					const dyld_cache_mapping_info* const fileMappingsStart = (dyld_cache_mapping_info*)&firstPages[header->mappingOffset];
 					const dyld_cache_mapping_info* const fileMappingsEnd = &fileMappingsStart[header->mappingCount];
 					shared_file_mapping_np	mappings[header->mappingCount+1]; // add room for code-sig 
@@ -3194,7 +3458,7 @@
 							}
 						}
 						// if shared cache is code signed, add a mapping for the code signature
-						uint32_t signatureSize = header->codeSignatureSize;
+						uint64_t signatureSize = header->codeSignatureSize;
 						// zero size in header means signature runs to end-of-file
 						if ( signatureSize == 0 )
 							signatureSize = stat_buf.st_size - header->codeSignatureOffset;
@@ -3202,7 +3466,11 @@
                             int linkeditMapping = mappingCount-1;
 							codeSignatureMappingIndex = mappingCount++;
 							mappings[codeSignatureMappingIndex].sfm_address		= mappings[linkeditMapping].sfm_address + mappings[linkeditMapping].sfm_size;
+#if __arm__ || __arm64__
+							mappings[codeSignatureMappingIndex].sfm_size		= (signatureSize+16383) & (-16384);
+#else
 							mappings[codeSignatureMappingIndex].sfm_size		= (signatureSize+4095) & (-4096);
+#endif
 							mappings[codeSignatureMappingIndex].sfm_file_offset	= header->codeSignatureOffset;
 							mappings[codeSignatureMappingIndex].sfm_max_prot	= VM_PROT_READ;
 							mappings[codeSignatureMappingIndex].sfm_init_prot	= VM_PROT_READ;
@@ -3228,7 +3496,17 @@
 							goodCache = false;
 						}
 					}
-#endif				
+#endif
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+					{
+						uint64_t lowAddress;
+						uint64_t highAddress;
+						getCacheBounds(mappingCount, mappings, lowAddress, highAddress);
+						if ( (highAddress-lowAddress) > SHARED_REGION_SIZE ) 
+							throw "dyld shared cache is too big to fit in shared region";
+					}
+#endif
+
 					if ( goodCache && (readWriteMappingIndex == -1) ) {
 						dyld::log("dyld: shared cached file is missing read/write mapping: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
 						goodCache = false;
@@ -3240,7 +3518,7 @@
 					if ( goodCache ) {
 						long cacheSlide = 0;
 						void* slideInfo = NULL;
-						uint32_t slideInfoSize = 0;
+						uint64_t slideInfoSize = 0;
 						// check if shared cache contains slid info
 						if ( header->slideInfoSize != 0 ) {
 							// <rdar://problem/8611968> don't slide shared cache if ASLR disabled (main executable didn't slide)
@@ -3256,6 +3534,12 @@
 								mappings[readWriteMappingIndex].sfm_init_prot |= VM_PROT_SLIDE;
 							}
 						}
+						if ( gLinkContext.verboseMapping ) {
+							dyld::log("dyld: calling _shared_region_map_and_slide_np() with regions:\n");
+							for (int i=0; i < mappingCount; ++i) {
+								dyld::log("   address=0x%08llX, size=0x%08llX, fileOffset=0x%08llX\n", mappings[i].sfm_address, mappings[i].sfm_size, mappings[i].sfm_file_offset);
+							}
+						}
 						if (_shared_region_map_and_slide_np(fd, mappingCount, mappings, codeSignatureMappingIndex, cacheSlide, slideInfo, slideInfoSize) == 0) {
 							// successfully mapped cache into shared region
 							sSharedCache = (dyld_cache_header*)mappings[0].sfm_address;
@@ -3268,6 +3552,9 @@
 							}
 						}
 						else {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+							throw "dyld shared cache could not be mapped";
+#endif
 							if ( gLinkContext.verboseMapping ) 
 								dyld::log("dyld: shared cached file could not be mapped\n");
 						}
@@ -3302,12 +3589,6 @@
 		// only room to tell gdb about first four regions
 		if ( dyld_shared_cache_ranges.sharedRegionsCount > 4 )
 			dyld_shared_cache_ranges.sharedRegionsCount = 4;
-		if ( gLinkContext.verboseMapping ) {
-			if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
-				dyld::log("dyld: Mapping shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
-			else if ( gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion )
-				dyld::log("dyld: Mapping private shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
-		}
 		const dyld_cache_mapping_info* const end = &start[dyld_shared_cache_ranges.sharedRegionsCount];
 		int index = 0;
 		for (const dyld_cache_mapping_info* p = start; p < end; ++p, ++index ) {
@@ -3339,11 +3620,12 @@
 		if ( gLinkContext.verboseMapping ) {
 			// list the code blob
 			dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
-			uint32_t signatureSize = header->codeSignatureSize;
+			uint64_t signatureSize = header->codeSignatureSize;
 			// zero size in header means signature runs to end-of-file
 			if ( signatureSize == 0 ) {
 				struct stat stat_buf;
-				if ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &stat_buf) == 0 ) 
+				// FIXME: need size of cache file actually used
+				if ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &stat_buf) == 0 )
 					signatureSize = stat_buf.st_size - header->codeSignatureOffset;
 			}
 			if ( signatureSize != 0 ) {
@@ -3355,7 +3637,10 @@
 #if __IPHONE_OS_VERSION_MIN_REQUIRED
 		// check for file that enables dyld shared cache dylibs to be overridden
 		struct stat enableStatBuf;
-		sDylibsOverrideCache = ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0 );
+		// check file size to determine if correct file is in place. 
+		// See <rdar://problem/13591370> Need a way to disable roots without removing /S/L/C/com.apple.dyld/enable...
+		sDylibsOverrideCache = ( (my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0)
+									&& (enableStatBuf.st_size < ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE) );
 #endif	
 	}
 }
@@ -3445,6 +3730,9 @@
 
 void registerRemoveCallback(ImageCallback func)
 {
+	// <rdar://problem/15025198> ignore calls to register a notification during a notification
+	if ( sRemoveImageCallbacksInUse )
+		return;
 	sRemoveImageCallbacks.push_back(func);
 }
 
@@ -3541,7 +3829,7 @@
 	
 	// bind lazy pointer and return it
 	try {
-		result = (*imageLoaderCache)->doBindFastLazySymbol(lazyBindingInfoOffset, gLinkContext, 
+		result = (*imageLoaderCache)->doBindFastLazySymbol((uint32_t)lazyBindingInfoOffset, gLinkContext, 
 								(dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->acquireGlobalDyldLock : NULL,
 								(dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->releaseGlobalDyldLock : NULL);
 	}
@@ -3573,8 +3861,8 @@
 	// search all images in order
 	const ImageLoader* firstWeakImage = NULL;
 	const ImageLoader::Symbol* firstWeakSym = NULL;
-	const unsigned int imageCount = sAllImages.size();
-	for(unsigned int i=0; i < imageCount; ++i) {
+	const size_t imageCount = sAllImages.size();
+	for(size_t i=0; i < imageCount; ++i) {
 		ImageLoader* anImage = sAllImages[i];
 		// the use of inserted libraries alters search order
 		// so that inserted libraries are found before the main executable
@@ -3625,8 +3913,8 @@
 bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, const ImageLoader** image)
 {
 	// search all images in order
-	const unsigned int imageCount = sAllImages.size();
-	for(unsigned int i=0; i < imageCount; ++i){
+	const size_t imageCount = sAllImages.size();
+	for(size_t i=0; i < imageCount; ++i){
 		ImageLoader* anImage = sAllImages[i];
 		// only look at images whose paths contain the hint string (NULL hint string is wildcard)
 		if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) {
@@ -3784,20 +4072,16 @@
 	gLinkContext.programVars.__prognamePtr=&gLinkContext.progname;
 	gLinkContext.mainExecutable			= NULL;
 	gLinkContext.imageSuffix			= NULL;
+	gLinkContext.dynamicInterposeArray	= NULL;
+	gLinkContext.dynamicInterposeCount	= 0;
 	gLinkContext.prebindUsage			= ImageLoader::kUseAllPrebinding;
+#if TARGET_IPHONE_SIMULATOR
+	gLinkContext.sharedRegionMode		= ImageLoader::kDontUseSharedRegion;
+#else
 	gLinkContext.sharedRegionMode		= ImageLoader::kUseSharedRegion;
-}
-
-
-#if __LP64__
-	#define LC_SEGMENT_COMMAND		LC_SEGMENT_64
-	#define macho_segment_command	segment_command_64
-	#define macho_section			section_64
-#else
-	#define LC_SEGMENT_COMMAND		LC_SEGMENT
-	#define macho_segment_command	segment_command
-	#define macho_section			section
-#endif
+#endif
+}
+
 
 
 //
@@ -3834,20 +4118,18 @@
 	return false;
 }
 
+
 #if SUPPORT_VERSIONED_PATHS
-//
-// Peeks at a dylib file and returns its current_version and install_name.
-// Returns false on error.
-//			
-static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName)
-{
+
+static bool readFirstPage(const char* dylibPath, uint8_t firstPage[4096]) 
+{
+	firstPage[0] = 0;
 	// open file (automagically closed when this function exits)
 	FileOpener file(dylibPath);
-	
+
 	if ( file.getFileDescriptor() == -1 ) 
 		return false;
 	
-	uint8_t firstPage[4096];
 	if ( pread(file.getFileDescriptor(), firstPage, 4096, 0) != 4096 )
 		return false;
 
@@ -3864,9 +4146,33 @@
 			return false;
 		}
 	}
+	
+	return true;
+}
+
+//
+// Peeks at a dylib file and returns its current_version and install_name.
+// Returns false on error.
+//
+static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName)
+{
+	uint8_t firstPage[4096];
+	const macho_header* mh = (macho_header*)firstPage;
+	if ( !readFirstPage(dylibPath, firstPage) ) {
+	#if DYLD_SHARED_CACHE_SUPPORT
+		// If file cannot be read, check to see if path is in shared cache
+		const macho_header* mhInCache;
+		const char*			pathInCache;
+		long				slideInCache;
+		if ( !findInSharedCacheImage(dylibPath, true, NULL, &mhInCache, &pathInCache, &slideInCache) )
+			return false;
+		mh = mhInCache;
+	#else
+		return false;
+	#endif
+	}
 
 	// check mach-o header
-	const mach_header* mh = (mach_header*)firstPage;
 	if ( mh->magic != sMainExecutableMachHeader->magic ) 
 		return false;
 	if ( mh->cputype != sMainExecutableMachHeader->cputype )
@@ -3898,6 +4204,7 @@
 }
 #endif // SUPPORT_VERSIONED_PATHS
 						
+
 #if 0
 static void printAllImages()
 {
@@ -3979,13 +4286,16 @@
 		for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
 			ImageLoader* image = *it;
 			if ( (image->dlopenCount() != 0) || image->neverUnload() ) {
-				image->markedUsedRecursive(sDynamicReferences);
+				OSSpinLockLock(&sDynamicReferencesLock);
+					image->markedUsedRecursive(sDynamicReferences);
+				OSSpinLockUnlock(&sDynamicReferencesLock);
 			}
 		}
 
 		// collect phase: build array of images not marked in-use
 		ImageLoader* deadImages[sAllImages.size()];
 		unsigned deadCount = 0;
+		int maxRangeCount = 0;
 		unsigned i = 0;
 		for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
 			ImageLoader* image = *it;
@@ -3993,21 +4303,35 @@
 				deadImages[i++] = image;
 				if (gLogAPIs) dyld::log("dlclose(), found unused image %p %s\n", image, image->getShortName());
 				++deadCount;
+				maxRangeCount += image->segmentCount();
 			}
 		}
 
 		// collect phase: run termination routines for images not marked in-use
-		// TO DO:  When libc has cxa_finalize() that takes array of images, pass deadImages[] instead of the for loop here
+		__cxa_range_t ranges[maxRangeCount];
+		int rangeCount = 0;
 		for (unsigned i=0; i < deadCount; ++i) {
 			ImageLoader* image = deadImages[i];
+			for (unsigned int j=0; j < image->segmentCount(); ++j) {
+				if ( !image->segExecutable(j) )
+					continue;
+				if ( rangeCount < maxRangeCount ) {
+					ranges[rangeCount].addr = (const void*)image->segActualLoadAddress(j);
+					ranges[rangeCount].length = image->segSize(j);
+					++rangeCount;
+				}
+			}
 			try {
-				if (gLogAPIs) dyld::log("dlclose(), running terminators for %p %s\n", image, image->getShortName());
-				runImageTerminators(image);
+				runImageStaticTerminators(image);
 			}
 			catch (const char* msg) {
 				dyld::warn("problem running terminators for image: %s\n", msg);
 			}
 		}
+		
+		// <rdar://problem/14718598> dyld should call __cxa_finalize_ranges()
+		if ( (rangeCount > 0) && (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 13) )
+			(*gLibSystemHelpers->cxa_finalize_ranges)(ranges, rangeCount);
 
 		// collect phase: delete all images which are not marked in-use
 		bool mightBeMore;
@@ -4081,31 +4405,45 @@
 		image = load(path, context);
 	}
 	catch (const char* msg) {
+#if TARGET_IPHONE_SIMULATOR
+		dyld::log("dyld: warning: could not load inserted library '%s' because %s\n", path, msg);
+#else
 		halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path, msg));
+#endif
 	}
 	catch (...) {
 		halt(dyld::mkstringf("could not load inserted library '%s'\n", path));
 	}
 }
 
-static bool processRestricted(const macho_header* mainExecutableMH)
+static bool processRestricted(const macho_header* mainExecutableMH, bool* ignoreEnvVars, bool* processRequiresLibraryValidation)
 {	
-#if __MAC_OS_X_VERSION_MIN_REQUIRED
+#if TARGET_IPHONE_SIMULATOR
+	gLinkContext.codeSigningEnforced = true;
+#else
     // ask kernel if code signature of program makes it restricted
     uint32_t flags;
 	if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
+		if (flags & CS_REQUIRE_LV)
+			*processRequiresLibraryValidation = true;
+
+  #if __MAC_OS_X_VERSION_MIN_REQUIRED
 		if ( flags & CS_ENFORCEMENT ) {
 			gLinkContext.codeSigningEnforced = true;
 		}
-	}
-	if (flags & CS_RESTRICT) {
-		sRestrictedReason = restrictedByEntitlements;
-		return true;
-	}
-#else
-	gLinkContext.codeSigningEnforced = true;
-#endif
-	
+		if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0) ) {
+			sRestrictedReason = restrictedByEntitlements;
+			return true;
+		}
+  #else
+		if ((flags & CS_ENFORCEMENT) && !(flags & CS_GET_TASK_ALLOW)) {
+			*ignoreEnvVars = true;
+		}
+		gLinkContext.codeSigningEnforced = true;
+  #endif
+	}
+#endif
+
 	// all processes with setuid or setgid bit set are restricted
     if ( issetugid() ) {
 		sRestrictedReason = restrictedBySetGUid;
@@ -4156,7 +4494,8 @@
 typedef int (*ioctl_proc_t)(int, unsigned long, void*);
 static void* getProcessInfo() { return dyld::gProcessInfo; }
 static SyscallHelpers sSysCalls = {
-		1, 
+		4,
+		// added in version 1
 		(open_proc_t)&open, 
 		&close, 
 		&pread, 
@@ -4185,7 +4524,16 @@
 		&OSMemoryBarrier,
 		&getProcessInfo,
 		&__error,
-		&mach_absolute_time
+		&mach_absolute_time,
+		// added in version 2
+		&thread_switch,
+		// added in version 3
+		&opendir,
+		&readdir_r,
+		&closedir,
+		// added in version 4
+		&coresymbolication_load_notifier,
+		&coresymbolication_unload_notifier
 };
 
 __attribute__((noinline))
@@ -4197,8 +4545,6 @@
 	// verify simulator dyld file is owned by root
 	struct stat sb;
 	if ( fstat(fd, &sb) == -1 )
-		return 0;
-	if ( sb.st_uid != 0 )
 		return 0;
 
 	// read first page of dyld file
@@ -4223,32 +4569,73 @@
 	
 	// calculate total size of dyld segments
 	const macho_header* mh = (const macho_header*)firstPage;
+	struct macho_segment_command* lastSeg = NULL;
+	struct macho_segment_command* firstSeg = NULL;
 	uintptr_t mappingSize = 0;
 	uintptr_t preferredLoadAddress = 0;
 	const uint32_t cmd_count = mh->ncmds;
+	if ( (sizeof(macho_header) + mh->sizeofcmds) > 4096 )
+		return 0;
 	const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
+	const struct load_command* const endCmds = (struct load_command*)(((char*)mh) + sizeof(macho_header) + mh->sizeofcmds);
 	const struct load_command* cmd = cmds;
 	for (uint32_t i = 0; i < cmd_count; ++i) {
+		uint32_t cmdLength = cmd->cmdsize;
+		if ( cmdLength < 8 )
+			return 0;
+		const struct load_command* const nextCmd = (const struct load_command*)(((char*)cmd)+cmdLength);
+		if ( (nextCmd > endCmds) || (nextCmd < cmd) )
+			return 0;
 		switch (cmd->cmd) {
 			case LC_SEGMENT_COMMAND:
 				{
 					struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+					if ( seg->vmaddr + seg->vmsize < seg->vmaddr )
+						return 0;
+					if ( seg->vmsize < seg->filesize )
+						return 0;
+					if ( lastSeg == NULL ) {
+						// first segment must be __TEXT and start at beginning of file/slice
+						firstSeg = seg;
+						if ( strcmp(seg->segname, "__TEXT") != 0 )
+							return 0;
+						if ( seg->fileoff != 0 )
+							return 0;
+						if ( seg->filesize < (sizeof(macho_header) + mh->sizeofcmds) )
+							return 0;
+						preferredLoadAddress = seg->vmaddr;
+					}
+					else {
+						// other sements must be continguous with previous segment and not executable
+						if ( lastSeg->fileoff + lastSeg->filesize != seg->fileoff )
+							return 0;
+						if ( lastSeg->vmaddr + lastSeg->vmsize != seg->vmaddr )
+							return 0;
+						if ( (seg->initprot & VM_PROT_EXECUTE) != 0 )
+							return 0;
+					}
 					mappingSize += seg->vmsize;
-					if ( seg->fileoff == 0 )
-						preferredLoadAddress = seg->vmaddr;
+					lastSeg = seg;
 				}
 				break;
-		}
-		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-	}
+			case LC_SEGMENT_COMMAND_WRONG:
+				return 0;
+		}
+		cmd = nextCmd;
+	}
+	// last segment must be named __LINKEDIT and not writable
+	if ( strcmp(lastSeg->segname, "__LINKEDIT") != 0 )
+		return 0;
+	if ( lastSeg->initprot & VM_PROT_WRITE )
+		return 0;
 
 	// reserve space, then mmap each segment
 	vm_address_t loadAddress = 0;
-	uintptr_t entry = 0;
 	if ( ::vm_allocate(mach_task_self(), &loadAddress, mappingSize, VM_FLAGS_ANYWHERE) != 0 )
 		return 0;
 	cmd = cmds;
 	struct linkedit_data_command* codeSigCmd = NULL;
+	struct source_version_command* dyldVersionCmd = NULL;
 	for (uint32_t i = 0; i < cmd_count; ++i) {
 		switch (cmd->cmd) {
 			case LC_SEGMENT_COMMAND:
@@ -4261,36 +4648,64 @@
 						return 0;
 				}
 				break;
-			case LC_UNIXTHREAD:
-				{
-				#if __i386__
-					const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
-					entry = (registers->__eip + loadAddress - preferredLoadAddress);
-				#elif __x86_64__
-					const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
-					entry = (registers->__rip + loadAddress - preferredLoadAddress);
-				#endif
-				}
-				break;
 			case LC_CODE_SIGNATURE:
 				codeSigCmd = (struct linkedit_data_command*)cmd;
 				break;
+			case LC_SOURCE_VERSION:
+				dyldVersionCmd = (struct source_version_command*)cmd;
+				break;
 		}
 		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
 	}
-	
-	if ( codeSigCmd != NULL ) {
-		fsignatures_t siginfo;
-		siginfo.fs_file_start=fileOffset;							// start of mach-o slice in fat file 
-		siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff);	// start of code-signature in mach-o file
-		siginfo.fs_blob_size=codeSigCmd->datasize;					// size of code-signature
-		int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
-		if ( result == -1 ) {
-			if ( (errno == EPERM) || (errno == EBADEXEC) )
+
+	// must have code signature which is contained within LINKEDIT segment
+	if ( codeSigCmd == NULL )
+		return 0;
+	if ( codeSigCmd->dataoff < lastSeg->fileoff )
+		return 0;
+	if ( (codeSigCmd->dataoff + codeSigCmd->datasize) > (lastSeg->fileoff + lastSeg->filesize) )
+		return 0;
+
+	fsignatures_t siginfo;
+	siginfo.fs_file_start=fileOffset;							// start of mach-o slice in fat file 
+	siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff);	// start of code-signature in mach-o file
+	siginfo.fs_blob_size=codeSigCmd->datasize;					// size of code-signature
+	int result = fcntl(fd, F_ADDFILESIGS_FOR_DYLD_SIM, &siginfo);
+	if ( result == -1 ) {
+		dyld::log("fcntl(F_ADDFILESIGS_FOR_DYLD_SIM) failed with errno=%d\n", errno);
+		return 0;
+	}
+	close(fd);
+	// file range covered by code signature must extend up to code signature itself
+	if ( siginfo.fs_file_start < codeSigCmd->dataoff )
+		return 0;
+
+	// walk newly mapped dyld_sim __TEXT load commands to find entry point
+	uintptr_t entry = 0;
+	cmd = (struct load_command*)(((char*)loadAddress)+sizeof(macho_header));
+	const uint32_t count = ((macho_header*)(loadAddress))->ncmds;
+	for (uint32_t i = 0; i < count; ++i) {
+		if (cmd->cmd == LC_UNIXTHREAD) {
+		#if __i386__
+			const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
+			// entry point must be in first segment
+			if ( registers->__eip < firstSeg->vmaddr )
 				return 0;
-		}
-	}
-	close(fd);
+			if ( registers->__eip > (firstSeg->vmaddr + firstSeg->vmsize) )
+				return 0;
+			entry = (registers->__eip + loadAddress - preferredLoadAddress);
+		#elif __x86_64__
+			const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
+			// entry point must be in first segment
+			if ( registers->__rip < firstSeg->vmaddr )
+				return 0;
+			if ( registers->__rip > (firstSeg->vmaddr + firstSeg->vmsize) )
+				return 0;
+			entry = (registers->__rip + loadAddress - preferredLoadAddress);
+		#endif
+		}
+		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+	}
 
 	// notify debugger that dyld_sim is loaded
 	dyld_image_info info;
@@ -4299,13 +4714,14 @@
 	info.imageFileModDate = sb.st_mtime;
 	addImagesToAllImages(1, &info);
 	dyld::gProcessInfo->notification(dyld_image_adding, 1, &info);
-	
+
+	const char** appleParams = apple;
 	// jump into new simulator dyld
 	typedef uintptr_t (*sim_entry_proc_t)(int argc, const char* argv[], const char* envp[], const char* apple[],
 								const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide,
 								const dyld::SyscallHelpers* vtable, uintptr_t* startGlue);
 	sim_entry_proc_t newDyld = (sim_entry_proc_t)entry;
-	return (*newDyld)(argc, argv, envp, apple, mainExecutableMH, (macho_header*)loadAddress, 
+	return (*newDyld)(argc, argv, envp, appleParams, mainExecutableMH, (macho_header*)loadAddress,
 					 loadAddress - preferredLoadAddress, 
 					 &sSysCalls, startGlue);
 }
@@ -4344,13 +4760,6 @@
 #endif
 
 	CRSetCrashLogMessage("dyld: launch started");
-#ifdef ALTERNATIVE_LOGFILE
-	sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
-	if ( sLogfile == -1 ) {
-		sLogfile = STDERR_FILENO;
-		dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE, errno);
-	}
-#endif
 
 #if LOG_BINDINGS
 	char bindingsLogPath[256];
@@ -4379,7 +4788,6 @@
 	// <rdar://problem/13868260> Remove interim apple[0] transition code from dyld
 	if (!sExecPath) sExecPath = apple[0];
 	
-	sExecPath = apple[0];
 	bool ignoreEnvironmentVariables = false;
 	if ( sExecPath[0] != '/' ) {
 		// have relative path, use cwd to make absolute
@@ -4399,25 +4807,25 @@
 		++sExecShortName;
 	else
 		sExecShortName = sExecPath;
-    sProcessIsRestricted = processRestricted(mainExecutableMH);
+    sProcessIsRestricted = processRestricted(mainExecutableMH, &ignoreEnvironmentVariables, &sProcessRequiresLibraryValidation);
     if ( sProcessIsRestricted ) {
 #if SUPPORT_LC_DYLD_ENVIRONMENT
 		checkLoadCommandEnvironmentVariables();
-#if SUPPORT_VERSIONED_PATHS
-		checkVersionedPaths();
-#endif	
 #endif 	
 		pruneEnvironmentVariables(envp, &apple);
 		// set again because envp and apple may have changed or moved
 		setContext(mainExecutableMH, argc, argv, envp, apple);
 	}
-	else
-		checkEnvironmentVariables(envp, ignoreEnvironmentVariables);
-	if ( sEnv.DYLD_PRINT_OPTS ) 
+	else {
+		if ( !ignoreEnvironmentVariables )
+			checkEnvironmentVariables(envp);
+		defaultUninitializedFallbackPaths(envp);
+	}
+	if ( sEnv.DYLD_PRINT_OPTS )
 		printOptions(argv);
 	if ( sEnv.DYLD_PRINT_ENV ) 
 		printEnvironmentVariables(envp);
-	getHostInfo();
+	getHostInfo(mainExecutableMH, mainExecutableSlide);
 	// install gdb notifier
 	stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB);
 	stateToHandlers(dyld_image_state_mapped, sSingleHandlers)->push_back(updateAllImages);
@@ -4438,21 +4846,48 @@
 	try {
 		// add dyld itself to UUID list
 		addDyldImageToUUIDList();
-		if ( sProcessIsRestricted )
-			CRSetCrashLogMessage("dyld: launch, loading dependent libraries, ignoring DYLD_* env vars");
-		else
-			CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
+		CRSetCrashLogMessage(sLoadingCrashMessage);
 		// instantiate ImageLoader for main executable
 		sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
 		gLinkContext.mainExecutable = sMainExecutable;
 		gLinkContext.processIsRestricted = sProcessIsRestricted;
+		gLinkContext.processRequiresLibraryValidation = sProcessRequiresLibraryValidation;
 		gLinkContext.mainExecutableCodeSigned = hasCodeSignatureLoadCommand(mainExecutableMH);
+
+#if TARGET_IPHONE_SIMULATOR
+	#if TARGET_OS_WATCH || TARGET_OS_TV
+		// disable error during bring up of these simulators
+	#else
+		// check main executable is not too new for this OS
+		{
+			if ( ! isSimulatorBinary((uint8_t*)mainExecutableMH, sExecPath) ) {
+				throwf("program was built for Mac OS X and cannot be run in simulator"); 
+			}
+			uint32_t mainMinOS = sMainExecutable->minOSVersion();
+			// dyld is always built for the current OS, so we can get the current OS version
+			// from the load command in dyld itself.
+			uint32_t dyldMinOS = ImageLoaderMachO::minOSVersion((const mach_header*)&__dso_handle);
+			if ( mainMinOS > dyldMinOS ) {
+				throwf("app was built for iOS %d.%d which is newer than this simulator %d.%d", 
+						mainMinOS >> 16, ((mainMinOS >> 8) & 0xFF),
+						dyldMinOS >> 16, ((dyldMinOS >> 8) & 0xFF));
+			}
+		}
+	#endif
+#endif
+
 		// load shared cache
 		checkSharedRegionDisable();
 	#if DYLD_SHARED_CACHE_SUPPORT
 		if ( gLinkContext.sharedRegionMode != ImageLoader::kDontUseSharedRegion )
 			mapSharedCache();
 	#endif
+
+		// Now that shared cache is loaded, setup an versioned dylib overrides
+	#if SUPPORT_VERSIONED_PATHS
+		checkVersionedPaths();
+	#endif
+
 		// load any inserted libraries
 		if	( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
 			for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib) 
@@ -4479,10 +4914,23 @@
 				ImageLoader* image = sAllImages[i+1];
 				link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL));
 				image->setNeverUnloadRecursive();
-				// only INSERTED libraries can interpose
+			}
+			// only INSERTED libraries can interpose
+			// register interposing info after all inserted libraries are bound so chaining works
+			for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
+				ImageLoader* image = sAllImages[i+1];
 				image->registerInterposing();
 			}
 		}
+
+		// <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES
+		for (int i=sInsertedDylibCount+1; i < sAllImages.size(); ++i) {
+			ImageLoader* image = sAllImages[i];
+			if ( image->inSharedCache() )
+				continue;
+			image->registerInterposing();
+		}
+
 		// apply interposing to initial set of images
 		for(int i=0; i < sImageRoots.size(); ++i) {
 			sImageRoots[i]->applyInterposing(gLinkContext);
@@ -4524,13 +4972,6 @@
 		dyld::log("dyld: launch failed\n");
 	}
 
-#ifdef ALTERNATIVE_LOGFILE
-	// only use alternate log during launch, otherwise file is open forever
-	if ( sLogfile != STDERR_FILENO ) {
-		close(sLogfile);
-		sLogfile = STDERR_FILENO;
-	}
-#endif
 	CRSetCrashLogMessage(NULL);
 	
 	return result;