]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/Options.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / ld / Options.cpp
index 6f115d8a5edae5074a5c39f408b1eea081d04cf6..09290a921b95267872e14a233ad24bf2681bba97 100644 (file)
@@ -40,6 +40,7 @@
 #include <map>
 #include <sstream>
 
+#include "ld.hpp"
 #include "Options.h"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
@@ -135,20 +136,22 @@ bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
 
 
 Options::Options(int argc, const char* argv[])
-       : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), 
-         fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
-         fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false), 
+       : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0),
+         fFallbackArchitecture(0), fFallbackSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable),
+         fHasPreferredSubType(false), fArchSupportsThumb2(false), fBindAtLoad(false), fKeepPrivateExterns(false),
+         fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false),
          fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
-         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName(NULL), 
-         fBaseAddress(0), fMaxAddress(0x7FFFFFFFFFFFFFFFLL), 
-         fBaseWritableAddress(0), fSplitSegs(false),
+         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName(NULL),
+         fBaseAddress(0), fMaxAddress(0xFFFFFFFFFFFFFFFFULL),
+         fBaseWritableAddress(0),
          fExportMode(kExportDefault), fLibrarySearchMode(kSearchDylibAndArchiveInEachDir),
          fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(true), 
          fWeakReferenceMismatchTreatment(kWeakReferenceMismatchNonWeak),
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
-         fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
+         fBundleLoader(NULL), fDtraceScriptName(NULL), fMapPath(NULL),
          fDyldInstallPath("/usr/lib/dyld"), fLtoCachePath(NULL), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
+         fKextObjectsEnable(-1),fKextObjectsDirPath(NULL),fToolchainPath(NULL),
          fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
@@ -161,7 +164,8 @@ Options::Options(int argc, const char* argv[])
          fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
          fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false),
          fOrderData(true), fMarkDeadStrippableDylib(false),
-         fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
+         fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false),
+         fMakeThreadedStartsSection(false), fNoEHLabels(false),
          fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(false),
          fWarnOnSwiftABIVersionMismatches(false), fUseSimplifiedDylibReExports(false),
          fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false),
@@ -176,15 +180,14 @@ Options::Options(int argc, const char* argv[])
          fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), 
          fDemangle(false), fTLVSupport(false), 
          fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false), 
-         fVersionLoadCommandForcedOff(false), fBuildVersionLoadCommand(false), fFunctionStartsLoadCommand(false),
+         fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
          fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
          fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false),
          fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false), 
          fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false),
-         fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
-         fSourceVersionLoadCommand(false), 
+         fSourceVersionLoadCommand(false),
          fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
-         fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
+         fExportDynamic(false), fAbsoluteSymbols(false),
          fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
          fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
          fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
@@ -194,13 +197,13 @@ Options::Options(int argc, const char* argv[])
          fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false), fUseTextExecSegment(false),
          fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
          fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false),
+         fUseLinkedListBinding(false), fNoLazyBinding(false), fDebugVariant(false),
          fReverseMapPath(NULL), fLTOCodegenOnly(false),
          fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fInitializersTreatment(Options::kInvalid),
          fZeroModTimeInDebugMap(false), fBitcodeKind(kBitcodeProcess),
-         fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
-         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset),
-         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
-         fDependencyInfoPath(NULL), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0),
+         fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
+         fSaveTempFiles(false), fLinkSnapshot(this), fSnapshotRequested(false), fPipelineFifo(NULL),
+         fDependencyInfoPath(NULL), fBuildContextName(NULL), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0),
          fUnalignedPointerTreatment(kUnalignedPointerIgnore)
 {
        this->checkForClassic(argc, argv);
@@ -346,7 +349,7 @@ uint32_t Options::maxSegProtection(const char* segName) const
 {
        // iPhoneOS always uses same protection for max and initial
        // <rdar://problem/11663436> simulator apps need to use MacOSX max-prot
-       if ( (fPlatform != kPlatformOSX) && !fTargetIOSSimulator )
+       if ( (platforms().contains(ld::kPlatform_macOS) == 0) && !targetIOSSimulator() )
                return initialSegProtection(segName);
 
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
@@ -587,28 +590,7 @@ const std::vector<const char*>* Options::sectionOrder(const char* segName) const
        return NULL;
 }
 
-uint32_t Options::minOSversion() const
-{
-       switch (fPlatform) {
-               case kPlatformiOS:
-                       return iOSVersionMin();
-               case kPlatformOSX:
-                       return macosxVersionMin();
-               case kPlatformWatchOS:
-                       return watchOSVersionMin();
-#if SUPPORT_APPLE_TV
-               case Options::kPlatform_tvOS:
-                       return iOSVersionMin();
-#endif
-               case kPlatform_bridgeOS:
-                       return iOSVersionMin();
-               case kPlatformUnknown:
-                       return 0;
-       }
-       return 0;
-}
-
-void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::Platform platform)
+void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, ld::Platform platform, uint32_t minOsVers)
 {
        for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
                if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
@@ -617,42 +599,47 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::P
                        fArchitectureName = t->archName;
                        fHasPreferredSubType = t->isSubType;
                        fArchSupportsThumb2 = t->supportsThumb2;
-                       if ( fPlatform == kPlatformUnknown)
-                               fPlatform = platform;
+                       if ( platforms().empty() && (platform != ld::kPlatform_unknown) )
+                               fPlatforms.add({platform, minOsVers});
                        switch ( type ) {
                                case CPU_TYPE_I386:
                                case CPU_TYPE_X86_64:
-                                       if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) && (fMacVersionMin == ld::macVersionUnset) ) {
+                                       if ( platforms().contains(ld::kPlatform_macOS) && (fOutputKind != Options::kObjectFile) && (platforms().minOS(ld::kPlatform_macOS) == 0) ) {
                                #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+                                               setVersionMin(ld::kPlatform_macOS, DEFAULT_MACOSX_MIN_VERSION);
                                #else
                                                warning("-macosx_version_min not specified, assuming 10.6");
-                                               fMacVersionMin = ld::mac10_6;
-                               #endif          
+                                               setVersionMin(ld::kPlatform_macOS, "10.6");
+                               #endif
                                        }
                                        break;
                                case CPU_TYPE_ARM:
                                case CPU_TYPE_ARM64:
-                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                               if ( platforms().contains(ld::kPlatform_iOS) && (platforms().minOS(ld::kPlatform_iOS) == 0) && (fOutputKind != Options::kObjectFile) ) {
                                #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
-                                               setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+                                               setVersionMin(ld::kPlatformiOS, DEFAULT_IPHONEOS_MIN_VERSION);
                                #else
                                                warning("-ios_version_min not specified, assuming 6.0");
-                                               setIOSVersionMin("6.0");
+                                               setVersionMin(ld::kPlatform_iOS, "6.0");
                                #endif
                                        }
+#if SUPPORT_ARCH_arm64e
+                                       if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) ) {
+                                               fSupportsAuthenticatedPointers = true;
+                                       }
+#endif
                                        break;
                        }
                        fLinkSnapshot.recordArch(fArchitectureName);
                        // only use compressed LINKEDIT for:
                        //                      Mac OS X 10.6 or later
                        //                      iOS 3.1 or later
-                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+                       if ( !fMakeCompressedDyldInfo && platforms().minOS(ld::version2009) && !fMakeCompressedDyldInfoForceOff )
                                fMakeCompressedDyldInfo = true;
                        // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
-                       if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+                       if ( platforms().minOS(ld::version2008) )
                                fUseSimplifiedDylibReExports = true;
                        return;
                }
@@ -665,6 +652,35 @@ bool Options::armUsesZeroCostExceptions() const
        return ( (fArchitecture == CPU_TYPE_ARM) && (fSubArchitecture == CPU_SUBTYPE_ARM_V7K) );
 }
 
+void Options::selectFallbackArch(const char *arch)
+{
+       // Should have the format "desired_arch:fallback_arch", for example "arm64_32:armv7k" to allow an armv7k
+       // slice to substitute for arm64_32 if the latter isn't present.
+       if (const char* fallbackEnv = getenv("LD_DYLIB_ARCH_FALLBACK") ) {
+               std::string fallback(fallbackEnv);
+               auto delimPos = fallback.find(':');
+
+               // Check we've got a potentially valid fallback string and that it's this architecture we're falling back from.
+               if ( delimPos == std::string::npos || fallback.substr(0, delimPos) != arch )
+                       return;
+
+               std::string fallbackTo = fallback.substr(delimPos + 1);
+               for (const ArchInfo *t = archInfoArray; t->archName != nullptr; ++t) {
+                       if ( fallbackTo == t->archName ) {
+                               fFallbackArchitecture = t->cpuType;
+                               fFallbackSubArchitecture = t->cpuSubType;
+                       }
+               }
+       }
+       else {
+               // <rdar://problem/39797337> let x86_64h fallback and use x86_64 slice
+               if ( (fArchitecture == CPU_TYPE_X86_64) && (fSubArchitecture == CPU_SUBTYPE_X86_64_H) ) {
+                       fFallbackArchitecture    = CPU_TYPE_X86_64;
+                       fFallbackSubArchitecture = CPU_SUBTYPE_X86_ALL;
+               }
+       }
+}
+
 void Options::parseArch(const char* arch)
 {
        if ( arch == NULL )
@@ -676,6 +692,7 @@ void Options::parseArch(const char* arch)
                        fSubArchitecture = t->cpuSubType;
                        fHasPreferredSubType = t->isSubType;
                        fArchSupportsThumb2 = t->supportsThumb2;
+                       selectFallbackArch(arch);
                        return;
                }
        }
@@ -826,7 +843,7 @@ static std::string replace_extension(const std::string &path, const std::string
        return result;
 }
 
