Loading...
src/dyld2.cpp dyld-852 dyld-750.5
--- dyld/dyld-852/src/dyld2.cpp
+++ dyld/dyld-750.5/src/dyld2.cpp
@@ -33,8 +33,7 @@
 #include <libproc.h>
 #include <sys/param.h>
 #include <mach/mach_time.h> // mach_absolute_time()
-#include <mach/mach_init.h>
-#include <mach/mach_traps.h>
+#include <mach/mach_init.h> 
 #include <sys/types.h>
 #include <sys/stat.h> 
 #include <sys/syscall.h>
@@ -42,13 +41,13 @@
 #include <sys/un.h>
 #include <sys/syslog.h>
 #include <sys/uio.h>
-#include <sys/xattr.h>
 #include <mach/mach.h>
 #include <mach-o/fat.h>
 #include <mach-o/loader.h> 
 #include <mach-o/ldsyms.h> 
 #include <libkern/OSByteOrder.h> 
 #include <libkern/OSAtomic.h>
+#include <mach/mach.h>
 #include <sys/sysctl.h>
 #include <sys/mman.h>
 #include <sys/dtrace.h>
@@ -64,27 +63,6 @@
 #include <sys/attr.h>
 #include <sys/fsgetpath.h>
 #include <System/sys/content_protection.h>
-
-#define SUPPORT_LOGGING_TO_CONSOLE !TARGET_OS_SIMULATOR
-#if SUPPORT_LOGGING_TO_CONSOLE
-#include <paths.h> // for logging to console
-#endif
-
-#if !TARGET_OS_SIMULATOR
-
-// The comm page is being renamed, so set our define to the new value if the old
-// value is missing
-#ifndef _COMM_PAGE_DYLD_SYSTEM_FLAGS
-
-#ifndef _COMM_PAGE_DYLD_FLAGS
-#error Must define _COMM_PAGE_DYLD_FLAGS or _COMM_PAGE_DYLD_SYSTEM_FLAGS
-#endif
-
-#define _COMM_PAGE_DYLD_SYSTEM_FLAGS _COMM_PAGE_DYLD_FLAGS
-
-#endif
-
-#endif
 
 #if TARGET_OS_SIMULATOR
 	enum {
@@ -146,8 +124,6 @@
 #include "ClosureFileSystemPhysical.h"
 #include "FileUtils.h"
 #include "BootArgs.h"
-#include "Defines.h"
-#include "RootsChecker.h"
 
 #ifndef MH_HAS_OBJC
   #define MH_HAS_OBJC			0x40000000
@@ -174,7 +150,7 @@
 	#define macho_section			section
 #endif
 
-#define DYLD_CLOSURE_XATTR_NAME "com.apple.dyld"
+
 
 #define CPU_TYPE_MASK 0x00FFFFFF	/* complement of CPU_ARCH_MASK */
 
@@ -182,7 +158,6 @@
 /* implemented in dyld_gdb.cpp */
 extern void resetAllImages();
 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
-extern void addAotImagesToAllAotImages(uint32_t aotInfoCount, const dyld_aot_image_info aotInfo[]);
 extern void removeImageFromAllImages(const mach_header* mh);
 extern void addNonSharedCacheImageUUID(const dyld_uuid_info& info);
 extern const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[]);
@@ -195,8 +170,6 @@
 
 // magic linker symbol for start of dyld binary
 extern "C" const macho_header __dso_handle;
-
-extern bool gEnableSharedCacheDataConst;
 
 
 //
@@ -283,8 +256,7 @@
 static cpu_type_t					sHostCPU;
 static cpu_subtype_t				sHostCPUsubtype;
 #endif
-typedef ImageLoaderMachO* __ptrauth_dyld_address_auth MainExecutablePointerType;
-static MainExecutablePointerType	sMainExecutable = NULL;
+static ImageLoaderMachO*			sMainExecutable = NULL;
 static size_t						sInsertedDylibCount = 0;
 static std::vector<ImageLoader*>	sAllImages;
 static std::vector<ImageLoader*>	sImageRoots;
@@ -299,7 +271,7 @@
 static void*						sBatchHandlers[7][3];
 static ImageLoader*					sLastImageByAddressCache;
 static EnvironmentVariables			sEnv;
-#if TARGET_OS_OSX
+#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 };
 static const char*					sRestrictedFrameworkFallbackPaths[] = { "/System/Library/Frameworks", NULL };
@@ -343,7 +315,7 @@
 static _dyld_objc_notify_init		sNotifyObjCInit;
 static _dyld_objc_notify_unmapped	sNotifyObjCUnmapped;
 
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 static bool							sForceStderr = false;
 #endif
 
@@ -355,17 +327,10 @@
 #endif
 
 bool								gUseDyld3 = false;
-static uint32_t						sLaunchModeUsed = 0;
 static bool							sSkipMain = false;
-static void                       (*sEntryOverride)() = nullptr;
+static void                       (*sEntryOveride)() = nullptr;
 static bool							sJustBuildClosure = false;
-#if !TARGET_OS_SIMULATOR
 static bool							sLogClosureFailure = false;
-#endif
-static bool 						sKeysDisabled = false;
-static bool							sOnlyPlatformArm64e = false; // arm64e binaries can only be loaded if they are part of the OS
-
-static dyld3::RootsChecker			sRootsChecker;
 
 enum class ClosureMode {
 	// Unset means we haven't provided an env variable or boot-arg to explicitly choose a mode
@@ -377,38 +342,12 @@
 	// -force_dyld2=1 env variable or an internal cache on iOS
 	Off,
 	// PreBuiltOnly means only use a shared cache closure and don't try build a new one
-	PreBuiltOnly,
+	PreBuiltOnly
 };
 
-enum class ClosureKind {
-	unset,
-	full,
-	minimal,
-};
-
 static ClosureMode					sClosureMode = ClosureMode::Unset;
-static ClosureKind					sClosureKind = ClosureKind::unset;
 static bool							sForceInvalidSharedCacheClosureFormat = false;
 static uint64_t						launchTraceID = 0;
-
-// These flags are the values in the 64-bit _COMM_PAGE_DYLD_SYSTEM_FLAGS entry
-// Note we own this and can write it from PID 1
-enum CommPageFlags : uint64_t {
-    None                                = 0,
-
-	// The boot args can set the low 32-bits of the comm page.  We'll reserve the high 32-bits
-	// for runtime (launchd) set values.
-	CommPageBootArgMask					= 0xFFFFFFFF,
-
-	// Are the simulator support dylibs definitely roots when launchd scanned them
-	libsystemKernelIsRoot 				= 1ULL << 32,
-	libsystemPlatformIsRoot				= 1ULL << 33,
-	libsystemPThreadIsRoot 				= 1ULL << 34,
-
-	// Is the file system writable, ie, could the simulator support dylibs be written
-	// later, after PID 1
-	fileSystemCanBeModified				= 1ULL << 35
-};
 
 //
 // The MappedRanges structure is used for fast address->image lookups.
@@ -607,7 +546,7 @@
 
 void vlog(const char* format, va_list list)
 {
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 	// <rdar://problem/25965832> log to console when running iOS app from Xcode
 	if ( !sLogToFile && !sForceStderr && useSyslog() )
 #else
@@ -640,21 +579,6 @@
 	va_start(list, format);
 	vwarn(format, list);
 	va_end(list);
-}
-
-void logToConsole(const char* format, ...) {
-#if SUPPORT_LOGGING_TO_CONSOLE
-    int cfd = open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY);
-    if (cfd == -1)
-        return;
-
-    va_list list;
-    va_start(list, format);
-    _simple_vdprintf(cfd, format, list);
-    va_end(list);
-
-    close(cfd);
-#endif
 }
 
 #else
@@ -694,7 +618,7 @@
 FileOpener::FileOpener(const char* path)
  : fd(-1)
 {
-	fd = dyld3::open(path, O_RDONLY, 0);
+	fd = my_open(path, O_RDONLY, 0);
 }
 
 FileOpener::~FileOpener()
@@ -751,7 +675,7 @@
 
 static void	unregisterDOF(int registrationID)
 {
-	int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR, 0);
+	int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
 	if ( fd < 0 ) {
 		dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to unregister dtrace DOF section\n");
 	}
@@ -869,188 +793,95 @@
 #endif
 
 #if !TARGET_OS_SIMULATOR
-#define DYLD_PROCESS_INFO_NOTIFY_MAGIC 0x49414E46
-
-struct RemoteNotificationResponder {
-	RemoteNotificationResponder(const RemoteNotificationResponder&) = delete;
-	RemoteNotificationResponder(RemoteNotificationResponder&&) = delete;
-	RemoteNotificationResponder() {
-		if (dyld::gProcessInfo->notifyPorts[0] != DYLD_PROCESS_INFO_NOTIFY_MAGIC) {
-			// No notifier found, early out
-			_namesCnt = 0;
-			return;
-		}
-		kern_return_t kr = task_dyld_process_info_notify_get(_names, &_namesCnt);
-		while (kr == KERN_NO_SPACE) {
-			// In the future the SPI may return the size we need, but for now we just double the count. Since we don't want to depend on the
-			// return value in _nameCnt we set it to have a minimm of 16, double the inline storage value
-			_namesCnt = std::max<uint32_t>(16, 2*_namesCnt);
-			_namesSize = _namesCnt*sizeof(mach_port_t);
-			kr = vm_allocate(mach_task_self(), (vm_address_t*)&_names, _namesSize, VM_FLAGS_ANYWHERE);
-			if (kr != KERN_SUCCESS) {
-				// We could not allocate memory, time to error out
-				break;
-			}
-			kr = task_dyld_process_info_notify_get(_names, &_namesCnt);
-			if (kr != KERN_SUCCESS) {
-				// We failed, so deallocate the memory. If the failures was KERN_NO_SPACE we will loop back and try again
-				(void)vm_deallocate(mach_task_self(), (vm_address_t)_names, _namesSize);
-				_namesSize = 0;
-			}
-		}
-		if (kr != KERN_SUCCESS) {
-			// We failed, set _namesCnt to 0 so nothing else will happen
-			_namesCnt = 0;
-		}
-	}
-	~RemoteNotificationResponder() {
-		if (_namesCnt) {
-			for (auto i = 0; i < _namesCnt; ++i) {
-				(void)mach_port_deallocate(mach_task_self(), _names[i]);
-			}
-			if (_namesSize != 0) {
-				// We are not using inline memory, we need to free it
-				(void)vm_deallocate(mach_task_self(), (vm_address_t)_names, _namesSize);
-			}
-		}
-	}
-	void sendMessage(mach_msg_id_t msgId, mach_msg_size_t sendSize, mach_msg_header_t* buffer) {
-		if (_namesCnt == 0) { return; }
-		// Allocate a port to listen on in this monitoring task
-		mach_port_t replyPort = MACH_PORT_NULL;
-		mach_port_options_t options = { .flags = MPO_CONTEXT_AS_GUARD | MPO_STRICT, .mpl = { 1 }};
-		kern_return_t kr = mach_port_construct(mach_task_self(), &options, (mach_port_context_t)&replyPort, &replyPort);
-		if (kr != KERN_SUCCESS) {
-			return;
-		}
-		for (auto i = 0; i < _namesCnt; ++i) {
-			if (_names[i] == MACH_PORT_NULL) { continue; }
-			// Assemble a message
-			uint8_t replyBuffer[sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE];
-			mach_msg_header_t* 	msg = buffer;
-			msg->msgh_bits         = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
-			msg->msgh_id           = msgId;
-			msg->msgh_local_port   = replyPort;
-			msg->msgh_remote_port  = _names[i];
-			msg->msgh_reserved     = 0;
-			msg->msgh_size         = sendSize;
-			kr = mach_msg_overwrite(msg, MACH_SEND_MSG | MACH_RCV_MSG, msg->msgh_size, sizeof(replyBuffer), replyPort, 0, MACH_PORT_NULL,
-									 (mach_msg_header_t*)&replyBuffer[0], 0);
-			if (kr != KERN_SUCCESS) {
-				// Send failed, we may have been psuedo recieved. destroy the message
-				(void)mach_msg_destroy(msg);
-				// Mark the port as null. It does not matter why we failed... if it is s single message we will not retry, if it
-				// is a fragmented message then subsequent messages will not decode correctly
-				_names[i] = MACH_PORT_NULL;
-			}
-		}
-		(void)mach_port_destruct(mach_task_self(), replyPort, 0, (mach_port_context_t)&replyPort);
-	}
-
-	bool const active() const {
-		for (auto i = 0; i < _namesCnt; ++i) {
-			if (_names[i] != MACH_PORT_NULL) {
-				return true;
-			}
-		}
-		return false;
-	}
-private:
-	mach_port_t             _namesArray[8] = {0};
-	mach_port_name_array_t  _names = (mach_port_name_array_t)&_namesArray[0];
-	mach_msg_type_number_t  _namesCnt = 8;
-	vm_size_t               _namesSize = 0;
-};
-
-//FIXME: Remove this once we drop support for iOS 11 simulators
-// This is an enormous hack to keep remote introspection of older simulators working
-//   It works by interposing mach_msg, and redirecting message sent to a special port name. Messages to that portname will trigger a full set
-//   of sends to all kernel registered notifiers. In this mode mach_msg_sim_interposed() must return KERN_SUCCESS or the older dyld_sim may
-//   try to cleanup the notifer array.
-kern_return_t mach_msg_sim_interposed(	mach_msg_header_t* msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size,
-									  mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_port_name_t notify) {
-	if (msg->msgh_remote_port != DYLD_PROCESS_INFO_NOTIFY_MAGIC) {
-		// Not the magic port, so just pass through to the real mach_msg()
-		return mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify);
-	}
-
-	// The magic port. We know dyld_sim is trying to message observers, so lets call into our messaging code directly.
-	// This is kind of weird since we effectively built a buffer in dyld_sim, then pass it to mach_msg, which we interpose, unpack, and then
-	// pass to send_message which then sends the buffer back out vis mach_message_overwrite(), but it should work at least as well as the old
-	// way.
-	RemoteNotificationResponder responder;
-	responder.sendMessage(msg->msgh_id, send_size, msg);
-
-	// We always return KERN_SUCCESS, otherwise old dyld_sims might clear the port
-	return KERN_SUCCESS;
-}
-
-static void notifyMonitoringDyld(RemoteNotificationResponder& responder, bool unloading, unsigned imageCount,
-								 const struct mach_header* loadAddresses[], const char* imagePaths[])
-{
-	// Make sure there is at least enough room to hold a the largest single file entry that can exist.
-	static_assert((MAXPATHLEN + sizeof(dyld_process_info_image_entry) + 1 + MAX_TRAILER_SIZE) <= DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE);
-
-	unsigned entriesSize = imageCount*sizeof(dyld_process_info_image_entry);
-	unsigned pathsSize = 0;
-	for (unsigned j=0; j < imageCount; ++j) {
-		pathsSize += (strlen(imagePaths[j]) + 1);
-	}
-
-	unsigned totalSize = (sizeof(struct dyld_process_info_notify_header) + entriesSize + pathsSize + 127) & -128;   // align
-	// The reciever has a fixed buffer of DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE, whcih needs to hold both the message and a trailer.
-	// If the total size exceeds that we need to fragment the message.
-	if ( (totalSize + MAX_TRAILER_SIZE) > DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE ) {
-		// Putting all image paths into one message would make buffer too big.
-		// Instead split into two messages.  Recurse as needed until paths fit in buffer.
-		unsigned imageHalfCount = imageCount/2;
-		notifyMonitoringDyld(responder, unloading, imageHalfCount, loadAddresses, imagePaths);
-		notifyMonitoringDyld(responder, unloading, imageCount - imageHalfCount, &loadAddresses[imageHalfCount], &imagePaths[imageHalfCount]);
+static void sendMessage(unsigned portSlot, mach_msg_id_t msgId, mach_msg_size_t sendSize, mach_msg_header_t* buffer, mach_msg_size_t bufferSize) {
+	// Allocate a port to listen on in this monitoring task
+	mach_port_t sendPort = dyld::gProcessInfo->notifyPorts[portSlot];
+	if (sendPort == MACH_PORT_NULL) {
 		return;
 	}
-	uint8_t	buffer[totalSize + MAX_TRAILER_SIZE];
-	dyld_process_info_notify_header* header = (dyld_process_info_notify_header*)buffer;
-	header->version			= 1;
-	header->imageCount		= imageCount;
-	header->imagesOffset	= sizeof(dyld_process_info_notify_header);
-	header->stringsOffset	= sizeof(dyld_process_info_notify_header) + entriesSize;
-	header->timestamp		= dyld::gProcessInfo->infoArrayChangeTimestamp;
-	dyld_process_info_image_entry* entries = (dyld_process_info_image_entry*)&buffer[header->imagesOffset];
-	char* const pathPoolStart = (char*)&buffer[header->stringsOffset];
-	char* pathPool = pathPoolStart;
-	for (unsigned j=0; j < imageCount; ++j) {
-		strcpy(pathPool, imagePaths[j]);
-		uint32_t len = (uint32_t)strlen(pathPool);
-		bzero(entries->uuid, 16);
-		dyld3::MachOFile* mf = (dyld3::MachOFile*)loadAddresses[j];
-		mf->getUuid(entries->uuid);
-		entries->loadAddress = (uint64_t)loadAddresses[j];
-		entries->pathStringOffset = (uint32_t)(pathPool - pathPoolStart);
-		entries->pathLength  = len;
-		pathPool += (len +1);
-		++entries;
-	}
-	if (unloading) {
-		responder.sendMessage(DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID, totalSize, (mach_msg_header_t*)buffer);
-	} else {
-		responder.sendMessage(DYLD_PROCESS_INFO_NOTIFY_LOAD_ID, totalSize, (mach_msg_header_t*)buffer);
-	}
+	mach_port_t replyPort = MACH_PORT_NULL;
+	mach_port_options_t options = { .flags = MPO_CONTEXT_AS_GUARD | MPO_STRICT,
+		.mpl = { 1 }};
+	kern_return_t kr = mach_port_construct(mach_task_self(), &options, (mach_port_context_t)&replyPort, &replyPort);
+	if (kr != KERN_SUCCESS) {
+		return;
+	}
+	// Assemble a message
+	mach_msg_header_t* h = buffer;
+	h->msgh_bits         = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
+	h->msgh_id           = msgId;
+	h->msgh_local_port   = replyPort;
+	h->msgh_remote_port  = sendPort;
+	h->msgh_reserved     = 0;
+	h->msgh_size         = sendSize;
+	kr = mach_msg(h, MACH_SEND_MSG | MACH_RCV_MSG, h->msgh_size, bufferSize, replyPort, 0, MACH_PORT_NULL);
+	mach_msg_destroy(h);
+	if ( kr == MACH_SEND_INVALID_DEST ) {
+		if (OSAtomicCompareAndSwap32(sendPort, 0, (volatile int32_t*)&dyld::gProcessInfo->notifyPorts[portSlot])) {
+			mach_port_deallocate(mach_task_self(), sendPort);
+		}
+	}
+	mach_port_destruct(mach_task_self(), replyPort, 0, (mach_port_context_t)&replyPort);
 }
 
 static void notifyMonitoringDyld(bool unloading, unsigned imageCount, const struct mach_header* loadAddresses[],
 								 const char* imagePaths[])
 {
 	dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER, 0, 0, 0);
-	RemoteNotificationResponder responder;
-	if (!responder.active()) { return; }
-	notifyMonitoringDyld(responder, unloading, imageCount, loadAddresses, imagePaths);
-}
-
-static void notifyMonitoringDyldMain() {
+	for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
+		if ( dyld::gProcessInfo->notifyPorts[slot] == 0) continue;
+		unsigned entriesSize = imageCount*sizeof(dyld_process_info_image_entry);
+		unsigned pathsSize = 0;
+		for (unsigned j=0; j < imageCount; ++j) {
+			pathsSize += (strlen(imagePaths[j]) + 1);
+		}
+		unsigned totalSize = (sizeof(dyld_process_info_notify_header) + entriesSize + pathsSize + 127) & -128;   // align
+		if ( totalSize > DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE ) {
+			// Putting all image paths into one message would make buffer too big.
+			// Instead split into two messages.  Recurse as needed until paths fit in buffer.
+			unsigned imageHalfCount = imageCount/2;
+			notifyMonitoringDyld(unloading, imageHalfCount, loadAddresses, imagePaths);
+			notifyMonitoringDyld(unloading, imageCount - imageHalfCount, &loadAddresses[imageHalfCount], &imagePaths[imageHalfCount]);
+			return;
+		}
+		uint8_t	buffer[totalSize + MAX_TRAILER_SIZE];
+		dyld_process_info_notify_header* header = (dyld_process_info_notify_header*)buffer;
+		header->version			= 1;
+		header->imageCount		= imageCount;
+		header->imagesOffset	= sizeof(dyld_process_info_notify_header);
+		header->stringsOffset	= sizeof(dyld_process_info_notify_header) + entriesSize;
+		header->timestamp		= dyld::gProcessInfo->infoArrayChangeTimestamp;
+		dyld_process_info_image_entry* entries = (dyld_process_info_image_entry*)&buffer[header->imagesOffset];
+		char* const pathPoolStart = (char*)&buffer[header->stringsOffset];
+		char* pathPool = pathPoolStart;
+		for (unsigned j=0; j < imageCount; ++j) {
+			strcpy(pathPool, imagePaths[j]);
+			uint32_t len = (uint32_t)strlen(pathPool);
+			bzero(entries->uuid, 16);
+			dyld3::MachOFile* mf = (dyld3::MachOFile*)loadAddresses[j];
+			mf->getUuid(entries->uuid);
+			entries->loadAddress = (uint64_t)loadAddresses[j];
+			entries->pathStringOffset = (uint32_t)(pathPool - pathPoolStart);
+			entries->pathLength  = len;
+			pathPool += (len +1);
+			++entries;
+		}
+		if (unloading) {
+			sendMessage(slot, DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID, totalSize, (mach_msg_header_t*)buffer, totalSize+MAX_TRAILER_SIZE);
+		} else {
+			sendMessage(slot, DYLD_PROCESS_INFO_NOTIFY_LOAD_ID, totalSize, (mach_msg_header_t*)buffer, totalSize+MAX_TRAILER_SIZE);
+		}
+	}
+}
+
+static void notifyMonitoringDyldMain()
+{
 	dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER, 0, 0, 0);
-	RemoteNotificationResponder responder;
-	uint8_t buffer[sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE];
-	responder.sendMessage(DYLD_PROCESS_INFO_NOTIFY_MAIN_ID, sizeof(mach_msg_header_t), (mach_msg_header_t*)buffer);
+	for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
+		if ( dyld::gProcessInfo->notifyPorts[slot] == 0) continue;
+		uint8_t buffer[sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE];
+		sendMessage(slot, DYLD_PROCESS_INFO_NOTIFY_MAIN_ID, sizeof(mach_msg_header_t), (mach_msg_header_t*)buffer, sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE);
+	}
 }
 #else
 extern void notifyMonitoringDyldMain() VIS_HIDDEN;