-void Options::addTAPIInterface(tapi::LinkerInterfaceFile *interface, const char *path) const {
+void Options::addTAPIInterface(tapi::LinkerInterfaceFileinterface, const char *path) const {
 #if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
        if (tapi::APIVersion::isAtLeast(1, 3)) {
                for (auto &name : interface->inlinedFrameworkNames()) {
@@ -968,9 +985,10 @@ bool Options::hasInlinedTAPIFile(const std::string &path) const {
        return false;
 }
 
-std::unique_ptr<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::string &path) const
+tapi::LinkerInterfaceFile* Options::findTAPIFile(const std::string &path) const
 {
-       std::unique_ptr<tapi::LinkerInterfaceFile> interface;
+#if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
+       tapi::LinkerInterfaceFile* interface = nullptr;
        std::string TBDPath;
        
        // create parsing options.
@@ -980,20 +998,29 @@ std::unique_ptr<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::stri
        
        if (!allowWeakImports())
                flags |= tapi::ParsingFlags::DisallowWeakImports;
-       
+
+       __block uint32_t linkMinOSVersion = 0;
+       //FIXME handle this correctly once we have multi-platform TAPI.
+       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if (linkMinOSVersion == 0)
+                       linkMinOSVersion = version;
+               if (platform == ld::kPlatform_macOS)
+                       linkMinOSVersion = version;
+       });
+
        // Search through all the inlined framework.
        for (const auto &dylib : fTAPIFiles) {
                if (dylib.getInstallName() == path) {
                        // If the install name matches, parse the framework.
                        std::string errorMessage;
                        auto file = dylib.getInterfaceFile()->getInlinedFramework(path.c_str(), architecture(), subArchitecture(),
-                                                                                                                                         flags, tapi::PackedVersion32(minOSversion()), errorMessage);
+                                                                                                                                         flags, tapi::PackedVersion32(linkMinOSVersion), errorMessage);
                        if (!file)
                                throw strdup(errorMessage.c_str());
 
                        if (!interface) {
                                // If this is the first inlined framework found, record the information.
-                               interface.reset(file);
+                               interface = file;
                                TBDPath = dylib.getTAPIFilePath();
                        } else {
                                // If we found other inlined framework already, check to see if their versions are the same.
@@ -1003,13 +1030,16 @@ std::unique_ptr<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::stri
                                warning("Inlined framework/dylib mismatch: %s (%s and %s)", path.c_str(),
                                                TBDPath.c_str(), dylib.getTAPIFilePath().c_str());
                                if (interface->getCurrentVersion() < file->getCurrentVersion()) {
-                                       interface.reset(file);
+                                       interface = file;
                                        TBDPath = dylib.getTAPIFilePath();
                                }
                        }
                }
        }
        return interface;
+#else
+       return nullptr;
+#endif
 }
 
 // search for indirect dylib first using -F and -L paths first
@@ -1065,60 +1095,6 @@ Options::FileInfo Options::findIndirectDylib(const std::string& installName, con
        return findFile(installName, fromDylib);
 }
 
-
-
-void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
-{
-       FILE* file = fopen(segAddrPath, "r");
-       if ( file == NULL ) {
-               warning("-seg_addr_table file cannot be read: %s", segAddrPath);
-               return;
-       }
-       
-       char path[PATH_MAX];
-       uint64_t firstColumAddress = 0;
-       uint64_t secondColumAddress = 0;
-       bool hasSecondColumn = false;
-       while ( fgets(path, PATH_MAX, file) != NULL ) {
-               path[PATH_MAX-1] = '\0';
-               char* eol = strchr(path, '\n');
-               if ( eol != NULL )
-                       *eol = '\0';
-               // ignore lines not starting with 0x number
-               if ( (path[0] == '0') && (path[1] == 'x') ) {
-                       char* p;
-                       firstColumAddress = strtoull(path, &p, 16);
-                       while ( isspace(*p) )
-                               ++p;
-                       // see if second column is a number
-                       if ( (p[0] == '0') && (p[1] == 'x') ) {
-                               secondColumAddress = strtoull(p, &p, 16);
-                               hasSecondColumn = true;
-                               while ( isspace(*p) )
-                                       ++p;
-                       }
-                       while ( isspace(*p) )
-                               ++p;
-                       if ( p[0] == '/' ) {
-                               // remove any trailing whitespace
-                               for(char* end = eol-1; (end > p) && isspace(*end); --end)
-                                       *end = '\0';
-                               // see if this line is for the dylib being linked
-                               if ( strcmp(p, installPth) == 0 ) {
-                                       fBaseAddress = firstColumAddress;
-                                       if ( hasSecondColumn ) {
-                                               fBaseWritableAddress = secondColumAddress;
-                                               fSplitSegs = true;
-                                       }
-                                       break; // out of while loop
-                               }
-                       }
-               }
-       }
-
-       fclose(file);
-}
-
 void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal)
 {
        FILE* file;
@@ -1535,61 +1511,29 @@ Options::Treatment Options::parseTreatment(const char* treatment)
                return kInvalid;
 }
 
-void Options::setMacOSXVersionMin(const char* version)
-{
-       uint32_t value;
-       if ( !parsePackedVersion32(version, value) ) {
-               throwf("-macosx_version_min value malformed: '%s'", version);
-       }
-       fMacVersionMin = (ld::MacVersionMin)value;
-       fPlatform = kPlatformOSX;
-}
-
-void Options::setIOSVersionMin(const char* version)
-{
-       uint32_t value;
-       if ( !parsePackedVersion32(version, value) ) {
-               throwf("-ios_version_min value malformed: '%s'", version);
-       }
-       fIOSVersionMin = (ld::IOSVersionMin)value;
-       fPlatform = kPlatformiOS;
-}
-
-
-void Options::setWatchOSVersionMin(const char* version)
-{
-       uint32_t value;
-       if ( !parsePackedVersion32(version, value) ) {
-               throwf("-watchos_version_min value malformed: '%s'", version);
-       }
-       fWatchOSVersionMin = (ld::WatchOSVersionMin)value;
-       fPlatform = kPlatformWatchOS;
-}
-
-
-bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
-{
-       if ( fMacVersionMin != ld::macVersionUnset ) {
-               return ( fMacVersionMin >= requiredMacMin );
-       }
-       else {
-               return min_iOS(requirediPhoneOSMin);
-       }
-}
-
-bool Options::min_iOS(ld::IOSVersionMin requirediOSMin)
-{
-        if ( fWatchOSVersionMin != ld::wOSVersionUnset ) {
-               // Hack until we fully track watch and ios versions seperately
-               return ( (fWatchOSVersionMin + 0x00070000) >= requirediOSMin);
-       }
-       else if ( fPlatform == Options::kPlatform_bridgeOS ) {
-               // Hack until we fully track bridge and ios versions seperately
-               return ( (fIOSVersionMin + 0x00090000) >= requirediOSMin);
-       }
-       else {
-               return ( fIOSVersionMin >= requirediOSMin );
-       }
+void Options::setVersionMin(const ld::Platform& platform, const char *version) {
+       auto checkAndParse = [&](const char *errorFlag) {
+               if ( version == NULL )
+                       throwf("%s missing version argument", errorFlag);
+               uint32_t value;
+               if ( !parsePackedVersion32(version, value) ) {
+                       throwf("%s value malformed: '%s'", errorFlag, version);
+               }
+               fPlatforms.add({platform, value});
+       };
+
+       switch(platform) {
+               case ld::kPlatform_macOS:                               checkAndParse("-macosx_version_min"); break;
+               case ld::kPlatform_iOS:                                 checkAndParse("-ios_version_min"); break;
+               case ld::kPlatform_tvOS:                                checkAndParse("-tvos_version_min"); break;
+               case ld::kPlatform_watchOS:                     checkAndParse("-watchos_version_min"); break;
+               case ld::kPlatform_bridgeOS:                    checkAndParse("-bridgeos_version_min"); break;
+               case ld::kPlatform_iOSSimulator:                checkAndParse("-ios_simulator_version_min"); break;
+               case ld::kPlatform_tvOSSimulator:               checkAndParse("-tvos_simulator_version_min"); break;
+               case ld::kPlatform_watchOSSimulator:    checkAndParse("-watchos_simulator_version_min"); break;
+               case ld::kPlatform_unknown:                     throw "kPlatformUnknown is an invalid argument to setVersionMin()";
+               case ld::kPlatform_iOSMac:                              checkAndParse("-iosmac_version_min"); break;
+       };
 }
 
 void Options::setWeakReferenceMismatchTreatment(const char* treatment)
@@ -2061,6 +2005,16 @@ bool Options::moveRwSymbol(const char* symName, const char* filePath, const char
        return false;
 }
 
+bool Options::moveAXMethodList(const char* className) const
+{
+       for (const SymbolsMove& sm : fSymbolsMovesAXMethodLists) {
+               bool wildcard;
+               if ( sm.symbols.containsWithPrefix(className, NULL, wildcard) )
+                       return true;
+       }
+       return false;
+}
+
 bool Options::moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const
 {
        for (std::vector<SymbolsMove>::const_iterator it=fSymbolsMovesCode.begin(); it != fSymbolsMovesCode.end(); ++it) {
@@ -2212,7 +2166,7 @@ bool Options::parsePackedVersion32(const std::string& versionStr, uint32_t &resu
                                return false;
                }
 
-               result = (majorValue << 16) | (minorValue << 8) | microValue;
+               result = (uint32_t)((majorValue << 16) | (minorValue << 8) | microValue);
 
                return true;
        }
@@ -2227,39 +2181,9 @@ std::string Options::getSDKVersionStr() const
        return getVersionString32(fSDKVersion);
 }
 
-std::string Options::getPlatformStr() const
-{
-       switch (fPlatform) {
-               case Options::kPlatformOSX:
-                       return "MacOSX";
-               case Options::kPlatformiOS:
-                       if (targetIOSSimulator())
-                               return "iPhoneSimulator";
-                       else
-                               return "iPhoneOS";
-               case Options::kPlatformWatchOS:
-                       if (targetIOSSimulator())
-                               return "watchOS Simulator";
-                       else
-                               return "watchOS";
-#if SUPPORT_APPLE_TV
-               case Options::kPlatform_tvOS:
-                       if (targetIOSSimulator())
-                               return "AppleTVSimulator";
-                       else
-                               return "AppleTVOS";
-                       break;
-#endif
-               case Options::kPlatform_bridgeOS:
-                       return "bridgeOS";
-               case Options::kPlatformUnknown:
-                       return "Unknown";
-       }
-}
-
 std::vector<std::string> Options::writeBitcodeLinkOptions() const
 {
-       std::vector<std::string> linkCommand;
+       __block std::vector<std::string> linkCommand;
        switch ( fOutputKind ) {
                case Options::kDynamicLibrary:
                        linkCommand.push_back("-dylib");
@@ -2291,45 +2215,53 @@ std::vector<std::string> Options::writeBitcodeLinkOptions() const
 
        // Add deployment target.
        // Platform is allowed to be unknown for "ld -r".
-       switch (fPlatform) {
-               case Options::kPlatformOSX:
-                       linkCommand.push_back("-macosx_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fMacVersionMin));
-                       break;
-               case Options::kPlatformiOS:
-                       if (targetIOSSimulator())
-                               linkCommand.push_back("-ios_simulator_version_min");
-                       else
+
+       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               switch (platform) {
+                       case ld::kPlatform_macOS:
+                               linkCommand.push_back("-macosx_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_iOS:
                                linkCommand.push_back("-ios_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
-                       break;
-               case Options::kPlatformWatchOS:
-                       if (targetIOSSimulator())
-                               linkCommand.push_back("-watchos_simulator_version_min");
-                       else
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_iOSSimulator:
+                               linkCommand.push_back("-ios_simulator_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_watchOS:
                                linkCommand.push_back("-watchos_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
-                       break;
-#if SUPPORT_APPLE_TV
-               case Options::kPlatform_tvOS:
-                       if (targetIOSSimulator())
-                               linkCommand.push_back("-tvos_simulator_version_min");
-                       else
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_watchOSSimulator:
+                               linkCommand.push_back("-watchos_simulator_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_tvOS:
                                linkCommand.push_back("-tvos_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
-                       break;
-#endif
-               case Options::kPlatform_bridgeOS:
-                       linkCommand.push_back("-bridgeos_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
-                       break;
-               case Options::kPlatformUnknown:
-                       if ( fOutputKind != Options::kObjectFile ) {
-                               throwf("platform is unknown for final bitcode bundle,"
-                                          "deployment target and min version is required for -bitcode_bundle");
-                       }
-                       break;
-       }
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_tvOSSimulator:
+                               linkCommand.push_back("-tvos_simulator_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_bridgeOS:
+                               linkCommand.push_back("-bridgeos_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_iOSMac:
+                               linkCommand.push_back("-iosmac_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_unknown:
+                               if ( fOutputKind != Options::kObjectFile ) {
+                                       throwf("platform is unknown for final bitcode bundle,"
+                                                  "deployment target and min version is required for -bitcode_bundle");
+                               }
+                               break;
+               }
+       });
 
 
        // entry name
@@ -2380,6 +2312,20 @@ std::vector<std::string> Options::writeBitcodeLinkOptions() const
        return linkCommand;
 }
 
+const char* Options::checkForNullArgument(const char* argument_name, const char* arg) const
+{
+       if ( arg == NULL )
+               throwf("missing argument for %s", argument_name);
+       return arg;
+}
+
+const char* Options::checkForNullVersionArgument(const char* argument_name, const char* arg) const
+{
+       if ( arg == NULL )
+               throwf("%s missing version argument", argument_name);
+       return arg;
+}
+
 //
 // Process all command line arguments.
 //
@@ -2430,7 +2376,9 @@ void Options::parse(int argc, const char* argv[])
                                exit (0);
                        }
                        else if ( strcmp(arg, "-arch") == 0 ) {
-                               parseArch(argv[++i]);
+                               const char* arch = argv[++i];
+                               parseArch(arch);
+                               fLinkSnapshot.recordArch(arch);
                        }
                        else if ( strcmp(arg, "-dynamic") == 0 ) {
                                // default
@@ -2468,10 +2416,19 @@ void Options::parse(int argc, const char* argv[])
                                fOutputKind = kKextBundle;
                                cannotBeUsedWithBitcode(arg);
                        }
+                       else if ( strcmp(arg, "-kext_objects_dir") == 0 ) {
+                               fKextObjectsDirPath = argv[++i];
+                               if ( fKextObjectsDirPath == NULL )
+                                       throw "missing argument to -kext_objects_dir";
+                               fKextObjectsEnable = 1;
+                       }
+                       else if ( strcmp(arg, "-no_kext_objects") == 0 ) {
+                               fKextObjectsEnable = 0;
+                       }
                        else if ( strcmp(arg, "-o") == 0 ) {
-                snapshotArgCount = 0;
-                               fOutputFile = argv[++i];
-                fLinkSnapshot.setSnapshotName(fOutputFile);
+                               snapshotArgCount = 0;
+                               fOutputFile = checkForNullArgument(arg, argv[++i]);
+                               fLinkSnapshot.setOutputPath(fOutputFile);
                        }
                        else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
                 snapshotArgCount = 0;
@@ -2498,6 +2455,7 @@ void Options::parse(int argc, const char* argv[])
                                if ( value == NULL )
                                        throw "missing argument to -prune_interval_lto";
                                char* endptr;
+                               fLtoPruneIntervalOverwrite = true;
                                fLtoPruneInterval = strtoul(value, &endptr, 10);
                                if ( *endptr != '\0')
                                        throw "invalid argument for -prune_interval_lto";
@@ -2570,7 +2528,8 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Similar to -all_load, but for the following archive only.
                        else if ( strcmp(arg, "-force_load") == 0 ) {
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fForceLoad = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -2697,13 +2656,15 @@ void Options::parse(int argc, const char* argv[])
                                if ( fExportMode == kDontExportSome )
                                        throw "can't use -exported_symbol and -unexported_symbols";
                                fExportMode = kExportSome;
-                               fExportSymbols.insert(argv[++i]);
+                               const char* symbol = checkForNullArgument(arg, argv[++i]);
+                               fExportSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-unexported_symbol") == 0 ) {
                                if ( fExportMode == kExportSome )
                                        throw "can't use -unexported_symbol and -exported_symbol";
                                fExportMode = kDontExportSome;
-                               fDontExportSymbols.insert(argv[++i]);
+                               const char* symbol = checkForNullArgument(arg, argv[++i]);
+                               fDontExportSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2734,7 +2695,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fWeakImport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -2743,7 +2705,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-lazy_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fLazyLoad = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -2827,12 +2790,11 @@ void Options::parse(int argc, const char* argv[])
                        // are prebound.  This can then be fixed up by update_prebinding
                        // later.  Prebinding is less useful on 10.4 and greater.
                        else if ( strcmp(arg, "-prebind") == 0 ) {
-                               fPrebind = true;
+                               warnObsolete(arg);
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-noprebind") == 0 ) {
                                warnObsolete(arg);
-                               fPrebind = false;
                        }
                        else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
                                warnObsolete(arg);
@@ -2901,22 +2863,23 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
-                               fBaseAddress = parseAddress(argv[++i]);
+                               warnObsolete(arg);
+                               ++i;
                                cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
-                               fBaseWritableAddress = parseAddress(argv[++i]);
-                               fSplitSegs = true;
+                               warnObsolete(arg);
+                               ++i;
                                cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we get rid of basing at build time.
                        else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
+                               warnObsolete(arg);
                 snapshotFileArgIndex = 1;
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-seg_addr_table missing argument";
-                               fSegAddrTablePath = name;
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
@@ -3000,9 +2963,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Use this flag to set default behavior for deployement targets.
                        else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
-                               const char* macVers = argv[++i];
-                               if ( macVers == NULL )
-                                       throw "-macosx_version_min missing version argument";
+                               const char* macVers = checkForNullVersionArgument(arg, argv[++i]);
                                const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                                const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                                if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
@@ -3012,67 +2973,49 @@ void Options::parse(int argc, const char* argv[])
                                                const char* sysrootPath = fSDKPaths.back();
                                                const char* lastSlash = strrchr(sysrootPath, '/');
                                                if ( strstr(lastSlash, "Simulator") != NULL ) 
-                                                       setIOSVersionMin(enviPhoneVers);
+                                                       setVersionMin(ld::kPlatform_iOS, enviPhoneVers);
                                                else
-                                                       setMacOSXVersionMin(macVers);
+                                                       setVersionMin(ld::kPlatform_macOS, macVers);
                                        }
                                        else {
-                                               setMacOSXVersionMin(macVers);
+                                               setVersionMin(ld::kPlatform_macOS, macVers);
                                        }
                                }
                                else {
-                                       setMacOSXVersionMin(macVers);
+                                       setVersionMin(ld::kPlatform_macOS, macVers);
                                }
                        }
                        else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-ios_version_min missing version argument";
-                               setIOSVersionMin(vers);
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_iOS, vers);
                        }
                        else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-ios_simulator_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fTargetIOSSimulator = true;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_iOSSimulator, vers);
                        }
                        else if ( strcmp(arg, "-watchos_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-watchos_version_min missing version argument";
-                               setWatchOSVersionMin(vers);
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_watchOS, vers);
                        }
                        else if ( strcmp(arg, "-watchos_simulator_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-watchos_simulator_version_min missing version argument";
-                               setWatchOSVersionMin(vers);
-                               fTargetIOSSimulator = true;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_watchOSSimulator, vers);
                        }
-       #if SUPPORT_APPLE_TV
                        else if ( strcmp(arg, "-tvos_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-tvos_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fPlatform = kPlatform_tvOS;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_tvOS, vers);
                        }
                        else if ( strcmp(arg, "-tvos_simulator_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-tvos_simulator_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fPlatform = kPlatform_tvOS;
-                               fTargetIOSSimulator = true;
-                       }
-       #endif
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_tvOSSimulator, vers);
+                       }
                        else if ( strcmp(arg, "-bridgeos_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-bridgeos_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fPlatform = kPlatform_bridgeOS;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_bridgeOS, vers);
+                       }
+                       else if ( strcmp(arg, "-iosmac_version_min") == 0 ) {
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_iOSMac, vers);
                        }
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
@@ -3307,12 +3250,8 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-alias") == 0 ) {
                                Options::AliasPair pair;
-                               pair.realName = argv[++i];
-                               if ( pair.realName == NULL )
-                                       throw "missing argument to -alias";
-                               pair.alias = argv[++i];
-                               if ( pair.alias == NULL )
-                                       throw "missing argument to -alias";
+                               pair.realName = checkForNullArgument(arg, argv[++i]);
+                               pair.alias = checkForNullArgument(arg, argv[++i]);
                                fAliases.push_back(pair);
                                cannotBeUsedWithBitcode(arg);
                        }
@@ -3331,9 +3270,7 @@ void Options::parse(int argc, const char* argv[])
                                fVerifyBitcode = true;
                        }
                        else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
-                               fReverseMapPath = argv[++i];
-                               if ( fReverseMapPath == NULL )
-                                       throw "missing argument to -bitcode_symbol_map";
+                               fReverseMapPath = checkForNullArgument(arg, argv[++i]);
                                struct stat statbuf;
                                int ret = ::stat(fReverseMapPath, &statbuf);
                                if ( ret == 0 && S_ISDIR(statbuf.st_mode)) {
@@ -3348,20 +3285,18 @@ void Options::parse(int argc, const char* argv[])
                                } else
                                        fReverseMapTempPath = std::string(fReverseMapPath);
                        }
-                       else if ( strcmp(argv[i], "-flto-codegen-only") == 0) {
+                       else if ( strcmp(arg, "-flto-codegen-only") == 0) {
                                fLTOCodegenOnly = true;
                        }
-                       else if ( strcmp(argv[i], "-ignore_auto_link") == 0) {
+                       else if ( strcmp(arg, "-ignore_auto_link") == 0) {
                                fIgnoreAutoLink = true;
                        }
-                       else if ( strcmp(argv[i], "-allow_dead_duplicates") == 0) {
+                       else if ( strcmp(arg, "-allow_dead_duplicates") == 0) {
                                fAllowDeadDups = true;
                        }
-                       else if ( strcmp(argv[i], "-bitcode_process_mode") == 0 ) {
-                               const char* bitcode_type = argv[++i];
-                               if ( bitcode_type == NULL )
-                                       throw "missing argument to -bitcode_process_mode";
-                               else if ( strcmp(bitcode_type, "strip") == 0 )
+                       else if ( strcmp(arg, "-bitcode_process_mode") == 0 ) {
+                               const char* bitcode_type = checkForNullArgument(arg, argv[++i]);
+                               if ( strcmp(bitcode_type, "strip") == 0 )
                                        fBitcodeKind = kBitcodeStrip;
                                else if ( strcmp(bitcode_type, "marker") == 0 )
                                        fBitcodeKind = kBitcodeMarker;
@@ -3373,9 +3308,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "unknown argument to -bitcode_process_mode {strip,marker,data,bitcode}";
                        }
                        else if ( strcmp(arg, "-rpath") == 0 ) {
-                               const char* path = argv[++i];
-                               if ( path == NULL )
-                                       throw "missing argument to -rpath";
+                               const char* path = checkForNullArgument(arg, argv[++i]);
                                fRPaths.push_back(path);
                        }
                        else if ( strcmp(arg, "-read_only_stubs") == 0 ) {
@@ -3385,9 +3318,7 @@ void Options::parse(int argc, const char* argv[])
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-map") == 0 ) {
-                               fMapPath = argv[++i];
-                               if ( fMapPath == NULL )
-                                       throw "missing argument to -map";
+                               fMapPath = checkForNullArgument(arg, argv[++i]);
                        }
                        else if ( strcmp(arg, "-pie") == 0 ) {
                                fPositionIndependentExecutable = true;
@@ -3409,7 +3340,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-reexport_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -3436,7 +3368,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-upward_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -3474,16 +3407,12 @@ void Options::parse(int argc, const char* argv[])
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-mllvm") == 0 ) {
-                               const char* opts = argv[++i];
-                               if ( opts == NULL )
-                                       throw "missing argument to -mllvm";
+                               const char* opts = checkForNullArgument(arg, argv[++i]);
                                fLLVMOptions.push_back(opts);
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-mcpu") == 0 ) {
-                               const char* cpu = argv[++i];
-                               if ( cpu == NULL )
-                                       throw "missing argument to -mcpu";
+                               const char* cpu = checkForNullArgument(arg, argv[++i]);
                                fLtoCpu = cpu;
                                cannotBeUsedWithBitcode(arg);
                        }
@@ -3539,9 +3468,7 @@ void Options::parse(int argc, const char* argv[])
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
-                               const char* version = argv[++i];
-                                if ( version == NULL )
-                                       throw "-objc_abi_version missing version number";
+                               const char* version = checkForNullVersionArgument(arg, argv[++i]);
                                if ( strcmp(version, "2") == 0 ) {
                                        fObjCABIVersion1Override = false;
                                        fObjCABIVersion2Override = true;
@@ -3565,17 +3492,17 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-objc_gc") == 0 ) {
                                fObjCGc = true;
-                               if ( fObjCGcOnly ) { 
+                               if ( fObjCGcOnly ) {
                                        warning("-objc_gc overriding -objc_gc_only");
-                                       fObjCGcOnly = false;    
+                                       fObjCGcOnly = false;
                                }
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
                                fObjCGcOnly = true;
-                               if ( fObjCGc ) { 
+                               if ( fObjCGc ) {
                                        warning("-objc_gc_only overriding -objc_gc");
-                                       fObjCGc = false;        
+                                       fObjCGc = false;
                                }
                                cannotBeUsedWithBitcode(arg);
                        }
@@ -3586,11 +3513,6 @@ void Options::parse(int argc, const char* argv[])
                                fVersionLoadCommandForcedOn = true;
                                fVersionLoadCommandForcedOff = false;
                        }
-                       else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
-                               fVersionLoadCommandForcedOff = true;
-                               fVersionLoadCommandForcedOn = false;
-                               cannotBeUsedWithBitcode(arg);
-                       }
                        else if ( strcmp(arg, "-function_starts") == 0 ) {
                                fFunctionStartsForcedOn = true;
                                fFunctionStartsForcedOff = false;
@@ -3610,9 +3532,7 @@ void Options::parse(int argc, const char* argv[])
                                fDataInCodeInfoLoadCommandForcedOff = false;
                        }
                        else if ( strcmp(arg, "-object_path_lto") == 0 ) {
-                               fTempLtoObjectPath = argv[++i];
-                               if ( fTempLtoObjectPath == NULL )
-                                       throw "missing argument to -object_path_lto";
+                               fTempLtoObjectPath = checkForNullArgument(arg, argv[++i]);
                        }
                        else if ( strcmp(arg, "-no_objc_category_merging") == 0 ) {
                                fObjcCategoryMerging = false;
@@ -3674,14 +3594,6 @@ void Options::parse(int argc, const char* argv[])
                                fSnapshotRequested = true;
                                cannotBeUsedWithBitcode(arg);
             }
-                       else if ( strcmp(arg, "-new_main") == 0 ) {
-                               fEntryPointLoadCommandForceOn = true;
-                               cannotBeUsedWithBitcode(arg);
-                       }
-                       else if ( strcmp(arg, "-no_new_main") == 0 ) {
-                               fEntryPointLoadCommandForceOff = true;
-                               cannotBeUsedWithBitcode(arg);
-                       }
                        else if ( strcmp(arg, "-source_version") == 0 ) {
                                 const char* vers = argv[++i];
                                 if ( vers == NULL )
@@ -3711,7 +3623,7 @@ void Options::parse(int argc, const char* argv[])
                                fKextsUseStubs = true;
                                cannotBeUsedWithBitcode(arg);
                        }
-                       else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+                       else if ( strcmp(arg, "-dependency_info") == 0 ) {
                 snapshotArgCount = 0;
                                ++i;
                                // previously handled by buildSearchPaths()
@@ -3928,15 +3840,24 @@ void Options::parse(int argc, const char* argv[])
                                }
                                fMaxDefaultCommonAlign = alignment;
                        }
-                       else if ( strcmp(argv[i], "-no_weak_imports") == 0 ) {
+                       else if ( strcmp(arg, "-no_weak_imports") == 0 ) {
                                fAllowWeakImports = false;
                        }
-                       else if ( strcmp(argv[i], "-no_inits") == 0 ) {
+                       else if ( strcmp(arg, "-no_inits") == 0 ) {
                                fInitializersTreatment = Options::kError;
                        }
-                       else if ( strcmp(argv[i], "-no_warn_inits") == 0 ) {
+                       else if ( strcmp(arg, "-no_warn_inits") == 0 ) {
                                fInitializersTreatment = Options::kSuppress;
                        }
+                       else if ( strcmp(arg, "-threaded_starts_section") == 0 ) {
+                               fMakeThreadedStartsSection = true;
+                       }
+                       else if (strcmp(arg, "-debug_variant") == 0) {
+                           fDebugVariant = true;
+            }
+                       else if (strcmp(arg, "-no_new_main") == 0) {
+                               // HACK until 39514191 is fixed
+                       }
                        // put this last so that it does not interfer with other options starting with 'i'
                        else if ( strncmp(arg, "-i", 2) == 0 ) {
                                const char* colon = strchr(arg, ':');
@@ -3977,9 +3898,25 @@ void Options::parse(int argc, const char* argv[])
     
     if (fSnapshotRequested)
         fLinkSnapshot.createSnapshot();
-}
-
 
+       if ( kKextBundle == fOutputKind ) {
+               if ( fKextObjectsEnable < 0 )
+                       fKextObjectsEnable = ((fArchitecture == CPU_TYPE_ARM64) || (fArchitecture == CPU_TYPE_ARM));
+
+               if (fKextObjectsEnable > 0) {
+                       if ( !fKextObjectsDirPath ) {
+                               const char* dstroot;
+                               const char* objdir = getenv("LD_KEXT_OBJECTS_DIR");
+                               if ( objdir )
+                                       fKextObjectsDirPath = strdup(objdir);
+                               else if ( (dstroot = getenv("DSTROOT")) )
+                                       asprintf((char **)&fKextObjectsDirPath, "%s/AppleInternal/KextObjects", dstroot);
+                       }
+                       fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_KEXT);
+                       fLinkSnapshot.createSnapshot();
+               }
+       }
+}
 
 //
 // -syslibroot <path> is used for SDK support.
@@ -4033,6 +3970,7 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        fVerbose = true;
                        extern const char ldVersionString[];
                        fprintf(stderr, "%s", ldVersionString);
+                       fprintf(stderr, "BUILD "  __TIME__ " "  __DATE__"\n");
                        fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS);
                         // if only -v specified, exit cleanly
                         if ( argc == 2 ) {
@@ -4243,9 +4181,6 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL)
                fPrintOrderFileStatistics = true;
 
-       if (getenv("LD_SPLITSEGS_NEW_LIBRARIES") != NULL)
-               fSplitSegs = true;
-               
        if (getenv("LD_NO_ENCRYPT") != NULL) {
                fEncryptable = false;
                fMarkAppExtensionSafe = true; // temporary
@@ -4288,6 +4223,21 @@ void Options::parsePreCommandLineEnvironmentSettings()
        // <rdar://problem/30746905> [Reproducible Builds] If env ZERO_AR_DATE is set, zero out timestamp in N_OSO stab
        if ( getenv("ZERO_AR_DATE") != NULL )
                fZeroModTimeInDebugMap = true;
+
+       char rawPath[PATH_MAX];
+       char path[PATH_MAX];
+       char *base;
+       uint32_t bufSize = PATH_MAX;
+       if ( _NSGetExecutablePath(rawPath, &bufSize) != -1 ) {
+               if ( realpath(rawPath, path) != NULL ) {
+#define TOOLCHAINBASEPATH "/Developer/Toolchains/"
+                       if ( (base = strstr(path, TOOLCHAINBASEPATH)) )
+                               fToolchainPath = strndup(path, base - path + strlen(TOOLCHAINBASEPATH));
+               }
+       }
+
+       // <rdar://problem/38679559> ld64 should consider RC_RELEASE when calculating a binary's UUID
+       fBuildContextName = getenv("RC_RELEASE");
 }
 
 
@@ -4299,15 +4249,6 @@ void Options::parsePostCommandLineEnvironmentSettings()
                fExecutablePath = fOutputFile;
        }
 
-       // allow build system to set default seg_addr_table
-       if ( fSegAddrTablePath == NULL )
-               fSegAddrTablePath = getenv("LD_SEG_ADDR_TABLE");
-
-       // allow build system to turn on prebinding
-       if ( !fPrebind ) {
-               fPrebind = ( getenv("LD_PREBIND") != NULL );
-       }
-       
        // allow build system to force on dead-code-stripping
        if ( !fDeadStrip ) {
                if ( getenv("LD_DEAD_STRIP") != NULL ) {
@@ -4374,20 +4315,22 @@ void Options::reconfigureDefaults()
        }
 
        // set default min OS version
-       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fWatchOSVersionMin == ld::wOSVersionUnset) ) {
+       if ( platforms().empty() ) {
                // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
+               if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) )
+                       warning("No version-min specified on command line");
                const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
                const char* wOSVers = getenv("WATCHOS_DEPLOYMENT_TARGET");
                if ( macVers != NULL )
-                       setMacOSXVersionMin(macVers);
+                       setVersionMin(ld::kPlatform_macOS, macVers);
                else if ( iPhoneVers != NULL )
-                       setIOSVersionMin(iPhoneVers);
+                       setVersionMin(ld::kPlatform_iOS, iPhoneVers);
                else if ( iOSVers != NULL )
-                       setIOSVersionMin(iOSVers);
+                       setVersionMin(ld::kPlatform_iOS, iOSVers);
                else if ( wOSVers != NULL )
-                       setWatchOSVersionMin(wOSVers);
+                       setVersionMin(ld::kPlatform_watchOS, wOSVers);
                else {
                        // if still nothing, set default based on architecture
                        switch ( fArchitecture ) {
@@ -4396,26 +4339,26 @@ void Options::reconfigureDefaults()
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+                                               setVersionMin(ld::kPlatform_macOS, DEFAULT_MACOSX_MIN_VERSION);
                        #else
                                                warning("-macosx_version_min not specified, assuming 10.6");
-                                               setMacOSXVersionMin("10.6");
-                       #endif          
+                                               setVersionMin(ld::kPlatform_macOS, "10.6");
+                       #endif
                                        }
                                        break;
                                case CPU_TYPE_ARM:
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
-                                               setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+                                               setVersionMin(ld::kPlatformiOS, DEFAULT_IPHONEOS_MIN_VERSION);
                        #else
                                                if ( fSubArchitecture == CPU_SUBTYPE_ARM_V7K ) {
                                                        warning("-watchos_version_min not specified, assuming 2.0");
-                                                       setWatchOSVersionMin("2.0");
+                                                       setVersionMin(ld::kPlatform_watchOS, "2.0");
                                                }
                                                else {
                                                        warning("-ios_version_min not specified, assuming 6.0");
-                                                       setIOSVersionMin("6.0");
+                                                       setVersionMin(ld::kPlatform_iOS, "6.0");
                                                }
                        #endif
                                        }
@@ -4427,29 +4370,23 @@ void Options::reconfigureDefaults()
                }
        }
 