@@ -1096,9 +927,7 @@
 	}
 	if ( state == dyld_image_state_mapped ) {
 		// <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache
-		// <rdar://problem/50432671> Include UUIDs for shared cache dylibs in all image info when using private mapped shared caches
-		if (!image->inSharedCache()
-			|| (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion)) {
+		if ( !image->inSharedCache() ) {
 			dyld_uuid_info info;
 			if ( image->getUUID(info.imageUUID) ) {
 				info.imageLoadAddress = image->machHeader();
@@ -1352,7 +1181,7 @@
 	notifyBatchPartial(state, false, NULL, preflightOnly, false);
 }
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 static
 void coresymbolication_load_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
 {
@@ -1645,13 +1474,12 @@
 	}
 
 	// If this image is the potential canonical definition of any weak defs, then set them to a tombstone value
-	if ( gLinkContext.weakDefMapInitialized && image->hasCoalescedExports() && (image->getState() >= dyld_image_state_bound) ) {
+	if ( gLinkContext.weakDefMapInitialized && image->hasCoalescedExports() ) {
 		Diagnostics diag;
 		const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)image->machHeader();
-		ma->forEachWeakDef(diag, ^(const char *symbolName, uint64_t imageOffset, bool isFromExportTrie) {
+		ma->forEachWeakDef(diag, ^(const char *symbolName, uintptr_t imageOffset, bool isFromExportTrie) {
 			auto it = gLinkContext.weakDefMap.find(symbolName);
-			if ( it == gLinkContext.weakDefMap.end() )
-				return;
+			assert(it != gLinkContext.weakDefMap.end());
 			it->second = { nullptr, 0 };
 			if ( !isFromExportTrie ) {
 				// The string was already duplicated if we are an export trie
@@ -1703,15 +1531,7 @@
 
 static void terminationRecorder(ImageLoader* image)
 {
-	bool add = true;
-#if __arm64e__
-	// <rdar://problem/71820555> Don't run static terminator for arm64e
-	const mach_header* mh = image->machHeader();
-	if ( (mh->cputype == CPU_TYPE_ARM64) && ((mh->cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E) )
-		add = false;
-#endif
-	if ( add )
-		sImageFilesNeedingTermination.push_back(image);
+	sImageFilesNeedingTermination.push_back(image);
 }
 
 const char* getExecutablePath()
@@ -2029,7 +1849,7 @@
 	}
 }
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 static void paths_expand_roots(const char **paths, const char *key, const char *val)
 {
 // 	assert(val != NULL);
@@ -2178,13 +1998,13 @@
 	}
 	else if ( strcmp(key, "DYLD_PRINT_STATISTICS") == 0 ) {
 		sEnv.DYLD_PRINT_STATISTICS = true;
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 		// <rdar://problem/26614838> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps
 		sForceStderr = true;
 #endif
 	}
 	else if ( strcmp(key, "DYLD_PRINT_TO_STDERR") == 0 ) {
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 		// <rdar://problem/26633440> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps
 		sForceStderr = true;
 #endif
@@ -2245,9 +2065,6 @@
 		sSharedCacheOverrideDir = value;
 	}
 	else if ( strcmp(key, "DYLD_USE_CLOSURES") == 0 ) {
-		// Handled elsewhere
-	}
-	else if ( strcmp(key, "DYLD_SHARED_REGION_DATA_CONST") == 0 ) {
 		// Handled elsewhere
 	}
 	else if ( strcmp(key, "DYLD_FORCE_INVALID_CACHE_CLOSURES") == 0 ) {
@@ -2290,7 +2107,7 @@
 #endif
 #if !TARGET_OS_SIMULATOR
 	else if ( (strcmp(key, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir == NULL) && gLinkContext.allowEnvVarsSharedCache ) {
-		int fd = dyld3::open(value, O_WRONLY | O_CREAT | O_APPEND, 0644);
+		int fd = open(value, O_WRONLY | O_CREAT | O_APPEND, 0644);
 		if ( fd != -1 ) {
 			sLogfile = fd;
 			sLogToFile = true;
@@ -2403,7 +2220,7 @@
 #endif	
 
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 //
 // For security, setuid programs ignore DYLD_* environment variables.
 // Additionally, the DYLD_* enviroment variables are removed
@@ -2455,7 +2272,7 @@
 
 static void defaultUninitializedFallbackPaths(const char* envp[])
 {
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	if ( !gLinkContext.allowClassicFallbackPaths ) {
 		sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sRestrictedFrameworkFallbackPaths;
 		sEnv.DYLD_FALLBACK_LIBRARY_PATH   = sRestrictedLibraryFallbackPaths;
@@ -2623,7 +2440,7 @@
 
 static void checkSharedRegionDisable(const dyld3::MachOLoaded* mainExecutableMH, uintptr_t mainExecutableSlide)
 {
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	// if main executable has segments that overlap the shared region,
 	// then disable using the shared region
 	if ( mainExecutableMH->intersectsRange(SHARED_REGION_BASE, SHARED_REGION_SIZE) ) {
@@ -2637,9 +2454,6 @@
 		gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
 	}
 #endif
-#endif
-#if TARGET_OS_SIMULATOR
-	gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
 #endif
 	// iOS cannot run without shared region
 }
@@ -2841,28 +2655,33 @@
 };
 #endif
 
+#if __arm64__
+//
+//     ARM64 sub-type lists
+//
+const int kARM64_RowCount = 2;
+static const cpu_subtype_t kARM64[kARM64_RowCount][4] = {
+
+	// armv64e can run: 64e, 64
+	{  CPU_SUBTYPE_ARM64E, CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST },
+
+	// armv64 can run: 64
+	{  CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST },
+};
+
 #if __ARM64_ARCH_8_32__
-//
-//    arm64_32 sub-type lists
-//
-	static const cpu_subtype_t kARM64_32[] = { CPU_SUBTYPE_ARM64_32_V8, CPU_SUBTYPE_END_OF_LIST };
-#endif
-
-#if __arm64__ && __LP64__
-//
-//     arm64[e] sub-type handing
-//
-	#if __arm64e__
-		// arm64e with keys on
-		static const cpu_subtype_t kARM64e[]        = { CPU_SUBTYPE_ARM64E, CPU_SUBTYPE_END_OF_LIST };
-		// arm64 or arm64e with keys off
-		static const cpu_subtype_t kARM64eKeysOff[] = { CPU_SUBTYPE_ARM64E, CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST };
-	#else
-		// arm64 main binary
-		static const cpu_subtype_t kARM64[] = { CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST };
-	#endif // __arm64e__
-#endif
-
+const int kARM64_32_RowCount = 2;
+static const cpu_subtype_t kARM64_32[kARM64_32_RowCount][4] = {
+
+	// armv64_32 can run: v8
+	{  CPU_SUBTYPE_ARM64_32_V8, CPU_SUBTYPE_END_OF_LIST },
+
+	// armv64 can run: 64
+	{  CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST },
+};
+#endif
+	
+#endif
 
 #if __x86_64__
 //      
@@ -2894,20 +2713,21 @@
 			break;
 #endif
 #if __arm64__
-	#if __LP64__
 		case CPU_TYPE_ARM64:
-		#if __arm64e__
-			return ( sKeysDisabled ? kARM64eKeysOff : kARM64e);
-		#else
-			return kARM64;
-		#endif
+			for (int i=0; i < kARM64_RowCount ; ++i) {
+				if ( kARM64[i][0] == subtype )
+					return kARM64[i];
+			}
 			break;
-	#endif
-
-	#if !__LP64__
+
+#if __ARM64_ARCH_8_32__
 		case CPU_TYPE_ARM64_32:
-			return kARM64_32;
-	#endif
+			for (int i=0; i < kARM64_32_RowCount ; ++i) {
+				if ( kARM64_32[i][0] == subtype )
+					return kARM64_32[i];
+			}
+			break;
+#endif
 
 #endif
 #if __x86_64__
@@ -2923,26 +2743,18 @@
 }
 
 
+
+
 // scan fat table-of-contents for best most preferred subtype
-static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[], const fat_header* fh, int fd, uint64_t* offset, uint64_t* len)
+static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[], const fat_header* fh, uint64_t* offset, uint64_t* len)
 {
 	const fat_arch* const archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
 	for (uint32_t subTypeIndex=0; list[subTypeIndex] != CPU_SUBTYPE_END_OF_LIST; ++subTypeIndex) {
 		for(uint32_t fatIndex=0; fatIndex < OSSwapBigToHostInt32(fh->nfat_arch); ++fatIndex) {
-			cpu_type_t    sliceCpuType    = OSSwapBigToHostInt32(archs[fatIndex].cputype);
-			cpu_subtype_t sliceCpuSubType = OSSwapBigToHostInt32(archs[fatIndex].cpusubtype) & ~CPU_SUBTYPE_MASK;
-			uint64_t      sliceOffset     = OSSwapBigToHostInt32(archs[fatIndex].offset);
-			uint64_t      sliceLen        = OSSwapBigToHostInt32(archs[fatIndex].size);
-			if ( (sliceCpuType == cpu) && ((list[subTypeIndex] & ~CPU_SUBTYPE_MASK) == sliceCpuSubType) ) {
-#if TARGET_OS_OSX && __has_feature(ptrauth_calls)
-				if ( sOnlyPlatformArm64e && (sliceCpuType == CPU_TYPE_ARM64) && (sliceCpuSubType == CPU_SUBTYPE_ARM64E) ) {
-					// if we can only load arm64e slices that are platform binaries, skip over slices that are not
-					if ( !dyld3::MachOAnalyzer::sliceIsOSBinary(fd, sliceOffset, sliceLen) )
-						continue;
-				}
-#endif
-				*offset = sliceOffset;
-				*len    = sliceLen;
+			if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[fatIndex].cputype) == cpu) 
+				&& (list[subTypeIndex] == (cpu_subtype_t)OSSwapBigToHostInt32(archs[fatIndex].cpusubtype)) ) {
+				*offset = OSSwapBigToHostInt32(archs[fatIndex].offset);
+				*len = OSSwapBigToHostInt32(archs[fatIndex].size);
 				return true;
 			}
 		}
@@ -2950,7 +2762,6 @@
 	return false;
 }
 
-#if !TARGET_OS_OSX || !__has_feature(ptrauth_calls)
 // scan fat table-of-contents for exact match of cpu and cpu-sub-type
 static bool fatFindExactMatch(cpu_type_t cpu, cpu_subtype_t subtype, const fat_header* fh, uint64_t* offset, uint64_t* len)
 {
@@ -2965,7 +2776,6 @@
 	}
 	return false;
 }
-#endif
 
 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types
 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t* offset, uint64_t* len)
@@ -3074,7 +2884,7 @@
 // each optimized for a different cpu-sub-type (e.g G3 or G5).
 // This routine picks the optimal sub-image.
 //
-static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len, int fd=-1)
+static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
 {
 	if ( !fatValidate(fh) )
 		return false;
@@ -3090,17 +2900,13 @@
 	
 		// use ordered list to find best sub-image in fat file
 		if ( subTypePreferenceList != NULL ) {
-			if ( fatFindBestFromOrderedList(cpu, subTypePreferenceList, fh, fd, offset, len) )
+			if ( fatFindBestFromOrderedList(cpu, subTypePreferenceList, fh, offset, len) )
 				return true;
 		}
-#if TARGET_OS_OSX && __has_feature(ptrauth_calls)
-		// don't use fallbacks for macOS arm64e to ensure only compatible binaries are loaded
-		return false;
-#else
+
 		// if running cpu is not in list, try for an exact match
 		if ( fatFindExactMatch(cpu, sHostCPUsubtype, fh, offset, len) )
 			return true;
-#endif
 	}
 	
 	// running on an uknown cpu, can only load generic code
@@ -3119,21 +2925,12 @@
 #endif
 }
 
-#if defined(__x86_64__) && !TARGET_OS_SIMULATOR
-#ifndef kIsTranslated
-   #define kIsTranslated  0x4000000000000000ULL
-#endif
-bool isTranslated()
-{
-	return ((*(uint64_t*)_COMM_PAGE_CPU_CAPABILITIES64) & kIsTranslated);
-}
-#endif
 
 
 //
 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
 // on the current processor. //
-bool isCompatibleMachO(const uint8_t* firstPage, const char* path, int fd=-1, uint64_t sliceOffset=0, uint64_t sliceLen=-1)
+bool isCompatibleMachO(const uint8_t* firstPage, const char* path)
 {
 #if CPU_SUBTYPES_SUPPORTED
 	// It is deemed compatible if any of the following are true:
@@ -3144,31 +2941,22 @@
 	if ( mh->magic == sMainExecutableMachHeader->magic ) {
 		if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
 			if ( mh->cputype == sHostCPU ) {
-				const cpu_subtype_t mhCPUSubtype = mh->cpusubtype & ~CPU_SUBTYPE_MASK;
 				// get preference ordered list of subtypes that this machine can use
 				const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(mh->cputype, sHostCPUsubtype);
 				if ( subTypePreferenceList != NULL ) {
 					// if image's subtype is in the list, it is compatible
 					for (const cpu_subtype_t* p = subTypePreferenceList; *p != CPU_SUBTYPE_END_OF_LIST; ++p) {
-						if ( *p == mhCPUSubtype ) {
-	#if TARGET_OS_OSX && __has_feature(ptrauth_calls)
-							if ( mhCPUSubtype == CPU_SUBTYPE_ARM64E ) {
-								if ( !sOnlyPlatformArm64e || dyld3::MachOAnalyzer::sliceIsOSBinary(fd, sliceOffset, sliceLen) )
-									return true;
-							}
-							else
-	#endif
+						if ( *p == mh->cpusubtype )
 							return true;
-						}
 					}
 					// have list and not in list, so not compatible
-					throwf("incompatible cpu-subtype: 0x%08X in %s", mhCPUSubtype, path);
+					throwf("incompatible cpu-subtype: 0x%08X in %s", mh->cpusubtype, path);
 				}
 				// unknown cpu sub-type, but if exact match for current subtype then ok to use
-				if ( mhCPUSubtype == sHostCPUsubtype )
+				if ( mh->cpusubtype == sHostCPUsubtype ) 
 					return true;
 			}
-
+			
 			// cpu type has no ordered list of subtypes
 			switch (mh->cputype) {
 				case CPU_TYPE_I386:
@@ -3199,13 +2987,13 @@
 static ImageLoaderMachO* instantiateFromLoadedImage(const macho_header* mh, uintptr_t slide, const char* path)
 {
 	// try mach-o loader
-//	if ( isCompatibleMachO((const uint8_t*)mh, path) ) {
+	if ( isCompatibleMachO((const uint8_t*)mh, path) ) {
 		ImageLoader* image = ImageLoaderMachO::instantiateMainExecutable(mh, slide, path, gLinkContext);
 		addImage(image);
 		return (ImageLoaderMachO*)image;
-//	}
+	}
 	
-//	throw "main executable not a known format";
+	throw "main executable not a known format";
 }
 
 #if SUPPORT_ACCELERATE_TABLES
@@ -3323,7 +3111,7 @@
 				    (strcmp(path, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0) ||
 				    (strcmp(path, "/sbin/launchd_sim_trampoline") == 0) ||
 				    (strcmp(path, "/usr/sbin/iokitsimd") == 0) ||
-					(strcmp(path, "/usr/lib/system/host/liblaunch_sim.dylib") == 0))
+				    (strcmp(path, "/usr/lib/system/host/liblaunch_sim.dylib") == 0))
 					return true;
 				return false;
 			case LC_BUILD_VERSION:
@@ -3336,6 +3124,10 @@
 					case PLATFORM_WATCHOSSIMULATOR:
 					case PLATFORM_WATCHOS:
 						return true;
+	#if TARGET_OS_IOSMAC
+					case 6:
+						return true;
+	#endif
 					case PLATFORM_MACOS:
 						if ((strcmp(path, "/usr/lib/system/libsystem_kernel.dylib") == 0) ||
 							(strcmp(path, "/usr/lib/system/libsystem_platform.dylib") == 0) ||
@@ -3357,6 +3149,31 @@
 }
 #endif
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+static bool iOSonMacDenied(const char* path)
+{
+	static char*  blackListBuffer 	= nullptr;
+	static size_t blackListSize 	= 0;
+	static bool   tried 			= false;
+	if ( !tried ) {
+		// only try to map file once
+		blackListBuffer = (char*)mapFileReadOnly("/System/iOSSupport/dyld/macOS-deny-list.txt", blackListSize);
+		tried = true;
+	}
+	__block bool result = false;
+	if ( blackListBuffer != nullptr ) {
+		dyld3::forEachLineInFile(blackListBuffer, blackListSize, ^(const char* line, bool& stop) {
+			// lines in the file are prefixes.  Any path that starts with one of these lines is allowed to be unzippered
+			size_t lineLen = strlen(line);
+			if ( (*line == '/') && strncmp(line, path, lineLen) == 0 ) {
+				result = true;
+				stop = true;
+			}
+		});
+	}
+	return result;
+}
+#endif
 
 // map in file and instantiate an ImageLoader
 static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char* path, const LoadContext& context)
@@ -3370,6 +3187,7 @@
 		throw "not a file";
 
 	uint8_t firstPages[MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE];
+	uint8_t *firstPagesPtr = firstPages;
 	bool shortPage = false;
 	
 	// min mach-o file is 4K
@@ -3389,7 +3207,7 @@
 	if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
 		if ( OSSwapBigToHostInt32(fileStartAsFat->nfat_arch) > ((4096 - sizeof(fat_header)) / sizeof(fat_arch)) )
 			throwf("fat header too large: %u entries", OSSwapBigToHostInt32(fileStartAsFat->nfat_arch));
-		if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength, fd) ) {
+		if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
 			if ( (fileOffset+fileLength) > (uint64_t)(stat_buf.st_size) )
 				throwf("truncated fat file.  file length=%llu, but needed slice goes to %llu", stat_buf.st_size, fileOffset+fileLength);
 			if (pread(fd, firstPages, 4096, fileOffset) != 4096)
@@ -3404,7 +3222,7 @@
 	if ( shortPage ) 
 		throw "file too short";
 
-	if ( isCompatibleMachO(firstPages, path, fd, fileOffset, fileLength) ) {
+	if ( isCompatibleMachO(firstPages, path) ) {
 
 		// only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
 		const mach_header* mh = (mach_header*)firstPages;
@@ -3418,45 +3236,60 @@
 		}
 
 		uint32_t headerAndLoadCommandsSize = sizeof(macho_header) + mh->sizeofcmds;
+		if ( headerAndLoadCommandsSize > MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE )
+			throwf("malformed mach-o: load commands size (%u) > %u", headerAndLoadCommandsSize, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE);
+
 		if ( headerAndLoadCommandsSize > fileLength )
 			dyld::throwf("malformed mach-o: load commands size (%u) > mach-o file size (%llu)", headerAndLoadCommandsSize, fileLength);
 
-		vm_address_t vmAllocatedFirstPages = 0;
-		if ( headerAndLoadCommandsSize > MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE ) {
-			if ( ::vm_allocate(mach_task_self(), &vmAllocatedFirstPages, headerAndLoadCommandsSize, VM_FLAGS_ANYWHERE) == 0 ) {
-				if ( ::pread(fd, (void*)vmAllocatedFirstPages, headerAndLoadCommandsSize, fileOffset) != headerAndLoadCommandsSize )
-					throwf("pread of all load commands failed: %d", errno);
-				mh = (mach_header*)vmAllocatedFirstPages;
-			}
-			else {
-				throwf("malformed mach-o: load commands size (%u) > %u", headerAndLoadCommandsSize, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE);
-			}
-		}
-		else if ( headerAndLoadCommandsSize > 4096 ) {
+		if ( headerAndLoadCommandsSize > 4096 ) {
 			// read more pages
 			unsigned readAmount = headerAndLoadCommandsSize - 4096;
 			if ( pread(fd, &firstPages[4096], readAmount, fileOffset+4096) != readAmount )
 				throwf("pread of extra load commands past 4KB failed: %d", errno);
 		}
 
-		if ( !((dyld3::MachOFile*)mh)->loadableIntoProcess((dyld3::Platform)gProcessInfo->platform, path) ) {
-			throwf("mach-o, but not built for platform %s", dyld3::MachOFile::platformName((dyld3::Platform)gProcessInfo->platform));
-		}
-
-#if __has_feature(ptrauth_calls)
-		if ( !sKeysDisabled && ((sMainExecutableMachHeader->cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E) && ((mh->cpusubtype & ~CPU_SUBTYPE_MASK) != CPU_SUBTYPE_ARM64E) )
+#if TARGET_OS_SIMULATOR	
+		// <rdar://problem/14168872> dyld_sim should restrict loading osx binaries
+		if ( !isSimulatorBinary(firstPages, path) ) {
+	#if TARGET_OS_WATCH
+			throw "mach-o, but not built for watchOS simulator";
+	#elif TARGET_OS_TV
+			throw "mach-o, but not built for tvOS simulator";
+	#else
+			throw "mach-o, but not built for iOS simulator";
+	#endif
+		}
+#endif
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+		if ( gLinkContext.iOSonMac ) {
+			const dyld3::MachOFile* mf = (dyld3::MachOFile*)firstPages;
+			bool supportsiOSMac = mf->supportsPlatform(dyld3::Platform::iOSMac);
+			if ( !supportsiOSMac && iOSonMacDenied(path) ) {
+				throw "mach-o, but not built for UIKitForMac";
+			}
+		}
+		else if ( gLinkContext.driverKit ) {
+			const dyld3::MachOFile* mf = (dyld3::MachOFile*)firstPages;
+			bool isDriverKitDylib = mf->supportsPlatform(dyld3::Platform::driverKit);
+			if ( !isDriverKitDylib ) {
+				throw "mach-o, but not built for driverkit";
+			}
+		}
+#endif
+
+#if __arm64e__
+		if ( (sMainExecutableMachHeader->cpusubtype == CPU_SUBTYPE_ARM64E) && (mh->cpusubtype != CPU_SUBTYPE_ARM64E) )
 			throw "arm64 dylibs cannot be loaded into arm64e processes";
 #endif
 		ImageLoader* image = nullptr;
 		{
 			dyld3::ScopedTimer timer(DBG_DYLD_TIMING_MAP_IMAGE, path, 0, 0);
-			image = ImageLoaderMachO::instantiateFromFile(path, fd, (uint8_t*)mh, headerAndLoadCommandsSize, fileOffset, fileLength, stat_buf, gLinkContext);
+			image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPagesPtr, headerAndLoadCommandsSize, fileOffset, fileLength, stat_buf, gLinkContext);
 			timer.setData4((uint64_t)image->machHeader());
 		}
-
-		if ( vmAllocatedFirstPages != 0 )
-			::vm_deallocate(mach_task_self(), (vm_address_t)vmAllocatedFirstPages, headerAndLoadCommandsSize);
-
+		
 		// validate
 		return checkandAddImage(image, context);
 	}
@@ -3523,8 +3356,6 @@
 	return false;
 }
 
-static ImageLoader* loadPhase5check(const char* path, const char* orgPath, const LoadContext& context);
-
 
 // try to open file
 static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
@@ -3560,6 +3391,13 @@
 #else
 
 	auto findSharedCacheImage = ^() {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+		if ( gLinkContext.iOSonMac ) {
+			// On iOSMac, we are also running with DYLD_ROOT_PATH set, but want to look up the orgPath
+			if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, orgPath, &shareCacheResults) )
+				return true;
+		}
+#endif
 		return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults);
 	};
 
@@ -3575,7 +3413,7 @@
 		// if RTLD_NOLOAD, do nothing if not already loaded
 		if ( context.dontLoad ) {
 			// <rdar://33412890> possible that there is an override of cache
-			if ( dyld3::stat(path, &statBuf) == 0 ) {
+			if ( my_stat(path, &statBuf) == 0 ) {
 				ImageLoader* imageLoader = findLoadedImage(statBuf);
 				if ( imageLoader != NULL )
 					return imageLoader;
@@ -3585,7 +3423,7 @@
 		bool useCache = false;
 		if ( shareCacheResults.image == nullptr ) {
 			// HACK to support old caches
-			existsOnDisk = ( dyld3::stat(path, &statBuf) == 0 );
+			existsOnDisk = ( my_stat(path, &statBuf) == 0 );
 			didStat = true;
 			statErrNo = errno;
 			useCache = !existsOnDisk;
@@ -3594,58 +3432,44 @@
 			// <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache
 			bzero(&statBuf, sizeof(statBuf));
 			if ( shareCacheResults.image->overridableDylib() ) {
-				existsOnDisk = ( dyld3::stat(path, &statBuf) == 0 );
+				existsOnDisk = ( my_stat(path, &statBuf) == 0 );
+				didStat = true;
 				statErrNo = errno;
 				if ( sSharedCacheLoadInfo.loadAddress->header.dylibsExpectedOnDisk ) {
-					// old style macOS with dylibs on disk
 					uint64_t expectedINode;
 					uint64_t expectedMtime;
 					if ( shareCacheResults.image->hasFileModTimeAndInode(expectedINode, expectedMtime) ) {
-						// if dylib found has same inode/mtime as one in cache, use one in cache
 						if ( (expectedMtime == statBuf.st_mtime) && (expectedINode == statBuf.st_ino) )
 							useCache = true;
 					}
 				}
 				else {
-					// MRM style where dylibs are not on disk
-					if ( !existsOnDisk ) {
-						// looking at path where dylib should be, and we expect it to not be there but rather in the cache
-						// Its possible we are looking at a deleted symlink path.  For example, we are trying to open .../AppKit but
-						// there's already a loaded root of .../Versions/C/AppKit.  That used to work when the symlink was on-disk as
-						// we'd realpath to find the shared cache path.  Now we record the aliases in the cache and delete the symlinks.
-						const char* pathInSharedCache = shareCacheResults.image->path();
-						if ( strcmp(path, pathInSharedCache) != 0 ) {
-							ImageLoader* imageLoader = loadPhase5check(pathInSharedCache, orgPath, context);
-							if ( imageLoader != NULL )
-								return imageLoader;
-						}
+					if ( !existsOnDisk )
 						useCache = true;
-					}
-					else if ( !sRootsChecker.onDiskFileIsRoot(path, sSharedCacheLoadInfo.loadAddress,
-															  shareCacheResults.image, nullptr, statBuf.st_ino, statBuf.st_mtime) ) {
-						// we found a file on disk, at the same path as the dyld cache has a dylib and it is one of the magic three
-						useCache = true;
-					}
 				}
 			}
 			else {
-				// we are trying to override a dylib in the cache that does not allow overrides, ignore override and use cache
 				useCache = true;
 			}
 		}
 		if ( useCache ) {
-			const dyld3::MachOFile* cacheDylibMH = (dyld3::MachOFile*)shareCacheResults.mhInCache;
-			if ( !cacheDylibMH->loadableIntoProcess((dyld3::Platform)gProcessInfo->platform, path) )
-				throwf("mach-o, but not built for platform %s", dyld3::MachOFile::platformName((dyld3::Platform)gProcessInfo->platform));
-
-			ImageLoader* imageLoader = ImageLoaderMachO::instantiateFromCache((macho_header*)cacheDylibMH, shareCacheResults.pathInCache, shareCacheResults.slideInCache, statBuf, gLinkContext);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+			if ( gLinkContext.iOSonMac ) {
+				const dyld3::MachOFile* mf = (dyld3::MachOFile*)shareCacheResults.mhInCache;
+				bool supportsiOSMac = mf->supportsPlatform(dyld3::Platform::iOSMac);
+				if ( !supportsiOSMac && iOSonMacDenied(path) ) {
+					throw "mach-o, but not built for UIKitForMac";
+				}
+			}
+#endif
+			ImageLoader* imageLoader = ImageLoaderMachO::instantiateFromCache((macho_header*)shareCacheResults.mhInCache, shareCacheResults.pathInCache, shareCacheResults.slideInCache, statBuf, gLinkContext);
 			return checkandAddImage(imageLoader, context);
 		}
 	}
 
 	// not in cache or cache not usable
 	if ( !didStat ) {
-		existsOnDisk = ( dyld3::stat(path, &statBuf) == 0 );
+		existsOnDisk = ( my_stat(path, &statBuf) == 0 );
 		statErrNo = errno;
 	}
 	if ( existsOnDisk ) {
@@ -3924,18 +3748,8 @@
 				if ( image != NULL ) {
 					// if original path is in the dyld cache, then mark this one found as an override
 					dyld3::SharedCacheFindDylibResults shareCacheResults;
-					if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) ) {
+					if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) )
 						image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
-					}
-#if SUPPORT_ROOT_PATH
-					else if ( (gLinkContext.rootPaths != nullptr)
-							   && dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, orgPath, &shareCacheResults)
-							   && (shareCacheResults.image != nullptr) ) {
-						// DYLD_ROOT_PATH, ie, iOSMac, also needs to check if the original path is overridden
-						// as the root prefix has been applied to 'path', but the framework path searches without a root path prefix
-						image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
-					}
-#endif
 					return image;
 				}
 			}