-
+       __block ld::VersionSet platformOverrides;
        // adjust min based on architecture
-       switch ( fArchitecture ) {
-               case CPU_TYPE_I386:
-                       if ( (fPlatform == kPlatformOSX) && (fMacVersionMin < ld::mac10_4) ) {
-                               //warning("-macosx_version_min should be 10.4 or later for i386");
-                               fMacVersionMin = ld::mac10_4;
-                       }
-                       break;
-               case CPU_TYPE_X86_64:
-                       if ( (fPlatform == kPlatformOSX) && (fMacVersionMin < ld::mac10_4) ) {
-                               //warning("-macosx_version_min should be 10.4 or later for x86_64");
-                               fMacVersionMin = ld::mac10_4;
-                       }
-                       break;
-               case CPU_TYPE_ARM64:
-                       if ( (fPlatform == kPlatformiOS) && (fIOSVersionMin < ld::iOS_7_0) ) {
-                               //warning("-mios_version_min should be 7.0 or later for arm64");
-                               fIOSVersionMin = ld::iOS_7_0;
-                       }
-                       break;
-       }
-       
+       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if ( (fArchitecture == CPU_TYPE_I386 || fArchitecture == CPU_TYPE_X86_64)
+                               && platform == ld::kPlatform_macOS && !platforms().minOS(ld::mac10_4) ) {
+                       platformOverrides.add(ld::mac10_4);
+               } else if (fArchitecture == CPU_TYPE_ARM64 && platform == ld::kPlatform_iOS
+                                  && !platforms().minOS(ld::iOS_7_0)) {
+                       platformOverrides.add(ld::iOS_7_0);
+               }
+       });
+
+       // Insert the overrides into fPlatfroms
+       platformOverrides.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               fPlatforms.add({platform, version});
+       });
+
        // default to adding functions start for dynamic code, static code must opt-in
        switch ( fOutputKind ) {
                case Options::kPreload:
@@ -4496,17 +4433,12 @@ void Options::reconfigureDefaults()
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
                        case CPU_TYPE_ARM:
-                               if ( min_iOS(ld::iOS_5_0) ) {
-                    // iOS 5.0 and later use new MH_KEXT_BUNDLE type
-                    fMakeCompressedDyldInfo = false;
-                    fMakeCompressedDyldInfoForceOff = true;
-                                       // kexts are PIC in iOS 6.0 and later
-                                       fAllowTextRelocs = !min_iOS(ld::iOS_6_0);
-                                       fKextsUseStubs = !fAllowTextRelocs;
-                    fUndefinedTreatment = kUndefinedDynamicLookup;
-                                       break;
-                               }
-                               // else use object file
+                               fMakeCompressedDyldInfo = false;
+                               fMakeCompressedDyldInfoForceOff = true;
+                               fAllowTextRelocs = false;
+                               fKextsUseStubs = !fAllowTextRelocs;
+                               fUndefinedTreatment = kUndefinedDynamicLookup;
+                               break;
                        case CPU_TYPE_I386:
                                // use .o files
                                fOutputKind = kObjectFile;
@@ -4516,65 +4448,9 @@ void Options::reconfigureDefaults()
 
        // disable implicit dylibs when targeting 10.3
        // <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
-       if ( !minOS(ld::mac10_4, ld::iOS_2_0) )
+       if ( !platforms().minOS(ld::version2007) )
                fImplicitlyLinkPublicDylibs = false;
 
-
-       // allow build system to force linker to ignore -prebind
-       if ( getenv("LD_FORCE_NO_PREBIND") != NULL )
-               fPrebind = false;                       
-
-       // allow build system to force linker to ignore -seg_addr_table
-       if ( getenv("LD_FORCE_NO_SEG_ADDR_TABLE") != NULL )
-                  fSegAddrTablePath = NULL;
-
-       // check for base address specified externally
-       if ( (fSegAddrTablePath != NULL) &&  (fOutputKind == Options::kDynamicLibrary) ) {
-               parseSegAddrTable(fSegAddrTablePath, this->installPath());
-               // HACK to support seg_addr_table entries that are physical paths instead of install paths
-               if ( fBaseAddress == 0 ) {
-                       if ( strcmp(this->installPath(), "/usr/lib/libstdc++.6.dylib") == 0 ) {
-                               parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.4.dylib");
-                               if ( fBaseAddress == 0 )
-                                       parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.9.dylib");
-                       }
-                               
-                       else if ( strcmp(this->installPath(), "/usr/lib/libz.1.dylib") == 0 ) 
-                               parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libz.1.2.3.dylib");
-                               
-                       else if ( strcmp(this->installPath(), "/usr/lib/libutil.dylib") == 0 ) 
-                               parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libutil1.0.dylib");
-               }               
-       }
-       
-       // split segs only allowed for dylibs
-       if ( fSplitSegs ) {
-        // split seg only supported for i386, and arm.
-        switch ( fArchitecture ) {
-            case CPU_TYPE_I386:
-                if ( fOutputKind != Options::kDynamicLibrary )
-                    fSplitSegs = false;
-                // make sure read and write segments are proper distance apart
-                if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x10000000) )
-                    fBaseWritableAddress = fBaseAddress + 0x10000000;
-                break;
-            case CPU_TYPE_ARM:
-                if ( fOutputKind != Options::kDynamicLibrary ) {
-                    fSplitSegs = false;
-                               }
-                               else {
-                                       // make sure read and write segments are proper distance apart
-                                       if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x08000000) )
-                                               fBaseWritableAddress = fBaseAddress + 0x08000000;
-                               }
-                break;
-            default:
-                fSplitSegs = false;
-                fBaseAddress = 0;
-                fBaseWritableAddress = 0;
-               }
-       }
-
        // set too-large size
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:
@@ -4606,77 +4482,10 @@ void Options::reconfigureDefaults()
                        break;
        }
 
-       // <rdar://problem/6138961> -r implies no prebinding for all architectures
-       if ( fOutputKind == Options::kObjectFile )
-               fPrebind = false;                       
-
-       // disable prebinding depending on arch and min OS version
-       if ( fPrebind ) {
-               switch ( fArchitecture ) {
-                       case CPU_TYPE_I386:
-                               if ( fMacVersionMin == ld::mac10_4 ) {
-                                       // in 10.4 only split seg dylibs are prebound
-                                       if ( (fOutputKind != Options::kDynamicLibrary) || ! fSplitSegs )
-                                               fPrebind = false;
-                               }
-                               else if ( fMacVersionMin >= ld::mac10_5 ) {
-                                       // in 10.5 nothing is prebound
-                                       fPrebind = false;
-                               }
-                               else if ( fIOSVersionMin != ld::iOSVersionUnset ) {
-                                       // nothing in simulator is prebound
-                                       fPrebind = false;
-                               }
-                               else {
-                                       // in 10.3 and earlier only dylibs and main executables could be prebound
-                                       switch ( fOutputKind ) {
-                                               case Options::kDynamicExecutable:
-                                               case Options::kDynamicLibrary:
-                                                       // only main executables and dylibs can be prebound
-                                                       break;
-                                               case Options::kStaticExecutable:
-                                               case Options::kDynamicBundle:
-                                               case Options::kObjectFile:
-                                               case Options::kDyld:
-                                               case Options::kPreload:
-                                               case Options::kKextBundle:
-                                                       // disable prebinding for everything else
-                                                       fPrebind = false;
-                                                       break;
-                                       }
-                               }
-                               break;
-                       case CPU_TYPE_X86_64:
-                               fPrebind = false;
-                               break;
-            case CPU_TYPE_ARM:
-                               switch ( fOutputKind ) {
-                                       case Options::kDynamicExecutable:
-                                       case Options::kDynamicLibrary:
-                                               // only main executables and dylibs can be prebound
-                                               break;
-                                       case Options::kStaticExecutable:
-                                       case Options::kDynamicBundle:
-                                       case Options::kObjectFile:
-                                       case Options::kDyld:
-                                       case Options::kPreload:
-                                       case Options::kKextBundle:
-                                               // disable prebinding for everything else
-                                               fPrebind = false;
-                                               break;
-                               }
-                               break;
-               }
-       }
-
-       // only prebound images can be split-seg
-       if ( fSplitSegs && !fPrebind )
-               fSplitSegs = false;
-
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
-               if ( minOS(ld::mac10_5, ld::iOS_3_1) )
-                       if ( !fPrebind && !fSharedRegionEligibleForceOff )
+               if ( platforms().minOS(ld::version2008Fall) )
+                       if ( !fSharedRegionEligibleForceOff )
                                if ( sharedCacheEligiblePath(this->installPath()) )
                                        fSharedRegionEligible = true;
        }