@@ -3958,21 +3772,11 @@
 				image = loadPhase2cache(libpath, orgPath, context, cacheIndex, exceptions);
 			if ( image != NULL ) {
 				// if original path is in the dyld cache, then mark this one found as an override
-			    dyld3::SharedCacheFindDylibResults shareCacheResults;
-			    if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) ) {
-				    image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
-			    }
-#if SUPPORT_ROOT_PATH
-				else if ( (gLinkContext.rootPaths != nullptr)
-						   && dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, orgPath, &shareCacheResults)
-						   && (shareCacheResults.image != nullptr) ) {
-				    // DYLD_ROOT_PATH, ie, iOSMac, also needs to check if the original path is overridden
-				    // as the root prefix has been applied to 'path', but the library path searches without a root path prefix
-				    image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
-			    }
-#endif
-			    return image;
-		   }
+				dyld3::SharedCacheFindDylibResults shareCacheResults;
+				if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) )
+					image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
+				return image;
+			}
 		}
 	}
 	return NULL;
@@ -4047,7 +3851,7 @@
 {
 	//dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	// handle macOS dylibs dlopen()ing versioned path which needs to map to flat path in mazipan simulator
 	if ( gLinkContext.iOSonMac && strstr(path, ".framework/Versions/")) {
 		uintptr_t sourceOffset = 0;
@@ -4145,11 +3949,6 @@
 		if ( !gSharedCacheOverridden && !image->inSharedCache() && image->isDylib() && dyld3::MachOFile::isSharedCacheEligiblePath(path) && inSharedCache(path) ) {
 			gSharedCacheOverridden = true;
 		}
-		// <rdar://problem/59327556> if file loaded via symlink to a root of something in dyld cache, mark it as an override
-		dyld3::SharedCacheFindDylibResults shareCacheResults;
-		if ( !image->inSharedCache() && dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, image->getRealPath(), &shareCacheResults) && (shareCacheResults.image != nullptr) )
-			image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
-		
 		return image;
 	}
 	else if ( exceptions.size() == 0 ) {
@@ -4180,20 +3979,19 @@
 
 
 
-static void mapSharedCache(uintptr_t mainExecutableSlide)
+static void mapSharedCache()
 {
 	dyld3::SharedCacheOptions opts;
 	opts.cacheDirOverride	= sSharedCacheOverrideDir;
 	opts.forcePrivate		= (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion);
+
+
 #if __x86_64__ && !TARGET_OS_SIMULATOR
 	opts.useHaswell			= sHaswell;
 #else
 	opts.useHaswell			= false;
 #endif
 	opts.verbose			= gLinkContext.verboseMapping;
-    // <rdar://problem/32031197> respect -disable_aslr boot-arg
-    // <rdar://problem/56299169> kern.bootargs is now blocked
-	opts.disableASLR		= (mainExecutableSlide == 0) && dyld3::internalInstall(); // infer ASLR is off if main executable is not slid
 	loadDyldCache(opts, &sSharedCacheLoadInfo);
 
 	// update global state
@@ -4206,7 +4004,7 @@
 		dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_SHARED_CACHE_A, sSharedCacheLoadInfo.path, (const uuid_t *)&dyld::gProcessInfo->sharedCacheUUID[0], {0,0}, {{ 0, 0 }}, (const mach_header *)sSharedCacheLoadInfo.loadAddress);
 	}
 
-//#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+//#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 // RAM disk booting does not have shared cache yet
 // Don't make lack of a shared cache fatal in that case
 //	if ( sSharedCacheLoadInfo.loadAddress == nullptr ) {
@@ -4390,24 +4188,6 @@
 		strlcat(error_string, sSharedCacheLoadInfo.errorMessage, sizeof(error_string));
 		strlcat(error_string, "\n", sizeof(error_string));
 		strlcat(error_string, message, sizeof(error_string));