@@ -4685,21 +4494,26 @@ void Options::reconfigureDefaults()
         fSharedRegionEligible = true;
        }
 
-       // automatically use __DATA_CONST in iOS dylibs
-       if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0) && !fUseDataConstSegmentForceOff && !fTargetIOSSimulator) {
+       // automatically use __DATA_CONST in dylibs on all platforms except macOS
+       if ( fSharedRegionEligible && !fUseDataConstSegmentForceOff
+               && !platforms().contains(ld::kPlatform_macOS) && !targetIOSSimulator()) {
                fUseDataConstSegment = true;
        }
        if ( fUseDataConstSegmentForceOn ) {
                fUseDataConstSegment = true;
        }
        // A -kext for iOS 10 ==>  -data_const, -text_exec, -add_split_seg_info
-       if ( (fOutputKind == Options::kKextBundle) && minOS(ld::mac10_Future, ld::iOS_10_0) && (fArchitecture == CPU_TYPE_ARM64) ) {
+       if ( (fOutputKind == Options::kKextBundle) && (fArchitecture == CPU_TYPE_ARM64) ) {
                fUseDataConstSegment = true;
                fUseTextExecSegment = true;
                fSharedRegionEligible = true;
        }
        if ( fUseDataConstSegment ) {
                addSectionRename("__DATA", "__got",                             "__DATA_CONST", "__got");
+
+#if SUPPORT_ARCH_arm64e
+               addSectionRename("__DATA", "__auth_got",                "__DATA_CONST", "__auth_got");
+#endif
                addSectionRename("__DATA", "__la_symbol_ptr",   "__DATA_CONST", "__la_symbol_ptr");
                addSectionRename("__DATA", "__nl_symbol_ptr",   "__DATA_CONST", "__nl_symbol_ptr");
                addSectionRename("__DATA", "__const",                   "__DATA_CONST", "__const");
@@ -4720,9 +4534,9 @@ void Options::reconfigureDefaults()
        }
        
        // Use V2 shared cache info when targetting newer OSs
-       if ( fSharedRegionEligible && minOS(ld::mac10_12, ld::iOS_9_0)) {
+       if ( fSharedRegionEligible && platforms().minOS(ld::supportsSplitSegV2)) {
                fSharedRegionEncodingV2 = true;
-               if ( fPlatform == kPlatformOSX ) {
+               if ( platforms().contains(ld::kPlatform_macOS) ) {
                        fSharedRegionEncodingV2 = false;
                        // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
                        if ( strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) == 0 )
@@ -4741,19 +4555,6 @@ void Options::reconfigureDefaults()
                fIgnoreOptimizationHints = true;
        }
 
-       // figure out if module table is needed for compatibility with old ld/dyld
-       if ( fOutputKind == Options::kDynamicLibrary ) {
-               switch ( fArchitecture ) {
-                       case CPU_TYPE_I386:
-                               if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules
-                                       break;
-                       case CPU_TYPE_ARM:
-                               if ( fPrebind )
-                                       fNeedsModuleTable = true; // redo_prebinding requires a module table
-                               break;
-               }
-       }
-       
        // <rdar://problem/5366363> -r -x implies -S
        if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) )
                fDebugInfoStripping = Options::kDebugInfoNone;                  
@@ -4825,7 +4626,7 @@ void Options::reconfigureDefaults()
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        // <rdar://problem/16293398> Add LC_ENCRYPTION_INFO load command to bundled frameworks
-                       if ( !min_iOS(ld::iOS_7_0) )
+                       if ( !platforms().minOS(ld::version2013) )
                                fEncryptable = false;
                        break;
        }
@@ -4864,35 +4665,33 @@ void Options::reconfigureDefaults()
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        break;
+               case Options::kDyld:
+                       // arm64e has support for compressed LINKEDIT.
+                       if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) )
+                               break;
                case Options::kPreload:
                case Options::kStaticExecutable:
                case Options::kObjectFile:
-               case Options::kDyld:
                case Options::kKextBundle:
                        fMakeCompressedDyldInfoForceOff = true;
                        break;
        }
-       if ( fMakeCompressedDyldInfoForceOff ) 
-               fMakeCompressedDyldInfo = false;
 
-       
-       // only use compressed LINKEDIT for:
-       //                      Mac OS X 10.6 or later
-       //                      iOS 3.1 or later
-       if ( fMakeCompressedDyldInfo ) {
-               if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
-                       fMakeCompressedDyldInfo = false;
-       }
+       // only use legacy LINKEDIT if compressed LINKEDIT is forced off of:
+       //                      macOS before 10.6
+       //                      iOS before 3.1
+       if ( fMakeCompressedDyldInfoForceOff || !platforms().minOS(ld::version2009) )
+               fMakeCompressedDyldInfo = false;
 
        // only ARM and x86_64 enforces that cpu-sub-types must match
        switch ( fArchitecture ) {
                case CPU_TYPE_ARM:
+               case CPU_TYPE_ARM64:
                        break;
                case CPU_TYPE_X86_64:
                        fEnforceDylibSubtypesMatch = false;
                        break;
                case CPU_TYPE_I386:
-               case CPU_TYPE_ARM64:
                        fEnforceDylibSubtypesMatch = false;
                        break;
        }
@@ -4924,34 +4723,107 @@ void Options::reconfigureDefaults()
        }
        
        // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
-       if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+       if ( platforms().minOS(ld::version2008) )
                fUseSimplifiedDylibReExports = true;
        
        // Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB
-       if ( minOS(ld::mac10_7, ld::iOS_4_2) && (fOutputKind == kDynamicLibrary) )
+       if ( platforms().minOS(ld::version2010) && (fOutputKind == kDynamicLibrary) )
                fCanUseUpwardDylib = true;
-               
+
+       if (fArchitecture == CPU_TYPE_ARM64) {
+#if SUPPORT_ARCH_arm64e
+               if (fSubArchitecture == CPU_SUBTYPE_ARM64_E)
+               {
+                       // FIXME: Move some of these to arm64
+                       fNoLazyBinding = true;
+                       switch ( fOutputKind ) {
+                               case Options::kDynamicExecutable:
+                               case Options::kDynamicLibrary:
+                               case Options::kDynamicBundle:
+                               case Options::kDyld:
+                                       fUseLinkedListBinding = true;
+                                       fUseAuthenticatedStubs = true;
+                                       break;
+                               case Options::kPreload:
+                               case Options::kStaticExecutable:
+                               case Options::kObjectFile:
+                               case Options::kKextBundle:
+                                       break;
+                       }
+                       switch ( fOutputKind ) {
+                               case Options::kDynamicExecutable:
+                               case Options::kDyld:
+                               case Options::kDynamicLibrary:
+                               case Options::kObjectFile:
+                               case Options::kDynamicBundle:
+                               case Options::kKextBundle:
+                                       fSupportsAuthenticatedPointers = true;
+                                       break;
+                               case Options::kStaticExecutable:
+                               case Options::kPreload:
+                                       fSupportsAuthenticatedPointers = false;
+                                       break;
+                       }
+               }
+#endif
+       }
+
+       if ( fMakeThreadedStartsSection && (fArchitecture != CPU_TYPE_ARM64) ) {
+               // Threaded starts isn't valid here so ignore it.
+               warning("-threaded_starts_section ignored ignored for non-arm64");
+               fMakeThreadedStartsSection = false;
+       }
+
+       if (fMakeThreadedStartsSection) {
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                       case Options::kDyld:
+                       case Options::kDynamicLibrary:
+                       case Options::kObjectFile:
+                       case Options::kDynamicBundle:
+                       case Options::kKextBundle:
+                               // Threaded starts isn't valid here so ignore it.
+                               warning("-threaded_starts_section ignored for binaries other than -static or -preload");
+                               fMakeThreadedStartsSection = false;
+                               break;
+                       case Options::kStaticExecutable:
+                       case Options::kPreload:
+                               fUseLinkedListBinding = true;
+                               fNoLazyBinding = true;
+#if SUPPORT_ARCH_arm64e
+                               if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) )
+                                       fSupportsAuthenticatedPointers = true;
+#endif
+                               break;
+               }
+       }
+
+       // Weak binding requires that if we want to use linked list binding, we must
+       // also be using no lazy binding.
+       if ( fUseLinkedListBinding )
+               assert(fNoLazyBinding);
+       
        // MacOSX 10.7 defaults to PIE
        if ( (fArchitecture == CPU_TYPE_I386)
                && (fOutputKind == kDynamicExecutable)
-               && (fMacVersionMin >= ld::mac10_7) ) {
+               && platforms().minOS(ld::mac10_7) ) {
                        fPositionIndependentExecutable = true;
        }
 
        // armv7 for iOS4.3 defaults to PIE
        if ( (fArchitecture == CPU_TYPE_ARM) 
                && fArchSupportsThumb2
-               && (fOutputKind == kDynamicExecutable) 
-               && min_iOS(ld::iOS_4_3) ) {
+               && (fOutputKind == kDynamicExecutable)
+               && (platforms().contains(ld::kPlatform_watchOS) || platforms().minOS(ld::iOS_4_3)) ) {
                        fPositionIndependentExecutable = true;
        }
 
-       // <rdar://problem/24535196> x86_64 defaults PIE (regardless of minOS version)
-       if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (fMacVersionMin >= ld::mac10_6) )
+       // <rdar://problem/24535196> x86_64 defaults PIE (for 10.6 and later)
+       if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (platforms().minOS(ld::mac10_6) || platforms().contains(ld::kPlatform_iOSMac)) )
                fPositionIndependentExecutable = true;
 
        // Simulator defaults to PIE
-       if ( fTargetIOSSimulator && (fOutputKind == kDynamicExecutable) )
+       if ( targetIOSSimulator() && (fOutputKind == kDynamicExecutable) )
                fPositionIndependentExecutable = true;
 
        // -no_pie anywhere on command line disable PIE
@@ -4987,22 +4859,12 @@ void Options::reconfigureDefaults()
                        break;
        }
 
-       // let linker know if thread local variables are supported
-       if ( fMacVersionMin >= ld::mac10_7 ) {
-               fTLVSupport = true;
-       }
-       else if ( ((fArchitecture == CPU_TYPE_ARM64)
-               )
-             && min_iOS(ld::iOS_8_0) ) {
-               fTLVSupport = true;
-       }
-       else if ( (fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_9_0) ) {
-               fTLVSupport = true;
-       }
-       else if ( fTargetIOSSimulator && (fArchitecture == CPU_TYPE_X86_64) && min_iOS(ld::iOS_8_0) ) {
-               fTLVSupport = true;
-       }
-       else if ( fTargetIOSSimulator && (fArchitecture == CPU_TYPE_I386) && min_iOS(ld::iOS_9_0) ) {
+       // Let linker know if thread local variables are supported
+       // This is more complex than normal version checks since
+       // runtime support varies by architecture
+       if (platforms().minOS(ld::supportsTLV)
+                       || ((fArchitecture == CPU_TYPE_ARM64) && platforms().minOS(ld::iOS_8_0))
+                       || ((fArchitecture == CPU_TYPE_X86_64) && platforms().minOS(ld::iOS_9_0))) {
                fTLVSupport = true;
        }
 
@@ -5027,7 +4889,7 @@ void Options::reconfigureDefaults()
        }
        
        // support re-export of individual symbols in MacOSX 10.7 and iOS 4.2
-       if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iOS_4_2) )
+       if ( (fOutputKind == kDynamicLibrary) && platforms().minOS(ld::version2010) )
                fCanReExportSymbols = true;
        
        // ObjC optimization is only in dynamic final linked images