-	} else if ( dyld::gProcessInfo->errorKind == DYLD_EXIT_REASON_DYLIB_MISSING ) {
-		// If a dylib is missing, but we have the cache, print the cache UUID to make it easier
-		// to see what might have gone wrong
-		if ( sSharedCacheLoadInfo.loadAddress == nullptr ) {
-			strlcpy(error_string, "dyld: No shared cache present\n", sizeof(error_string));
-		} else {
-			uuid_t cacheUUID;
-			sSharedCacheLoadInfo.loadAddress->getUUID(cacheUUID);
-			uuid_string_t uuidStr;
-			uuid_unparse_upper(cacheUUID, uuidStr);
-
-			strlcpy(error_string, "dyld: Using shared cache: ", sizeof(error_string));
-			strlcat(error_string, uuidStr, sizeof(error_string));
-			strlcat(error_string, "\n", sizeof(error_string));
-		}
-
-		dyld::log("dyld: %s\n", message);
-		strlcat(error_string, message, sizeof(error_string));
 	}
 	else {
 		dyld::log("dyld: %s\n", message);
@@ -4479,8 +4259,7 @@
 	#endif
 		if ( target == NULL )
 			throwf("image not found for lazy pointer at %p", lazyPointer);
-		DyldSharedCache::DataConstLazyScopedWriter patcher(gLinkContext.dyldCache, mach_task_self(), gLinkContext.verboseMapping ? &dyld::log : nullptr);
-		result = target->doBindLazySymbol(lazyPointer, gLinkContext, patcher);
+		result = target->doBindLazySymbol(lazyPointer, gLinkContext);
 	}
 	catch (const char* message) {
 		dyld::log("dyld: lazy symbol binding failed: %s\n", message);
@@ -4952,7 +4731,7 @@
 // Its presences means that the binary wants to have DYLD ignore
 // DYLD_ environment variables.
 //
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 static bool hasRestrictedSegment(const macho_header* mh)
 {
 	const uint32_t cmd_count = mh->ncmds;
@@ -4983,7 +4762,7 @@
 }
 #endif
 
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 static bool isFairPlayEncrypted(const macho_header* mh)
 {
 	const uint32_t cmd_count = mh->ncmds;
@@ -5003,9 +4782,7 @@
 
 #if SUPPORT_VERSIONED_PATHS
 
-#define FIRST_PAGE_BUFFER_SIZE	16384
-
-static bool readFirstPage(const char* dylibPath, uint8_t firstPage[FIRST_PAGE_BUFFER_SIZE])
+static bool readFirstPage(const char* dylibPath, uint8_t firstPage[4096]) 
 {
 	firstPage[0] = 0;
 	// open file (automagically closed when this function exits)
@@ -5014,7 +4791,7 @@
 	if ( file.getFileDescriptor() == -1 ) 
 		return false;
 	
-	if ( pread(file.getFileDescriptor(), firstPage, FIRST_PAGE_BUFFER_SIZE, 0) != FIRST_PAGE_BUFFER_SIZE )
+	if ( pread(file.getFileDescriptor(), firstPage, 4096, 0) != 4096 )
 		return false;
 
 	// if fat wrapper, find usable sub-file
@@ -5023,7 +4800,7 @@
 		uint64_t fileOffset;
 		uint64_t fileLength;
 		if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
-			if ( pread(file.getFileDescriptor(), firstPage, FIRST_PAGE_BUFFER_SIZE, fileOffset) != FIRST_PAGE_BUFFER_SIZE )
+			if ( pread(file.getFileDescriptor(), firstPage, 4096, fileOffset) != 4096 )
 				return false;
 		}
 		else {
@@ -5040,7 +4817,7 @@
 //
 static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName)
 {
-	uint8_t firstPage[FIRST_PAGE_BUFFER_SIZE];
+	uint8_t firstPage[4096];
 	const macho_header* mh = (macho_header*)firstPage;
 	if ( !readFirstPage(dylibPath, firstPage) ) {
 		// If file cannot be read, check to see if path is in shared cache
@@ -5061,7 +4838,7 @@
 	// scan load commands for LC_ID_DYLIB
 	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)+FIRST_PAGE_BUFFER_SIZE);
+	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) {
@@ -5314,21 +5091,18 @@
 	uint64_t amfiInputFlags = 0;
 #if TARGET_OS_SIMULATOR
 	amfiInputFlags |= AMFI_DYLD_INPUT_PROC_IN_SIMULATOR;
-#elif TARGET_OS_OSX
+#elif __MAC_OS_X_VERSION_MIN_REQUIRED
 	if ( hasRestrictedSegment(mainExecutableMH) )
 		amfiInputFlags |= AMFI_DYLD_INPUT_PROC_HAS_RESTRICT_SEG;
-#elif TARGET_OS_IPHONE
+#elif __IPHONE_OS_VERSION_MIN_REQUIRED
 	if ( isFairPlayEncrypted(mainExecutableMH) )
 		amfiInputFlags |= AMFI_DYLD_INPUT_PROC_IS_ENCRYPTED;
 #endif
 	uint64_t amfiOutputFlags = 0;
 	const char* amfiFake = nullptr;
-	if constexpr(BUILD_FOR_TESTING == 1) {
+	if ( dyld3::internalInstall() && dyld3::BootArgs::enableDyldTestMode() ) {
 		amfiFake = _simple_getenv(envp, "DYLD_AMFI_FAKE");
-	} else if ( dyld3::internalInstall() && dyld3::BootArgs::enableDyldTestMode() ) {
-		amfiFake = _simple_getenv(envp, "DYLD_AMFI_FAKE");
-	}
-
+	}
 	if ( amfiFake != nullptr ) {
 		amfiOutputFlags = hexToUInt64(amfiFake, nullptr);
 	}
@@ -5346,7 +5120,7 @@
 #endif
 	}
 	else {
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 		// support chrooting from old kernel
 		bool isRestricted = false;
 		bool libraryValidation = false;
@@ -5383,15 +5157,15 @@
 // called by _dyld_register_driverkit_main()
 void setMainEntry(void (*main)())
 {
-	if ( sEntryOverride == nullptr )
-		sEntryOverride = main;
+	if ( sEntryOveride == nullptr )
+		sEntryOveride = main;
 	else
 		halt("_dyld_register_driverkit_main() may only be called once");
 }
 
 bool processIsRestricted()
 {
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	return !gLinkContext.allowEnvVarsPath;
 #else
 	return false;
@@ -5430,7 +5204,7 @@
 	fsobj_id_t fsobj_id = {0};
 	if (endptr != nullptr) {
 		fsobj_id_scalar = hexToUInt64(endptr+1, &endptr);
-		fsobj_id = *reinterpret_cast<fsobj_id_t *>(&fsobj_id_scalar);
+		fsobj_id = *reinterpret_cast<fsobj_id_t *>(&tmp);
 	}
 	const uint32_t cmd_count = mh->ncmds;
 	const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
@@ -5452,10 +5226,10 @@
 	}
 }
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 static void* getProcessInfo() { return dyld::gProcessInfo; }
 static const SyscallHelpers sSysCalls = {
-		14,
+		12,
 		// added in version 1
 		&open,
 		&close, 
@@ -5500,7 +5274,7 @@
 		&getpid,
 		&mach_port_insert_right,
 		&mach_port_allocate,
-		&mach_msg_sim_interposed,
+		&mach_msg,
 		// Added in version 6
 		&abort_with_payload,
 		// Added in version 7
@@ -5525,12 +5299,7 @@
 		// Add in version 12
 		&mach_msg_destroy,
 		&mach_port_construct,
-		&mach_port_destruct,
-		// Added in version 13
-		&fstat,
-		&vm_copy,
-		// Added in version 14
-		&task_dyld_process_info_notify_get
+		&mach_port_destruct
 };
 
 __attribute__((noinline))
@@ -5573,7 +5342,7 @@
 		if ( pread(fd, firstPage, 4096, fileOffset) != 4096 )
 			return "pread(dyld_sim) failed";
 	}
-	else if ( !isCompatibleMachO(firstPage, dyldPath, fd, fileOffset, fileLength) ) {
+	else if ( !isCompatibleMachO(firstPage, dyldPath) ) {
 		return "dyld_sim is not compatible with the loaded process, likely due to architecture mismatch";
 	}
 	
@@ -5705,22 +5474,34 @@
 	}
 	close(fd);
 
-	// Walk newly mapped dyld_sim load commands to find entry point
+	// walk newly mapped dyld_sim __TEXT load commands to find entry point
 	uintptr_t entry = 0;
-	bool unusedUsesCRT = false;
-	uint64_t entryOffset = 0;
-	if ( !((dyld3::MachOAnalyzer*)loadAddress)->getEntry(entryOffset, unusedUsesCRT) ) {
+	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 "dyld_sim entry point not in __TEXT segment";
+			if ( registers->__eip > (firstSeg->vmaddr + firstSeg->vmsize) )
+				return "dyld_sim entry point not in __TEXT segment";
+			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 "dyld_sim entry point not in __TEXT segment";
+			if ( registers->__rip > (firstSeg->vmaddr + firstSeg->vmsize) )
+				return "dyld_sim entry point not in __TEXT segment";
+			entry = (registers->__rip + loadAddress - preferredLoadAddress);
+		#endif
+		}
+		cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+	}
+	if ( entry == 0 )
 		return "dyld_sim entry not found";
-	}
-
-	// Translate the load address by the entry offset in order to get the runtime address.
-	entry = (uintptr_t)loadAddress;
-	entry += entryOffset;
-
-#if __arm64e__
-	// It's necessary to sign the entry pointer.
-	entry = (uint64_t)__builtin_ptrauth_sign_unauthenticated((void*)entry, ptrauth_key_asia, 0);
-#endif
 
 	// notify debugger that dyld_sim is loaded
 	dyld_image_info info;
@@ -5736,7 +5517,7 @@
 	fsobj.fid_objno = (uint32_t)inode;
 	fsobj.fid_generation = (uint32_t)(inode>>32);
 	fsid.val[0] = sb.st_dev;
-	dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A, dyldPath, (const uuid_t *)&uuidCmd->uuid[0], fsobj, fsid, (const mach_header *)loadAddress);
+	dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A, dyldPath, (const uuid_t *)&uuidCmd->uuid[0], fsobj, fsid, (const mach_header *)mh);
 
 	const char** appleParams = apple;
 
@@ -5873,6 +5654,33 @@
 				return false;
 			}
 		}
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+		// verify this closure is not from a previous reboot
+		const char* expectedBootUUID = mainClosure->bootUUID();
+		char actualBootSessionUUID[256] = { 0 };
+		size_t bootSize = sizeof(actualBootSessionUUID);
+		bool gotActualBootUUID = (sysctlbyname("kern.bootsessionuuid", actualBootSessionUUID, &bootSize, NULL, 0) == 0);
+		if ( gotActualBootUUID ) {
+			// If we got a boot UUID then we should have also recorded it in the closure
+			if ( expectedBootUUID == nullptr) {
+				// The closure didn't have a UUID but now we do.  This isn't valid.
+				if ( gLinkContext.verboseWarnings )
+					dyld::log("dyld: closure %p missing boot-UUID\n", mainClosure);
+				return false;
+			} else if ( strcmp(expectedBootUUID, actualBootSessionUUID) != 0 ) {
+				if ( gLinkContext.verboseWarnings )
+					dyld::log("dyld: closure %p built in different boot context\n", mainClosure);
+				return false;
+			}
+		} else {
+			// We didn't get a UUID now, which is ok so long as the closure also doesn't have one.
+			if ( expectedBootUUID != nullptr) {
+				if ( gLinkContext.verboseWarnings )
+					dyld::log("dyld: closure %p has boot-UUID\n", mainClosure);
+				return false;
+			}
+		}
+#endif
 	}
 
 	// verify all mach-o files have not changed since closure was built