@@ -5054,33 +4916,21 @@ void Options::reconfigureDefaults()
        // Use LC_MAIN instead of LC_UNIXTHREAD for newer OSs
        switch ( fOutputKind ) {
                case Options::kDynamicExecutable:
-                       if ( fEntryPointLoadCommandForceOn ) {
+                       // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS
+                       if ( platforms().minOS(ld::version2012) ) {
                                fEntryPointLoadCommand = true;
-                               if ( fEntryName == NULL ) 
+                               if ( fEntryName == NULL )
                                        fEntryName = "_main";
+                               if ( strcmp(fEntryName, "start") == 0 ) {
+                                       warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version");
+                                       fEntryName = "_main";
+                               }
                        }
-                       else if ( fEntryPointLoadCommandForceOff ) {
+                       else {
                                fNeedsThreadLoadCommand = true;
-                               if ( fEntryName == NULL ) 
+                               if ( fEntryName == NULL )
                                        fEntryName = "start";
                        }
-                       else {
-                               // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS
-                               if ( minOS(ld::mac10_8, ld::iOS_6_0) || fTargetIOSSimulator ) {
-                                       fEntryPointLoadCommand = true;
-                                       if ( fEntryName == NULL ) 
-                                               fEntryName = "_main";
-                                       if ( strcmp(fEntryName, "start") == 0 ) {
-                                               warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version");
-                                               fEntryName = "_main";
-                                       }
-                               } 
-                               else {
-                                       fNeedsThreadLoadCommand = true;
-                                       if ( fEntryName == NULL ) 
-                                               fEntryName = "start";
-                               }
-                       }
                        break;
                case Options::kObjectFile:
                case Options::kKextBundle:
@@ -5112,7 +4962,7 @@ void Options::reconfigureDefaults()
                                fSourceVersionLoadCommand = false;
                        }
                        else {
-                               if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+                               if ( platforms().minOS(ld::version2012) ) {
                                        fSourceVersionLoadCommand = true;
                                }
                                else
@@ -5141,12 +4991,12 @@ void Options::reconfigureDefaults()
                        fSDKVersion = parseVersionNumber32(sdkVersionStr);
                }
        }
-       
+
        // if -sdk_version and -syslibroot not used, but targeting MacOSX, use current OS version
-       if ( (fSDKVersion == 0) && (fMacVersionMin != ld::macVersionUnset) ) {
+       if ( (fSDKVersion == 0) && platforms().contains(ld::kPlatform_macOS) ) {
                // special case if RC_ProjectName and MACOSX_DEPLOYMENT_TARGET are both set that sdkversion=minos
                if ( getenv("RC_ProjectName") && getenv("MACOSX_DEPLOYMENT_TARGET") ) {
-                       fSDKVersion = fMacVersionMin;
+                       fSDKVersion = platforms().minOS(ld::kPlatform_macOS);
                }
                else {
                        int mib[2] = { CTL_KERN, KERN_OSRELEASE };
@@ -5162,18 +5012,15 @@ void Options::reconfigureDefaults()
        
        // allow trie based absolute symbols if targeting new enough OS
        if ( fMakeCompressedDyldInfo ) {
-               if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
+               if ( platforms().minOS(ld::version2013) ) {
                        fAbsoluteSymbols = true;
                }
        }
-       
-       // <rdar://problem/12959510> iOS main executables now default to 16KB page size
-       if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fOutputKind == Options::kDynamicExecutable) ) {
-               // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
-               if ( fEncryptable ) {
-                       if ( fSegmentAlignment == 4096 )
-                               fSegmentAlignment = 4096*4;
-               }
+
+       // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
+       if ( fEncryptable ) {
+               if ( fSegmentAlignment == 4096 )
+                       fSegmentAlignment = 4096*4;
        }
   
        // <rdar://problem/12258065> ARM64 needs 16KB page size for user land code
@@ -5184,18 +5031,17 @@ void Options::reconfigureDefaults()
                        case Options::kDynamicLibrary:
                        case Options::kDynamicBundle:
                        case Options::kDyld:
-                               if ( ((fArchitecture == CPU_TYPE_ARM64)
-                     )
-                               || ((fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_7_0)) ) {
+                               // <rdar://problem/14676611> 16KB segments for arm64 kexts
+                               if ( (fArchitecture == CPU_TYPE_ARM64)
+                     || (fArchitecture == CPU_TYPE_ARM) ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
                        case Options::kStaticExecutable:
                        case Options::kKextBundle:
                                // <rdar://problem/14676611> 16KB segments for arm64 kexts
-                               if ( ((fArchitecture == CPU_TYPE_ARM64)
-                     )
-                                   && min_iOS(ld::iOS_9_0) ) {
+                               if ( (fArchitecture == CPU_TYPE_ARM64)
+                                       ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
@@ -5220,7 +5066,7 @@ void Options::reconfigureDefaults()
                                fKeepDwarfUnwind = false;
                        }
                        else {
-                               if ( minOS(ld::mac10_9, ld::iOS_7_0) ) 
+                               if ( platforms().minOS(ld::version2013) )
                                        fKeepDwarfUnwind = false;
                                else
                                        fKeepDwarfUnwind = true;
@@ -5257,6 +5103,24 @@ void Options::reconfigureDefaults()
        }
 
 
+       // Look in $SDKROOT/AppleInternal/AccessibilityLinkerSymbols/<dylib>.axsymbols for objc-class names
+       if ( fUseDataConstSegment && (fDylibInstallName != NULL) && !fSDKPaths.empty() ) {
+               const char* dylibLeaf = strrchr(fDylibInstallName, '/');
+               if ( dylibLeaf ) {
+                       char path[PATH_MAX];
+                       strlcpy(path , fSDKPaths.front(), sizeof(path));
+                       strlcat(path , "/AppleInternal/AccessibilityLinkerSymbols", sizeof(path));
+                       strlcat(path , dylibLeaf, sizeof(path));
+                       strlcat(path , ".axsymbols", sizeof(path));
+                       FileInfo info;
+                       if ( info.checkFileExists(*this, path) ) {
+                               SymbolsMove tmp;
+                               fSymbolsMovesAXMethodLists.push_back(tmp);
+                               loadExportFile(path, ".axsymbols", fSymbolsMovesAXMethodLists.back().symbols);
+                       }
+               }
+       }
+
        // <rdar://problem/32138080> Automatically use OrderFiles found in the AppleInternal SDK
        if ( (fFinalName != NULL) && fOrderedSymbols.empty() && !fSDKPaths.empty() ) {
                char path[PATH_MAX];
@@ -5278,11 +5142,11 @@ void Options::reconfigureDefaults()
        }
 
        // Add warnings for issues likely to cause OS verification issues
-       if ( fSharedRegionEligible && !fRPaths.empty() ) {
+       if ( fSharedRegionEligible && !fRPaths.empty() && !fDebugVariant ) {
                // <rdar://problem/18719327> warn if -rpath is used with OS dylibs
                warning("OS dylibs should not add rpaths (linker option: -rpath) (Xcode build setting: LD_RUNPATH_SEARCH_PATHS)");
        }
-       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (fFinalName != NULL) && sharedCacheEligiblePath(fFinalName) ) {
+       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (fFinalName != NULL) && sharedCacheEligiblePath(fFinalName) && !fDebugVariant ) {
                if ( strncmp(fDylibInstallName, "@rpath", 6) == 0 )
                        warning("OS dylibs should not use @rpath for -install_name.  Use absolute path instead");
                if ( strcmp(fDylibInstallName, fFinalName) != 0 ) {
@@ -5312,15 +5176,20 @@ void Options::reconfigureDefaults()
        }
 
        // set if unaligned pointers are warnings or errors
-       if ( fMacVersionMin >= ld::mac10_12 ) {
+       if ( platforms().minOS(ld::mac10_12) ) {
                // ignore unaligned pointers when targeting older macOS versions
                if ( fSharedRegionEligible )
                        fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
                else
                        fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
        }
-       else if ( min_iOS(ld::iOS_10_0) ) {
-               fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
+       else if ( platforms().minOS(ld::iOS_10_0) ) {
+#if SUPPORT_ARCH_arm64e
+               if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) ) {
+                               fUnalignedPointerTreatment = Options::kUnalignedPointerError;
+               } else
+#endif
+                       fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
        }
        else {
                fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
@@ -5328,11 +5197,8 @@ void Options::reconfigureDefaults()
 
        // warn by default for OS dylibs
        if ( fInitializersTreatment == Options::kInvalid ) {
-               if ( fSharedRegionEligible && (fOutputKind == Options::kDynamicLibrary) ) {
+               if ( fSharedRegionEligible && (fOutputKind == Options::kDynamicLibrary) && !fDebugVariant ) {
                        fInitializersTreatment = Options::kWarning;
-                       // TEMP HACK
-                       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (strstr(fDylibInstallName, "EmbeddedAcousticRecognition.framework") != NULL) && !fNoWeakExports )
-                               fInitializersTreatment = Options::kSuppress;
                }
                else
                        fInitializersTreatment = Options::kSuppress;
@@ -5347,23 +5213,26 @@ void Options::checkIllegalOptionCombinations()
                case kUndefinedError:
                        // always legal
                        break;
-               case kUndefinedDynamicLookup:
-                       switch (fPlatform) {
-                               case kPlatformOSX:
-                                       break;
-                               case kPlatformiOS:
-                               case kPlatformWatchOS:
-                               case kPlatform_bridgeOS:
-               #if SUPPORT_APPLE_TV
-                               case kPlatform_tvOS:
-               #endif
-                                       if ( fOutputKind != kKextBundle )
-                                               warning("-undefined dynamic_lookup is deprecated on %s", platformName(fPlatform));
-                                       break;
-                               default:
-                                       break;
-                       }
-                       break;
+               case kUndefinedDynamicLookup: {
+                       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               switch (platform) {
+                                       case ld::kPlatform_macOS:
+                                       case ld::kPlatform_iOSMac:
+                                       case ld::kPlatform_unknown:
+                                               break;
+                                       case ld::kPlatform_iOS:
+                                       case ld::kPlatform_iOSSimulator:
+                                       case ld::kPlatform_watchOS:
+                                       case ld::kPlatform_watchOSSimulator:
+                                       case ld::kPlatform_bridgeOS:
+                                       case ld::kPlatform_tvOS:
+                                       case ld::kPlatform_tvOSSimulator:
+                                               if ( fOutputKind != kKextBundle )
+                                                       warning("-undefined dynamic_lookup is deprecated on %s", platformName(platform));
+                                               break;
+                               }
+                       });
+               } break;
                case kUndefinedWarning:
                case kUndefinedSuppress:
                        // requires flat namespace
@@ -5422,20 +5291,24 @@ void Options::checkIllegalOptionCombinations()
        // sync reader options
        if ( fNameSpace != kTwoLevelNameSpace ) {
                fFlatNamespace = true;
-               switch (fPlatform) {
-                       case kPlatformOSX:
-                               break;
-                       case kPlatformiOS:
-                       case kPlatformWatchOS:
-                       case kPlatform_bridgeOS:
-       #if SUPPORT_APPLE_TV
-                       case Options::kPlatform_tvOS:
-       #endif
-                               warning("-flat_namespace is deprecated on %s", platformName(fPlatform));
-                               break;
-                       default:
-                               break;
-               }
+               platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                       switch (platform) {
+                               case ld::kPlatform_unknown:
+                               case ld::kPlatform_macOS:
+                               case ld::kPlatform_iOSMac:
+                                       break;
+                               case ld::kPlatform_iOS:
+                               case ld::kPlatform_iOSSimulator:
+                               case ld::kPlatform_watchOS:
+                               case ld::kPlatform_watchOSSimulator:
+                               case ld::kPlatform_bridgeOS:
+                               case ld::kPlatform_tvOS:
+                               case ld::kPlatform_tvOSSimulator:
+                                       warning("-flat_namespace is deprecated on %s", platformName(platform));
+                                       break;
+                       }
+               });
+
        }
 
 
@@ -5461,7 +5334,7 @@ void Options::checkIllegalOptionCombinations()
        if ( fStackSize != 0 ) {
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
-                               if ( fPlatform == kPlatformOSX ) {
+                               if ( platforms().contains(ld::kPlatform_macOS) ) {
                                        if ( fStackSize > 0xFFFFFFFF )
                                                throw "-stack_size must be < 4GB for 32-bit processes";
                                        if ( fStackAddr == 0 )
@@ -5485,7 +5358,7 @@ void Options::checkIllegalOptionCombinations()
                     throw "-stack_addr must be < 0x20000000 for arm";
                                break;
                        case CPU_TYPE_X86_64:
-                               if ( fPlatform == kPlatformOSX ) {
+                               if ( platforms().contains(ld::kPlatform_macOS) ) {
                                        if ( fStackSize > 0x10000000000 )
                                                throw "-stack_size must be <= 1TB";
                                        if ( fStackAddr == 0 ) {
@@ -5603,7 +5476,7 @@ void Options::checkIllegalOptionCombinations()
                throw "-setuid_safe cannot be used with -r";
 
        // <rdar://problem/12781832> compiler driver no longer uses -objc_abi_version, it uses -ios_simulator_version_min instead
-       if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && fTargetIOSSimulator )
+       if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && targetIOSSimulator() )
                fObjCABIVersion2Override = true;
 
        // rdar://problem/4718189 map ObjC class names to new runtime names
@@ -5753,7 +5626,7 @@ void Options::checkIllegalOptionCombinations()
 
        // can't use -rpath unless targeting 10.5 or later
        if ( fRPaths.size() > 0 ) {
-               if ( !minOS(ld::mac10_5, ld::iOS_2_0) )
+               if ( !platforms().minOS(ld::version2008) )
                        throw "-rpath can only be used when targeting Mac OS X 10.5 or later";
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
@@ -5773,11 +5646,8 @@ void Options::checkIllegalOptionCombinations()
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
                                // check -pie is only used when building a dynamic main executable for 10.5
-                               if ( !minOS(ld::mac10_5, ld::iOS_4_2) ) {
-                                       if ( fIOSVersionMin == ld::iOSVersionUnset )
-                                               throw "-pie can only be used when targeting Mac OS X 10.5 or later";
-                                       else
-                                               throw "-pie can only be used when targeting iOS 4.2 or later";
+                               if ( !platforms().minOS(ld::supportsPIE) ) {
+                                       throw "-pie requires targetting a newer minimum version";
                                }
                                break;
                        case Options::kStaticExecutable:
@@ -5796,12 +5666,15 @@ void Options::checkIllegalOptionCombinations()
                }
        }
        
-       // check -read_only_relocs is not used with x86_64
+       // check -read_only_relocs is not used with x86_64 or arm64
        if ( fAllowTextRelocs ) {
                if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind != kKextBundle) ) {
                        warning("-read_only_relocs cannot be used with x86_64");
                        fAllowTextRelocs = false;
                }
+               else if ( fArchitecture == CPU_TYPE_ARM64 ) {
+                       warning("-read_only_relocs cannot be used with arm64");
+               }
        }
        
        // check -mark_auto_dead_strip is only used with dylibs
@@ -5823,7 +5696,7 @@ void Options::checkIllegalOptionCombinations()
        if ( !fReExportSymbols.empty() ) {
                if ( fOutputKind != Options::kDynamicLibrary )
                        throw "-reexported_symbols_list can only used used when created dynamic libraries";
-               if ( !minOS(ld::mac10_7, ld::iOS_4_2) )
+               if ( !platforms().minOS(ld::version2010) )
                        throw "targeted OS version does not support -reexported_symbols_list";
        }
        
@@ -5852,21 +5725,80 @@ void Options::checkIllegalOptionCombinations()
 
        // <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
        // <rdar://problem/18935714> How can we suppress "ld: warning: embedded dylibs/frameworks only run on iOS 8 or later" when building XCTest?
-       if ( (fOutputKind == Options::kDynamicLibrary) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) {
-               if ( !min_iOS(ld::iOS_8_0) && (fDylibInstallName[0] == '@') && !fEncryptableForceOff )
+       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) ) {
+               if ( platforms().contains(ld::kPlatform_iOS) && !platforms().minOS(ld::iOS_8_0) && (fDylibInstallName[0] == '@') && !fEncryptableForceOff )
                        warning("embedded dylibs/frameworks only run on iOS 8 or later");
        }
 
-       // bridgeOS always generates new load command
-       if ( fVersionLoadCommand && (fPlatform == kPlatform_bridgeOS) ) {
-               fBuildVersionLoadCommand = true;
-       }
-
        // produce nicer error when no input
        if ( fInputFiles.empty() ) {
                throw "no object files specified";
        }
-}      
+
+       // Check zippered combinations.
+       if (platforms().count() > 2) {
+               throw "Illegal platform count.  Only 2 platforms at a maximum can be specified";
+       }
+
+       // Convert from -ios_version_min to -ios_simulator_version_min for now until clang has been updated
+       if (architecture() == CPU_TYPE_X86_64 || architecture() == CPU_TYPE_X86) {
+               if (platforms().contains(ld::kPlatform_iOS)) {
+                       uint32_t version = platforms().minOS(ld::kPlatform_iOS);
+                       fPlatforms.erase(ld::kPlatform_iOS);
+                       // HACK infer the build environment from the SDK path
+                       bool macOSSDK = false;
+                       for (const auto& sdkPath : fSDKPaths) {
+                               if (strstr(sdkPath, "MacOSX10") != 0) {
+                                       macOSSDK = true;
+                                       break;
+                               }
+                       }
+                       if (macOSSDK) {
+                               fPlatforms.add({ ld::kPlatform_iOSMac, version });
+                               warning("URGENT: -ios_version_min is invalid for architecture x86/x86_64, inferring -iosmac_version_min. "
+                                               "This will be an error in the future.");
+                       } else {
+                               fPlatforms.add({ ld::kPlatform_iOSSimulator, version });
+                               warning("URGENT: -ios_version_min is invalid for architecture x86/x86_64, inferring -ios_simulator_version_min. "
+                                               "This will be an error in the future.");
+                       }
+               }
+       }
+
+       if (platforms().count() == 2) {
+               if (!platforms().minOS(ld::mac10_14))
+                       throw "Zippered macOS version platform must be at least 10.14";
+               if (!platforms().minOS(ld::iOS_12_0))
+                       throw "Zippered iosmac version platform must be at least 12.0";
+       }
+
+       if (platforms().contains(ld::kPlatform_iOSMac) && !platforms().minOS(ld::iOS_12_0)) {
+               throw "iosmac platform version must be at least 12.0";
+       }
+
+       // <rdar://problem/38155581> ld64 shouldn't allow final executables to have more than one version load command
+       if ( platforms().contains(ld::kPlatform_iOSMac) && platforms().contains(ld::kPlatform_macOS) ) {
+               if ( (fOutputKind != Options::kDynamicLibrary) && (fOutputKind != Options::kDynamicBundle) ) {
+                       warning("Only dylibs and bundles can be zippered, changing output to be macOS only.");
+                       fPlatforms.erase(ld::kPlatform_iOSMac);
+               }
+       }
+
+       // <rdar://problem/39095109> Linker warning for i386 macOS binaries
+       if ( (architecture() == CPU_TYPE_I386) && platforms().contains(ld::kPlatform_macOS) ) {
+               bool internalSDK = false;
+               for (const char* sdkPath : fSDKPaths) {
+                       std::string possiblePath = std::string(sdkPath) + "/AppleInternal/";
+                       struct stat statBuffer;
+                       if ( stat(possiblePath.c_str(), &statBuffer) == 0 ) {
+                               internalSDK = true;
+                               break;
+                       }
+               }
+               if ( !internalSDK )
+                       warning("The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)");
+       }
+}
 
 
 void Options::checkForClassic(int argc, const char* argv[])
@@ -6006,7 +5938,7 @@ const char* Options::demangleSymbol(const char* sym) const
 
 #if DEMANGLE_SWIFT
        // only try to demangle symbols that look like Swift symbols
-       if ( strncmp(sym, "__T", 3) == 0 ) {
+       if ( strncmp(sym, "_$", 2) == 0 ) {
                size_t demangledSize = fnd_get_demangled_name(&sym[1], buff, size);
                if ( demangledSize > size ) {
                        size = demangledSize+2;