@@ -5882,7 +5690,7 @@
 		__block uint64_t expectedMtime;
 		if ( image->hasFileModTimeAndInode(expectedInode, expectedMtime) ) {
 			struct stat statBuf;
-			if ( dyld3::stat(image->path(), &statBuf) == 0 ) {
+			if ( ::stat(image->path(), &statBuf) == 0 ) {
 				if ( (statBuf.st_mtime != expectedMtime) || (statBuf.st_ino != expectedInode) ) {
 					if ( gLinkContext.verboseWarnings )
 						dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure, image->path());
@@ -5902,7 +5710,7 @@
 		return false;
 
 	// verify cdHash of main executable is same as recorded in closure
-	const dyld3::closure::Image* mainImage = mainClosure->topImage();
+	const dyld3::closure::Image* mainImage = mainClosure->images()->imageForNum(mainClosure->topImage());
 
 	__block bool foundCDHash = false;
 	__block bool foundValidCDHash = false;
@@ -5986,7 +5794,7 @@
 	// verify files that are supposed to be missing actually are missing
 	mainClosure->forEachMustBeMissingFile(^(const char* path, bool& stop) {
 		struct stat statBuf;
-		if ( dyld3::stat(path, &statBuf) == 0 ) {
+		if ( ::stat(path, &statBuf) == 0 ) {
 			stop = true;
 			foundFileThatInvalidatesClosure = true;
 			if ( gLinkContext.verboseWarnings )
@@ -5997,7 +5805,7 @@
 	// verify files that are supposed to exist are there with the
 	mainClosure->forEachSkipIfExistsFile(^(const dyld3::closure::LaunchClosure::SkippedFile &file, bool &stop) {
 		struct stat statBuf;
-		if ( dyld3::stat(file.path, &statBuf) == 0 ) {
+		if ( ::stat(file.path, &statBuf) == 0 ) {
 			if ( (statBuf.st_mtime != file.mtime) || (statBuf.st_ino != file.inode) ) {
 				if ( gLinkContext.verboseWarnings )
 					dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure, file.path);
@@ -6043,12 +5851,9 @@
 static bool launchWithClosure(const dyld3::closure::LaunchClosure* mainClosure,
 							  const DyldSharedCache* dyldCache,
 							  const dyld3::MachOLoaded* mainExecutableMH, uintptr_t mainExecutableSlide,
-							  int argc, const char* argv[], const char* envp[], const char* apple[], Diagnostics& diag,
-							  uintptr_t* entry, uintptr_t* startGlue, bool* closureOutOfDate, bool* recoverable)
-{
-	*closureOutOfDate = false;
-	*recoverable      = true;
-
+							  int argc, const char* argv[], const char* envp[], const char* apple[],
+							  uintptr_t* entry, uintptr_t* startGlue)
+{
 	// build list of all known ImageArrays (at most three: cached dylibs, other OS dylibs, and main prog)
 	STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray*, imagesArrays, 3);
 	const dyld3::closure::ImageArray* mainClosureImages = mainClosure->images();
@@ -6061,23 +5866,19 @@
 
 	// allocate space for Array<LoadedImage>
 	STACK_ALLOC_ARRAY(dyld3::LoadedImage, allImages, mainClosure->initialLoadCount());
-	STACK_ALLOC_ARRAY(dyld3::LoadedImage, noImages, 1);
 
 	// Get the pre-optimized Objective-C so that we can bind the selectors
 	const dyld3::closure::ObjCSelectorOpt* 					selectorOpt = nullptr;
 	dyld3::Array<dyld3::closure::Image::ObjCSelectorImage> 	selectorImages;
 	mainClosure->selectorHashTable(selectorImages, selectorOpt);
 
-	__block dyld3::Loader loader(noImages, allImages, dyldCache, imagesArrays,
-								 selectorOpt, selectorImages, sRootsChecker,
-								 (dyld3::Platform)gProcessInfo->platform,
+	__block dyld3::Loader loader({}, allImages, dyldCache, imagesArrays,
+								 selectorOpt, selectorImages,
 								 (gLinkContext.verboseLoading ? &dolog : &nolog),
 								 (gLinkContext.verboseMapping ? &dolog : &nolog),
 								 (gLinkContext.verboseBind    ? &dolog : &nolog),
-								 (gLinkContext.verboseDOF     ? &dolog : &nolog),
-								 (sClosureKind == ClosureKind::minimal),
-								 (dyld3::LaunchErrorInfo*)&gProcessInfo->errorKind);
-	dyld3::closure::ImageNum mainImageNum = mainClosure->topImageNum();
+								 (gLinkContext.verboseDOF     ? &dolog : &nolog));
+	dyld3::closure::ImageNum mainImageNum = mainClosure->topImage();
 	mainClosureImages->forEachImage(^(const dyld3::closure::Image* image, bool& stop) {
 		if ( image->imageNum() == mainImageNum ) {
 			// add main executable (which is already mapped by kernel) to list
@@ -6095,32 +5896,13 @@
 
 	// recursively load all dependents and fill in allImages array
 	bool someCacheImageOverridden = false;
+	Diagnostics diag;
 	loader.completeAllDependents(diag, someCacheImageOverridden);
 	if ( diag.noError() )
-		loader.mapAndFixupAllImages(diag, dyld3::Loader::dtraceUserProbesEnabled(), false, closureOutOfDate, recoverable);
+		loader.mapAndFixupAllImages(diag, dyld3::Loader::dtraceUserProbesEnabled());
 	if ( diag.hasError() ) {
 		if ( gLinkContext.verboseWarnings )
 			dyld::log("dyld: %s\n", diag.errorMessage());
-		if ( !*recoverable ) {
-			// we won't make it to libDyldEntry, so the image list will never be set up
-			// hack together an image list here so crash reports show the binaries involved
-			__block unsigned loadImageCount = 0;
-			loader.forEachImage(^(const dyld3::LoadedImage& li, bool& stop) {
-				++loadImageCount;
-			});
-			dyld_image_info* tempArray = new dyld_image_info[loadImageCount];
-			__block unsigned i = 0;
-			loader.forEachImage(^(const dyld3::LoadedImage& li, bool& stop) {
-				tempArray[i].imageFilePath    = li.image()->path();
-				tempArray[i].imageLoadAddress = li.loadedAddress();
-				tempArray[i].imageFileModDate = 0;
-				++i;
-			});
-			dyld::gProcessInfo->infoArray        = tempArray;
-			dyld::gProcessInfo->infoArrayCount   = loadImageCount;
-			dyld::gProcessInfo->initialImageCount= loadImageCount;
-			dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time();
-		}
 		return false;
 	}
 
@@ -6134,15 +5916,9 @@
 	mainClosure->libDyldEntry(dyldEntry);
 	const dyld3::LibDyldEntryVector* libDyldEntry = (dyld3::LibDyldEntryVector*)loader.resolveTarget(dyldEntry);
 
-	// Set the logging function first so that libdyld can log from inside all other entry vector functions
-#if !TARGET_OS_SIMULATOR
-	if ( libDyldEntry->vectorVersion > 3 )
-		libDyldEntry->setLogFunction(&dyld::vlog);
-#endif
-
 	// send info on all images to libdyld.dylb
-	libDyldEntry->setVars(mainExecutableMH, argc, argv, envp, apple, sKeysDisabled, sOnlyPlatformArm64e, gEnableSharedCacheDataConst);
-#if TARGET_OS_OSX
+	libDyldEntry->setVars(mainExecutableMH, argc, argv, envp, apple);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	uint32_t progVarsOffset;
 	if ( mainClosure->hasProgramVars(progVarsOffset) ) {
 		if ( libDyldEntry->vectorVersion >= 8 ) {
@@ -6170,14 +5946,13 @@
 
 	if ( libDyldEntry->vectorVersion > 2 )
 		libDyldEntry->setChildForkFunction(&_dyld_fork_child);
-	if ( libDyldEntry->vectorVersion >= 9 )
-		libDyldEntry->setLaunchMode(sLaunchModeUsed);
-
-
+#if !TARGET_OS_SIMULATOR
+	if ( libDyldEntry->vectorVersion > 3 )
+		libDyldEntry->setLogFunction(&dyld::vlog);
+#endif
 	libDyldEntry->setOldAllImageInfo(gProcessInfo);
 	dyld3::LoadedImage* libSys = loader.findImage(mainClosure->libSystemImageNum());
-	libDyldEntry->setInitialImageList(mainClosure, dyldCache, sSharedCacheLoadInfo.path, allImages, *libSys,
-									  mach_task_self());
+	libDyldEntry->setInitialImageList(mainClosure, dyldCache, sSharedCacheLoadInfo.path, allImages, *libSys);
 	// run initializers
 	CRSetCrashLogMessage("dyld3: launch, running initializers");
 	libDyldEntry->runInitialzersBottomUp((mach_header*)mainExecutableMH);
@@ -6186,14 +5961,11 @@
 	if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE)) {
 		dyld3::kdebug_trace_dyld_duration_end(launchTraceID, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE, 0, 0, 3);
 	}
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	if ( gLinkContext.driverKit ) {
-		if (libDyldEntry->vectorVersion >= 10)
-			*entry = (uintptr_t)libDyldEntry->getDriverkitMain();
+		*entry = (uintptr_t)sEntryOveride;
 		if ( *entry == 0 )
 			halt("no entry point registered");
-		if ( sClosureKind != ClosureKind::minimal )
-			halt("driverkit process should run with minimal closures");
 		*startGlue = (uintptr_t)(libDyldEntry->startFunc);
 	}
 	else
@@ -6206,10 +5978,6 @@
 			// set entry to "main" function in program
 			*startGlue = (uintptr_t)(libDyldEntry->startFunc);
 			*entry     = loader.resolveTarget(progEntry);
-#if __has_feature(ptrauth_calls)
-			// start() calls the result pointer as a function pointer so we need to sign it.
-			*entry = (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)*entry, 0, 0);
-#endif
 		}
 		else if ( mainClosure->startEntry(progEntry) ) {
 			// old style app linked with crt1.o
@@ -6226,17 +5994,29 @@
 }
 
 
+static const char* getTempDir(const char* envp[])
+{
+	if (const char* tempDir = _simple_getenv(envp, "TMPDIR"))
+		return tempDir;
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+	return "/private/tmp/";
+#else
+	return "/private/var/tmp/";
+#endif
+}
+
 static const dyld3::closure::LaunchClosure* mapClosureFile(const char* closurePath)
 {
 	struct stat statbuf;
-	if ( dyld3::stat(closurePath, &statbuf) == -1 )
+	if ( ::stat(closurePath, &statbuf) == -1 )
 		return nullptr;
 
 	// check for tombstone file
 	if ( statbuf.st_size == 0 )
 		return nullptr;
 
-	int fd = dyld3::open(closurePath, O_RDONLY, 0);
+	int fd = ::open(closurePath, O_RDONLY);
 	if ( fd < 0 )
 		return nullptr;
 
@@ -6256,11 +6036,10 @@
 	return false;
 }
 
+
 // Note: buildLaunchClosure calls halt() if there is an error building the closure
 static const dyld3::closure::LaunchClosure* buildLaunchClosure(const uint8_t* mainExecutableCDHash,
-															   const dyld3::closure::LoadedFileInfo& mainFileInfo,
-															   const char* envp[],
-															   const dyld3::Array<uint8_t>& bootToken)
+															   const dyld3::closure::LoadedFileInfo& mainFileInfo, const char* envp[])
 {
 	const dyld3::MachOLoaded* mainExecutableMH = (const dyld3::MachOLoaded*)mainFileInfo.fileContent;
 	dyld3::closure::PathOverrides pathOverrides;
@@ -6274,30 +6053,24 @@
 	}
 
 	char closurePath[PATH_MAX];
-	bool canSaveClosureToDisk = !bootToken.empty() && dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo.path, envp, true, closurePath);
-	dyld3::LaunchErrorInfo* errorInfo = (dyld3::LaunchErrorInfo*)&gProcessInfo->errorKind;
-	const dyld3::GradedArchs& archs = dyld3::GradedArchs::forCurrentOS(sKeysDisabled, sOnlyPlatformArm64e);
+	dyld3::closure::ClosureBuilder::LaunchErrorInfo* errorInfo = (dyld3::closure::ClosureBuilder::LaunchErrorInfo*)&gProcessInfo->errorKind;
 	dyld3::closure::FileSystemPhysical fileSystem;
+	const dyld3::GradedArchs& archs = dyld3::GradedArchs::forCurrentOS(mainExecutableMH);
 	dyld3::closure::ClosureBuilder::AtPath atPathHanding = (gLinkContext.allowAtPaths ? dyld3::closure::ClosureBuilder::AtPath::all : dyld3::closure::ClosureBuilder::AtPath::none);
-	dyld3::closure::ClosureBuilder builder(dyld3::closure::kFirstLaunchClosureImageNum, fileSystem, sRootsChecker, sSharedCacheLoadInfo.loadAddress, true,
-										   archs, pathOverrides, atPathHanding, gLinkContext.allowEnvVarsPath, errorInfo, (dyld3::Platform)gProcessInfo->platform);
+	dyld3::closure::ClosureBuilder builder(dyld3::closure::kFirstLaunchClosureImageNum, fileSystem, sSharedCacheLoadInfo.loadAddress, true,
+										   archs, pathOverrides, atPathHanding, gLinkContext.allowEnvVarsPath, errorInfo);
 	if (sForceInvalidSharedCacheClosureFormat)
 		builder.setDyldCacheInvalidFormatVersion();
-	if (sClosureKind == ClosureKind::minimal)
-		builder.makeMinimalClosures();
-	else if ( canSaveClosureToDisk )
-		builder.setCanSkipEncodingRebases(); // <rdar://problem/56172089> large iOS apps with massive number of rebases can overflow 16MB closure file limit
 	if ( !gLinkContext.allowInterposing )
 		builder.disableInterposing();
-
 	const dyld3::closure::LaunchClosure* result = builder.makeLaunchClosure(mainFileInfo, gLinkContext.allowInsertFailures);
 	if ( builder.diagnostics().hasError() ) {
 		const char* errMsg = builder.diagnostics().errorMessage();
 		// let apps with this error fallback to dyld2 mode
 		if ( needsDyld2ErrorMessage(errMsg) ) {
-			if ( canSaveClosureToDisk ) {
+			if ( dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo.path, closurePath, getTempDir(envp), true) ) {
 				// create empty file as a tombstone to not keep trying
-				int fd = dyld3::open(closurePath, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+				int fd = ::open(closurePath, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
 				if ( fd != -1 ) {
 					::fchmod(fd, S_IRUSR);
 					::close(fd);
@@ -6324,24 +6097,8 @@
 			dyld::log("dyld: somehow just built closure is invalid\n");
 		return nullptr;
 	}
-
-	// write closure file but only if we have boot-token
-	if ( canSaveClosureToDisk ) {
-		if ( const dyld3::closure::LaunchClosure* existingClosure = mapClosureFile(closurePath) ) {
-			if ( (existingClosure->size() == result->size()) && (memcmp(existingClosure, result, result->size()) == 0) ) {
-				// closure file already exists and has same content, so re-use file by altering boot-token
-				::chmod(closurePath, S_IRUSR|S_IWUSR); // file has to be writable to alter attributes
-				// handle both attribute size change and missing attribute
-				if ( ::setxattr(closurePath, DYLD_CLOSURE_XATTR_NAME, bootToken.begin(), bootToken.count(), 0, XATTR_REPLACE) != 0 )
-					::setxattr(closurePath, DYLD_CLOSURE_XATTR_NAME, bootToken.begin(), bootToken.count(), 0, 0);
-				::chmod(closurePath, S_IRUSR);
-				result->deallocate();
-				if ( gLinkContext.verboseWarnings )
-					dyld::log("dyld: reusing previous boot %s closure %p (size=%lu) for %s\n", existingClosure->topImage()->variantString(), existingClosure, existingClosure->size(), sExecPath);
-				return existingClosure;
-			}
-		}
-		// make new file
+	// try to atomically save closure to disk to speed up next launch
+	if ( dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo.path, closurePath, getTempDir(envp), true) ) {
 		char closurePathTemp[PATH_MAX];
 		strlcpy(closurePathTemp, closurePath, PATH_MAX);
 		int mypid = getpid();
@@ -6354,22 +6111,20 @@
 		putHexByte(mypid, s);
 		*s = '\0';
 		strlcat(closurePathTemp, pidBuf, PATH_MAX);
-#if TARGET_OS_OSX
-		int fd = dyld3::open(closurePathTemp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+		int fd = ::open(closurePathTemp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
 #else
 		int fd = ::open_dprotected_np(closurePathTemp, O_WRONLY|O_CREAT, PROTECTION_CLASS_D, 0, S_IRUSR|S_IWUSR);
 #endif
 		if ( fd != -1 ) {
 			::ftruncate(fd, result->size());
 			::write(fd, result, result->size());
-			::fsetxattr(fd, DYLD_CLOSURE_XATTR_NAME, bootToken.begin(), bootToken.count(), 0, 0);
 			::fchmod(fd, S_IRUSR);
 			::close(fd);
 			::rename(closurePathTemp, closurePath);
 			// free built closure and mmap file() to reduce dirty memory
 			result->deallocate();
 			result = mapClosureFile(closurePath);
-			sLaunchModeUsed |= DYLD_LAUNCH_MODE_CLOSURE_SAVED_TO_FILE;
 		}
 		else if ( gLinkContext.verboseWarnings ) {
 			dyld::log("could not save closure (errno=%d) to: %s\n", errno, closurePathTemp);
@@ -6377,35 +6132,19 @@
 	}
 
 	if ( gLinkContext.verboseWarnings )
-		dyld::log("dyld: just built %s closure %p (size=%lu) for %s\n", result->topImage()->variantString(), result, result->size(), sExecPath);
+		dyld::log("dyld: just built closure %p (size=%lu) for %s\n", result, result->size(), sExecPath);
 
 	return result;
 }
 
 static const dyld3::closure::LaunchClosure* findCachedLaunchClosure(const uint8_t* mainExecutableCDHash,
 																    const dyld3::closure::LoadedFileInfo& mainFileInfo,
-																	const char* envp[],
-																	const dyld3::Array<uint8_t>& bootToken)
-{
-	// get path to where closure file will be store for this program
+																	const char* envp[])
+{
 	char closurePath[PATH_MAX];
-	if ( !dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo.path, envp, false, closurePath) ) {
-		// if cannot construct path to use/store closure file, then use minimal closures
-		if ( sClosureKind == ClosureKind::unset )
-			sClosureKind = ClosureKind::minimal;
+	// build base path of $TMPDIR/dyld/<prog-name>-
+	if ( !dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo.path, closurePath, getTempDir(envp), false) )
 		return nullptr;
-	}
-
-	// if file exists, but extended attribute is wrong, ignore file (might be re-used later)
-	if ( bootToken.empty() )
-		return nullptr;
-	uint8_t filesBootToken[bootToken.count()];
-	ssize_t attrSize = ::getxattr(closurePath, DYLD_CLOSURE_XATTR_NAME, filesBootToken, bootToken.count(), 0, 0);
-	if ( attrSize != bootToken.count() )
-		return nullptr;
-	if ( memcmp(bootToken.begin(), filesBootToken, bootToken.count()) != 0 )
-		return nullptr;
-
 	const dyld3::closure::LaunchClosure* closure = mapClosureFile(closurePath);
 	if ( closure == nullptr )
 		return nullptr;
@@ -6416,7 +6155,7 @@
 	}
 
 	if ( gLinkContext.verboseWarnings )
-		dyld::log("dyld: used cached %s closure %p (size=%lu) for %s\n", closure->topImage()->variantString(), closure, closure->size(), sExecPath);
+		dyld::log("dyld: used cached closure %p (size=%lu) for %s\n", closure, closure->size(), sExecPath);
 
 	return closure;
 }
@@ -6425,7 +6164,7 @@
 
 	
 static ClosureMode getPlatformDefaultClosureMode() {
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 #if __i386__
 	// rdar://problem/32701418: Don't use dyld3 for i386 for now.
 	return ClosureMode::Off;
@@ -6440,7 +6179,7 @@
 		return ClosureMode::On;
 	else
 		return ClosureMode::Off;
-#endif // TARGET_OS_OSX
+#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
 }
 
 //
@@ -6461,29 +6200,11 @@
 	//Check and see if there are any kernel flags
 	dyld3::BootArgs::setFlags(hexToUInt64(_simple_getenv(apple, "dyld_flags"), nullptr));
 
-#if __has_feature(ptrauth_calls)
-	// Check and see if kernel disabled JOP pointer signing (which lets us load plain arm64 binaries)
-	if ( const char* disableStr = _simple_getenv(apple, "ptrauth_disabled") ) {
-		if ( strcmp(disableStr, "1") == 0 )
-			sKeysDisabled = true;
-	}
-	else {
-		// needed until kernel passes ptrauth_disabled for arm64 main executables
-		if ( (mainExecutableMH->cpusubtype == CPU_SUBTYPE_ARM64_V8) || (mainExecutableMH->cpusubtype == CPU_SUBTYPE_ARM64_ALL) )
-			sKeysDisabled = true;
-	}
-#endif
-
     // Grab the cdHash of the main executable from the environment
 	uint8_t mainExecutableCDHashBuffer[20];
 	const uint8_t* mainExecutableCDHash = nullptr;
-	if ( const char* mainExeCdHashStr = _simple_getenv(apple, "executable_cdhash") ) {
-		unsigned bufferLenUsed;
-		if ( hexStringToBytes(mainExeCdHashStr, mainExecutableCDHashBuffer, sizeof(mainExecutableCDHashBuffer), bufferLenUsed) )
-			mainExecutableCDHash = mainExecutableCDHashBuffer;
-	}
-
-	getHostInfo(mainExecutableMH, mainExecutableSlide);
+	if ( hexToBytes(_simple_getenv(apple, "executable_cdhash"), 40, mainExecutableCDHashBuffer) )
+		mainExecutableCDHash = mainExecutableCDHashBuffer;
 
 #if !TARGET_OS_SIMULATOR
 	// Trace dyld's load
@@ -6499,8 +6220,7 @@
 
 	// Set the platform ID in the all image infos so debuggers can tell the process type
 	// FIXME: This can all be removed once we make the kernel handle it in rdar://43369446
-	// The host may not have the platform field in its struct, but there's space for it in the padding, so always set it
-	{
+	if (gProcessInfo->version >= 16) {
 		__block bool platformFound = false;
 		((dyld3::MachOFile*)mainExecutableMH)->forEachSupportedPlatform(^(dyld3::Platform platform, uint32_t minOS, uint32_t sdk) {
 			if (platformFound) {
@@ -6512,7 +6232,7 @@
 		if (gProcessInfo->platform == (uint32_t)dyld3::Platform::unknown) {
 			// There were no platforms found in the binary. This may occur on macOS for alternate toolchains and old binaries.
 			// It should never occur on any of our embedded platforms.
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 			gProcessInfo->platform = (uint32_t)dyld3::Platform::macOS;
 #else
 			halt("MH_EXECUTE binaries must specify a minimum supported OS version");
@@ -6520,21 +6240,16 @@
 		}
 	}
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 	// Check to see if we need to override the platform
 	const char* forcedPlatform = _simple_getenv(envp, "DYLD_FORCE_PLATFORM");
 	if (forcedPlatform) {
-		dyld_platform_t forcedPlatformType = 0;
-		if (strncmp(forcedPlatform, "6", 1) == 0) {
-			forcedPlatformType = PLATFORM_MACCATALYST;
-		} else if (strncmp(forcedPlatform, "2", 1) == 0) {
-			forcedPlatformType = PLATFORM_IOS;
-		} else  {
-			halt("DYLD_FORCE_PLATFORM is only supported for platform 2 or 6.");
+		if (strncmp(forcedPlatform, "6", 1) != 0) {
+			halt("DYLD_FORCE_PLATFORM is only supported for platform 6");
 		}
 		const dyld3::MachOFile* mf = (dyld3::MachOFile*)sMainExecutableMachHeader;
 		if (mf->allowsAlternatePlatform()) {
-			gProcessInfo->platform = forcedPlatformType;
+			gProcessInfo->platform = PLATFORM_IOSMAC;
 		}
 	}
 
@@ -6545,7 +6260,7 @@
 		char simDyldPath[PATH_MAX]; 
 		strlcpy(simDyldPath, rootPath, PATH_MAX);
 		strlcat(simDyldPath, "/usr/lib/dyld_sim", PATH_MAX);
-		int fd = dyld3::open(simDyldPath, O_RDONLY, 0);
+		int fd = my_open(simDyldPath, O_RDONLY, 0);
 		if ( fd != -1 ) {
 			const char* errMessage = useSimulatorDyld(fd, mainExecutableMH, simDyldPath, argc, argv, envp, apple, startGlue, &result);
 			if ( errMessage != NULL )
@@ -6571,7 +6286,7 @@
 	// <rdar://problem/13868260> Remove interim apple[0] transition code from dyld
 	if (!sExecPath) sExecPath = apple[0];
 
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_OS_SIMULATOR
 	// <rdar://54095622> kernel is not passing a real path for main executable
 	if ( strncmp(sExecPath, "/var/containers/Bundle/Application/", 35) == 0 ) {
 		if ( char* newPath = (char*)malloc(strlen(sExecPath)+10) ) {
@@ -6602,17 +6317,6 @@
 	else
 		sExecShortName = sExecPath;
 
-#if TARGET_OS_OSX && __has_feature(ptrauth_calls)
-	// on Apple Silicon macOS, only Apple signed ("platform binary") arm64e can be loaded
-	sOnlyPlatformArm64e = true;
-
-	// internal builds, or if boot-arg is set, then non-platform-binary arm64e slices can be run
-	if ( const char* abiMode = _simple_getenv(apple, "arm64e_abi") ) {
-		if ( strcmp(abiMode, "all") == 0 )
-			sOnlyPlatformArm64e = false;
-	}
-#endif
-
     configureProcessRestrictions(mainExecutableMH, envp);
 
 	// Check if we should force dyld3.  Note we have to do this outside of the regular env parsing due to AMFI
@@ -6621,13 +6325,20 @@
 			if ( strcmp(useClosures, "0") == 0 ) {
 				sClosureMode = ClosureMode::Off;
 			} else if ( strcmp(useClosures, "1") == 0 ) {
-	#if !__i386__ // don't support dyld3 for 32-bit macOS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+
+#if __i386__
+				// don't support dyld3 for 32-bit macOS
+#else
+				// Also don't support dyld3 for iOSMac right now
+				if ( gProcessInfo->platform != PLATFORM_IOSMAC ) {
+					sClosureMode = ClosureMode::On;
+				}
+#endif // __i386__
+
+#else
 				sClosureMode = ClosureMode::On;
-				sClosureKind = ClosureKind::full;
-	#endif
-			} else if ( strcmp(useClosures, "2") == 0 ) {
-				sClosureMode = ClosureMode::On;
-				sClosureKind = ClosureKind::minimal;
+#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
 			} else {
 				dyld::warn("unknown option to DYLD_USE_CLOSURES.  Valid options are: 0 and 1\n");
 			}
@@ -6635,36 +6346,7 @@
 		}
 	}
 
-	// Check if we should force the shared cache __DATA_CONST to read-only or read-write
-	if ( dyld3::BootArgs::forceReadWriteDataConst() ) {
-		gEnableSharedCacheDataConst = false;
-	} else if ( dyld3::BootArgs::forceReadOnlyDataConst() ) {
-		gEnableSharedCacheDataConst = true;
-	} else {
-		// __DATA_CONST is enabled by default for arm64(e) for now
-#if __arm64__ && __LP64__
-		gEnableSharedCacheDataConst = true;
-#else
-		gEnableSharedCacheDataConst = false;
-#endif
-	}
-	bool sharedCacheDataConstIsEnabled = gEnableSharedCacheDataConst;
-
-	if ( dyld3::internalInstall() ) {
-		if (const char* dataConst = _simple_getenv(envp, "DYLD_SHARED_REGION_DATA_CONST")) {
-			if ( strcmp(dataConst, "RW") == 0 ) {
-				gEnableSharedCacheDataConst = false;
-			} else if ( strcmp(dataConst, "RO") == 0 ) {
-				gEnableSharedCacheDataConst = true;
-			} else {
-				dyld::warn("unknown option to DYLD_SHARED_REGION_DATA_CONST.  Valid options are: RW and RO\n");
-			}
-
-		}
-	}
-
-
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
     if ( !gLinkContext.allowEnvVarsPrint && !gLinkContext.allowEnvVarsPath && !gLinkContext.allowEnvVarsSharedCache ) {
 		pruneEnvironmentVariables(envp, &apple);
 		// set again because envp and apple may have changed or moved
@@ -6676,25 +6358,18 @@
 		checkEnvironmentVariables(envp);
 		defaultUninitializedFallbackPaths(envp);
 	}
-#if TARGET_OS_OSX
-	switch (gProcessInfo->platform) {
-#if (TARGET_OS_OSX && TARGET_CPU_ARM64)
-		case PLATFORM_IOS:
-			sClosureMode = ClosureMode::On; // <rdar://problem/56792308> Run iOS apps on macOS in dyld3 mode
-			[[clang::fallthrough]];
-#endif
-		case PLATFORM_MACCATALYST:
-			gLinkContext.rootPaths = parseColonList("/System/iOSSupport", NULL);
-			gLinkContext.iOSonMac = true;
-			if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == sLibraryFallbackPaths )
-				sEnv.DYLD_FALLBACK_LIBRARY_PATH = sRestrictedLibraryFallbackPaths;
-			if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == sFrameworkFallbackPaths )
-				sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sRestrictedFrameworkFallbackPaths;
-			break;
-		case PLATFORM_DRIVERKIT:
-			gLinkContext.driverKit = true;
-			gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
-			break;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+	if ( gProcessInfo->platform == PLATFORM_IOSMAC ) {
+		gLinkContext.rootPaths = parseColonList("/System/iOSSupport", NULL);
+		gLinkContext.iOSonMac = true;
+		if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == sLibraryFallbackPaths )
+			sEnv.DYLD_FALLBACK_LIBRARY_PATH = sRestrictedLibraryFallbackPaths;
+		if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == sFrameworkFallbackPaths )
+			sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sRestrictedFrameworkFallbackPaths;
+	}
+	else if ( ((dyld3::MachOFile*)mainExecutableMH)->supportsPlatform(dyld3::Platform::driverKit) ) {
+		gLinkContext.driverKit = true;
+		gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
 	}
 #endif
 	if ( sEnv.DYLD_PRINT_OPTS )
@@ -6707,11 +6382,18 @@
 #if !TARGET_OS_SIMULATOR
 	if ( _simple_getenv(envp, "DYLD_JUST_BUILD_CLOSURE") != nullptr ) {
 #if TARGET_OS_IPHONE
-		char tempClosurePath[PATH_MAX];
-		if ( dyld3::closure::LaunchClosure::buildClosureCachePath(sExecPath, envp, false, tempClosurePath) )
-			sJustBuildClosure = true;
-#endif
-		// If the env vars for the data contain look wrong, don't want to launch the app as that would bring up the UI
+		const char* tempDir = getTempDir(envp);
+		if ( (tempDir != nullptr) && (geteuid() != 0) ) {
+			// Use realpath to prevent something like TMPRIR=/tmp/../usr/bin
+			char realPath[PATH_MAX];
+			if ( realpath(tempDir, realPath) != NULL )
+				tempDir = realPath;
+			if (strncmp(tempDir, "/private/var/mobile/Containers/", strlen("/private/var/mobile/Containers/")) == 0) {
+				sJustBuildClosure = true;
+			}
+		}
+#endif
+		// If we didn't like the format of TMPDIR, just exit.  We don't want to launch the app as that would bring up the UI
 		if (!sJustBuildClosure) {
 			_exit(EXIT_SUCCESS);
 		}
@@ -6720,105 +6402,18 @@
 
 	if ( sJustBuildClosure )
 		sClosureMode = ClosureMode::On;
+	getHostInfo(mainExecutableMH, mainExecutableSlide);
 
 	// load shared cache
 	checkSharedRegionDisable((dyld3::MachOLoaded*)mainExecutableMH, mainExecutableSlide);
 	if ( gLinkContext.sharedRegionMode != ImageLoader::kDontUseSharedRegion ) {
 #if TARGET_OS_SIMULATOR
 		if ( sSharedCacheOverrideDir)
-			mapSharedCache(mainExecutableSlide);
+			mapSharedCache();
 #else
-		mapSharedCache(mainExecutableSlide);
-#endif
-
-		// If this process wants a different __DATA_CONST state from the shared region, then override that now
-		if ( (sSharedCacheLoadInfo.loadAddress != nullptr) && (gEnableSharedCacheDataConst != sharedCacheDataConstIsEnabled) ) {
-			uint32_t permissions = gEnableSharedCacheDataConst ? VM_PROT_READ : (VM_PROT_READ | VM_PROT_WRITE);
-			sSharedCacheLoadInfo.loadAddress->changeDataConstPermissions(mach_task_self(), permissions,
-																		 (gLinkContext.verboseMapping ? &dyld::log : nullptr));
-		}
-	}
-
-#if !TARGET_OS_SIMULATOR
-	if ( getpid() == 1 ) {
-		// Get the value as set by the boot-args
-		uint64_t commPageValue = 0;
-		size_t commPageValueSize = sizeof(commPageValue);
-		if ( sysctlbyname("kern.dyld_flags", &commPageValue, &commPageValueSize, nullptr, 0) != 0 ) {
-			// Try again with the old name
-			// TODO: Remove this when we are always on new enough kernels
-			sysctlbyname("kern.dyld_system_flags", &commPageValue, &commPageValueSize, nullptr, 0);
-		}
-
-		commPageValue &= CommPageBootArgMask;
-		// logToConsole("dyld: got comm page flags 0x%llx\n", commPageValue);
-
-		// If we are PID 1 (launchd) and on macOS, then we should check if the simulator support dylibs
-		// are roots or not.
-		// If they are not roots at launchd time, and the file system is read-only, then we know for sure
-		// they will not be roots later
-#if DYLD_SIMULATOR_ROOTS_SUPPORT
-		bool fileSystemIsWritable = true;
-
-		// logToConsole("dyld: in launchd\n");
-		struct statfs statBuffer;
-		int statResult = statfs("/", &statBuffer);
-		if ( statResult == 0 ) {
-			if ( !strcmp(statBuffer.f_fstypename, "apfs") ) {
-				if ( (statBuffer.f_flags & (MNT_RDONLY | MNT_SNAPSHOT)) == (MNT_RDONLY | MNT_SNAPSHOT) ) {
-					// logToConsole("dyld: got statfs flags 0x%llx\n", statBuffer.f_flags);
-					fileSystemIsWritable = false;
-				}
-			}
-		} else {
-			int error = errno;
-			logToConsole("dyld: could not stat '/', errno = %d\n", error);
-		}
-
-		// If the file system is read-only, then we can check now whether any of the simulator support
-		// dylibs are roots
-		bool libsystemKernelIsRoot 		= false;
-		bool libsystemPlatformIsRoot 	= false;
-		bool libsystemPThreadIsRoot 	= false;
-		if ( !fileSystemIsWritable && (sSharedCacheLoadInfo.loadAddress != nullptr)) {
-			dyld3::closure::FileSystemPhysical fileSystem;
-			libsystemKernelIsRoot 	= !dyld3::RootsChecker::uuidMatchesSharedCache("/usr/lib/system/libsystem_kernel.dylib",
-																				   &fileSystem, sSharedCacheLoadInfo.loadAddress);
-			libsystemPlatformIsRoot = !dyld3::RootsChecker::uuidMatchesSharedCache("/usr/lib/system/libsystem_platform.dylib",
-																				   &fileSystem, sSharedCacheLoadInfo.loadAddress);
-			libsystemPThreadIsRoot 	= !dyld3::RootsChecker::uuidMatchesSharedCache("/usr/lib/system/libsystem_pthread.dylib",
-																				   &fileSystem, sSharedCacheLoadInfo.loadAddress);
-		}
-		commPageValue |= (fileSystemIsWritable ? CommPageFlags::fileSystemCanBeModified : CommPageFlags::None);
-		commPageValue |= (libsystemKernelIsRoot ? CommPageFlags::libsystemKernelIsRoot : CommPageFlags::None);
-		commPageValue |= (libsystemPlatformIsRoot ? CommPageFlags::libsystemPlatformIsRoot : CommPageFlags::None);
-		commPageValue |= (libsystemPThreadIsRoot ? CommPageFlags::libsystemPThreadIsRoot : CommPageFlags::None);
-#endif // DYLD_SIMULATOR_ROOTS_SUPPORT
-
-		logToConsole("dyld: setting comm page to 0x%llx\n", commPageValue);
-		if ( sysctlbyname("kern.dyld_flags", nullptr, 0, &commPageValue, sizeof(commPageValue)) != 0 ) {
-			// Try again with the old name
-			// TODO: Remove this when we are always on new enough kernels
-			sysctlbyname("kern.dyld_system_flags", nullptr, 0, &commPageValue, sizeof(commPageValue));
-		}
-	}
-
-#if DYLD_SIMULATOR_ROOTS_SUPPORT
-	// Set the roots checker to the state from the comm page
-	{
-		uint64_t dyldFlags = *((uint64_t*)_COMM_PAGE_DYLD_SYSTEM_FLAGS);
-		bool fileSystemCanBeModified = dyldFlags & CommPageFlags::fileSystemCanBeModified;
-		bool libsystemKernelIsRoot = dyldFlags & CommPageFlags::libsystemKernelIsRoot;
-		bool libsystemPlatformIsRoot = dyldFlags & CommPageFlags::libsystemPlatformIsRoot;
-		bool libsystemPThreadIsRoot = dyldFlags & CommPageFlags::libsystemPThreadIsRoot;
-		sRootsChecker.setFileSystemCanBeModified(fileSystemCanBeModified);
-		sRootsChecker.setLibsystemKernelIsRoot(libsystemKernelIsRoot);
-		sRootsChecker.setLibsystemPlatformIsRoot(libsystemPlatformIsRoot);
-		sRootsChecker.setLibsystemPThreadIsRoot(libsystemPThreadIsRoot);
-	}
-#endif // DYLD_SIMULATOR_ROOTS_SUPPORT
-
-#endif // !TARGET_OS_SIMULATOR
+		mapSharedCache();
+#endif
+	}
 
 	// If we haven't got a closure mode yet, then check the environment and cache type
 	if ( sClosureMode == ClosureMode::Unset ) {
@@ -6839,9 +6434,8 @@
 #if !TARGET_OS_SIMULATOR
 	if ( sClosureMode == ClosureMode::Off ) {
 		if ( gLinkContext.verboseWarnings )
-			dyld::log("dyld: not using closures\n");
+			dyld::log("dyld: not using closure because of DYLD_USE_CLOSURES or -force_dyld2=1 override\n");
 	} else {
-		sLaunchModeUsed = DYLD_LAUNCH_MODE_USING_CLOSURE;
 		const dyld3::closure::LaunchClosure* mainClosure = nullptr;
 		dyld3::closure::LoadedFileInfo mainFileInfo;
 		mainFileInfo.fileContent = mainExecutableMH;
@@ -6850,7 +6444,7 @@
 		mainFileInfo.sliceOffset = 0;
 		mainFileInfo.sliceLen = -1;
 		struct stat mainExeStatBuf;
-		if ( dyld3::stat(sExecPath, &mainExeStatBuf) == 0 ) {
+		if ( ::stat(sExecPath, &mainExeStatBuf) == 0 ) {
 			mainFileInfo.inode = mainExeStatBuf.st_ino;
 			mainFileInfo.mtime = mainExeStatBuf.st_mtime;
 		}
@@ -6859,8 +6453,6 @@
 			mainClosure = sSharedCacheLoadInfo.loadAddress->findClosure(sExecPath);
 			if ( gLinkContext.verboseWarnings && (mainClosure != nullptr) )
 				dyld::log("dyld: found closure %p (size=%lu) in dyld shared cache\n", mainClosure, mainClosure->size());
-			if ( mainClosure != nullptr )
-				sLaunchModeUsed |= DYLD_LAUNCH_MODE_CLOSURE_FROM_OS;
 		}
 
 		// We only want to try build a closure at runtime if its an iOS third party binary, or a macOS binary from the shared cache
@@ -6871,32 +6463,17 @@
 			allowClosureRebuilds = true;
 		}
 
-		if ( (mainClosure != nullptr) && !closureValid(mainClosure, mainFileInfo, mainExecutableCDHash, true, envp) ) {
+		if ( (mainClosure != nullptr) && !closureValid(mainClosure, mainFileInfo, mainExecutableCDHash, true, envp) )
 			mainClosure = nullptr;
-			sLaunchModeUsed &= ~DYLD_LAUNCH_MODE_CLOSURE_FROM_OS;
-		}
-
-		// <rdar://60333505> bootToken is a concat of boot-hash kernel passes down for app and dyld's uuid
-		uint8_t bootTokenBufer[128];
-		unsigned bootTokenBufferLen = 0;
-		if ( const char* bootHashStr = _simple_getenv(apple, "executable_boothash") ) {
-			if ( hexStringToBytes(bootHashStr, bootTokenBufer, sizeof(bootTokenBufer), bootTokenBufferLen) ) {
-				if ( ((dyld3::MachOFile*)&__dso_handle)->getUuid(&bootTokenBufer[bootTokenBufferLen]) )
-					bootTokenBufferLen += sizeof(uuid_t);
-			}
-		}
-		dyld3::Array<uint8_t> bootToken(bootTokenBufer, bootTokenBufferLen, bootTokenBufferLen);
 
 		// If we didn't find a valid cache closure then try build a new one
 		if ( (mainClosure == nullptr) && allowClosureRebuilds ) {
 			// if forcing closures, and no closure in cache, or it is invalid, check for cached closure
 			if ( !sForceInvalidSharedCacheClosureFormat )
-				mainClosure = findCachedLaunchClosure(mainExecutableCDHash, mainFileInfo, envp, bootToken);
+				mainClosure = findCachedLaunchClosure(mainExecutableCDHash, mainFileInfo, envp);
 			if ( mainClosure == nullptr ) {
 				// if  no cached closure found, build new one
-				mainClosure = buildLaunchClosure(mainExecutableCDHash, mainFileInfo, envp, bootToken);
-				if ( mainClosure != nullptr )
-					sLaunchModeUsed |= DYLD_LAUNCH_MODE_BUILT_CLOSURE_AT_LAUNCH;
+				mainClosure = buildLaunchClosure(mainExecutableCDHash, mainFileInfo, envp);
 			}
 		}
 
@@ -6907,29 +6484,22 @@
 		// try using launch closure
 		if ( mainClosure != nullptr ) {
 			CRSetCrashLogMessage("dyld3: launch started");
-			if ( mainClosure->topImage()->fixupsNotEncoded() )
-				sLaunchModeUsed |= DYLD_LAUNCH_MODE_MINIMAL_CLOSURE;
-			Diagnostics diag;
-			bool closureOutOfDate;
-			bool recoverable;
 			bool launched = launchWithClosure(mainClosure, sSharedCacheLoadInfo.loadAddress, (dyld3::MachOLoaded*)mainExecutableMH,
-											  mainExecutableSlide, argc, argv, envp, apple, diag, &result, startGlue, &closureOutOfDate, &recoverable);
-			if ( !launched && closureOutOfDate && allowClosureRebuilds ) {
+											  mainExecutableSlide, argc, argv, envp, apple, &result, startGlue);
+			if ( !launched && allowClosureRebuilds ) {
 				// closure is out of date, build new one
-				mainClosure = buildLaunchClosure(mainExecutableCDHash, mainFileInfo, envp, bootToken);
+				mainClosure = buildLaunchClosure(mainExecutableCDHash, mainFileInfo, envp);
 				if ( mainClosure != nullptr ) {
-					diag.clearError();
-					sLaunchModeUsed |= DYLD_LAUNCH_MODE_BUILT_CLOSURE_AT_LAUNCH;
-					if ( mainClosure->topImage()->fixupsNotEncoded() )
-						sLaunchModeUsed |= DYLD_LAUNCH_MODE_MINIMAL_CLOSURE;
-					else
-						sLaunchModeUsed &= ~DYLD_LAUNCH_MODE_MINIMAL_CLOSURE;
 					launched = launchWithClosure(mainClosure, sSharedCacheLoadInfo.loadAddress, (dyld3::MachOLoaded*)mainExecutableMH,
-												 mainExecutableSlide, argc, argv, envp, apple, diag, &result, startGlue, &closureOutOfDate, &recoverable);
+												 mainExecutableSlide, argc, argv, envp, apple, &result, startGlue);
 				}
 			}
 			if ( launched ) {
 				gLinkContext.startedInitializingMainExecutable = true;
+#if __has_feature(ptrauth_calls)
+				// start() calls the result pointer as a function pointer so we need to sign it.
+				result = (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result, 0, 0);
+#endif
 				if (sSkipMain)
 					result = (uintptr_t)&fake_main;
 				return result;
@@ -6938,14 +6508,12 @@
 				if ( gLinkContext.verboseWarnings ) {
 					dyld::log("dyld: unable to use closure %p\n", mainClosure);
 				}
-				if ( !recoverable )
-					halt(diag.errorMessage());
 			}
 		}
 	}
 #endif // TARGET_OS_SIMULATOR
 	// could not use closure info, launch old way
-	sLaunchModeUsed = 0;
+
 
 
 	// install gdb notifier
@@ -6974,13 +6542,13 @@
 #if SUPPORT_ACCELERATE_TABLES
 #if __arm64e__
 		// Disable accelerator tables when we have threaded rebase/bind, which is arm64e executables only for now.
-		if ((sMainExecutableMachHeader->cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E)
+		if (sMainExecutableMachHeader->cpusubtype == CPU_SUBTYPE_ARM64E)
 			sDisableAcceleratorTables = true;
 #endif
 		bool mainExcutableAlreadyRebased = false;
 		if ( (sSharedCacheLoadInfo.loadAddress != nullptr) && !dylibsCanOverrideCache() && !sDisableAcceleratorTables && (sSharedCacheLoadInfo.loadAddress->header.accelerateInfoAddr != 0) ) {
 			struct stat statBuf;
-			if ( dyld3::stat(IPHONE_DYLD_SHARED_CACHE_DIR "no-dyld2-accelerator-tables", &statBuf) != 0 )
+			if ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR "no-dyld2-accelerator-tables", &statBuf) != 0 )
 				sAllCacheImagesProxy = ImageLoaderMegaDylib::makeImageLoaderMegaDylib(&sSharedCacheLoadInfo.loadAddress->header, sSharedCacheLoadInfo.slide, mainExecutableMH, gLinkContext);
 		}
 
@@ -6988,7 +6556,7 @@
 #endif
 
 
-#if TARGET_OS_OSX
+	#if __MAC_OS_X_VERSION_MIN_REQUIRED
 		gLinkContext.strictMachORequired = false;
         // <rdar://problem/22805519> be less strict about old macOS mach-o binaries
         ((dyld3::MachOFile*)mainExecutableMH)->forEachSupportedPlatform(^(dyld3::Platform platform, uint32_t minOS, uint32_t sdk) {
@@ -7046,54 +6614,6 @@
 		sAllImages.reserve(INITIAL_IMAGE_COUNT);
 	#endif
 
-#if defined(__x86_64__) && !TARGET_OS_SIMULATOR
-		if (dyld::isTranslated()) {
-			struct dyld_all_runtime_info {
-				uint32_t image_count;
-				dyld_image_info* images;
-				uint32_t uuid_count;
-				dyld_uuid_info* uuids;
-				uint32_t aot_image_count;
-				dyld_aot_image_info* aots;
-				dyld_aot_shared_cache_info aot_cache_info;
-			};
-
-			dyld_all_runtime_info* runtime_info;
-			int ret = syscall(0x7000004, &runtime_info);
-			if (ret == 0) {
-				for (int i = 0; i < runtime_info->uuid_count; i++) {
-					dyld_image_info image_info = runtime_info->images[i];
-					dyld_uuid_info uuid_info = runtime_info->uuids[i];
-
-					// add the arm64 cambria runtime to uuid info
-					addNonSharedCacheImageUUID(uuid_info);
-
-					struct stat sb;
-					if (stat(image_info.imageFilePath, &sb) == 0) {
-						fsid_t fsid = {{0, 0}};
-						fsobj_id_t fsobj = {0};
-						ino_t inode = sb.st_ino;
-						fsobj.fid_objno = (uint32_t)inode;
-						fsobj.fid_generation = (uint32_t)(inode>>32);
-						fsid.val[0] = sb.st_dev;
-
-						dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A, image_info.imageFilePath, &(uuid_info.imageUUID), fsobj, fsid, image_info.imageLoadAddress);
-					}
-				}
-
-				// add aot images to dyld_all_image_info
-				addAotImagesToAllAotImages(runtime_info->aot_image_count, runtime_info->aots);
-
-				// add the arm64 cambria runtime to dyld_all_image_info
-				addImagesToAllImages(runtime_info->image_count, runtime_info->images);
-
-				// set the aot shared cache info in dyld_all_image_info
-				dyld::gProcessInfo->aotSharedCacheBaseAddress = runtime_info->aot_cache_info.cacheBaseAddress;
-				memcpy(dyld::gProcessInfo->aotSharedCacheUUID, runtime_info->aot_cache_info.cacheUUID, sizeof(uuid_t));
-			}
-		}
-#endif
-
 		// Now that shared cache is loaded, setup an versioned dylib overrides
 	#if SUPPORT_VERSIONED_PATHS
 		checkVersionedPaths();
@@ -7221,7 +6741,7 @@
 		if ( sInsertedDylibCount > 0 ) {
 			for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
 				ImageLoader* image = sAllImages[i+1];
-				image->recursiveBind(gLinkContext, sEnv.DYLD_BIND_AT_LAUNCH, true, nullptr);
+				image->recursiveBind(gLinkContext, sEnv.DYLD_BIND_AT_LAUNCH, true);
 			}
 		}
 		
@@ -7248,9 +6768,9 @@
 		}
 		ARIADNEDBG_CODE(220, 1);
 
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 		if ( gLinkContext.driverKit ) {
-			result = (uintptr_t)sEntryOverride;
+			result = (uintptr_t)sEntryOveride;
 			if ( result == 0 )
 				halt("no entry point registered");
 			*startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit;
@@ -7273,6 +6793,10 @@
 				*startGlue = 0;
 			}
 		}
+#if __has_feature(ptrauth_calls)
+		// start() calls the result pointer as a function pointer so we need to sign it.
+		result = (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result, 0, 0);
+#endif
 	}
 	catch(const char* message) {
 		syncAllImages();
@@ -7299,7 +6823,7 @@
 		result = (uintptr_t)&fake_main;
 		*startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit;
 	}
-
+	
 	return result;
 }