]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/Options.cpp
ld64-278.4.tar.gz
[apple/ld64.git] / src / ld / Options.cpp
index 8106e933614f1819569c08748e5e61f933f68b0d..d36bc02cfc6b6835b331685cba79ff40904a996f 100644 (file)
@@ -34,6 +34,7 @@
 #include <spawn.h>
 #include <cxxabi.h>
 #include <Availability.h>
+#include <tapi/tapi.h>
 
 #include <vector>
 #include <map>
@@ -119,12 +120,12 @@ bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
          p = path;
        if ( stat(p, &statBuffer) == 0 ) {
                if (p != path) path = strdup(p);
-               fileLen = statBuffer.st_size;
                modTime = statBuffer.st_mtime;
                return true;
        }
        if ( options.dumpDependencyInfo() )
                options.dumpDependency(Options::depNotFound, p);
+//     fprintf(stderr, "not found: %s\n", p);
     return false;
 }
 
@@ -143,7 +144,7 @@ Options::Options(int argc, const char* argv[])
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
          fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
-         fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
+         fDyldInstallPath("/usr/lib/dyld"), fLtoCachePath(NULL), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
          fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
@@ -157,7 +158,7 @@ Options::Options(int argc, const char* argv[])
          fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false),
          fOrderData(true), fMarkDeadStrippableDylib(false),
          fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
-         fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
+         fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(false), fUseSimplifiedDylibReExports(false),
          fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false),
          fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false),
          fLinkingMainExecutable(false), fForFinalLinkedImage(false), fForStatic(false),
@@ -165,7 +166,7 @@ Options::Options(int argc, const char* argv[])
          fSetuidSafe(false), fImplicitlyLinkPublicDylibs(true), fAddCompactUnwindEncoding(true),
          fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false),
          fAutoOrderInitializers(true), fOptimizeZeroFill(true), fMergeZeroFill(false), fLogObjectFiles(false),
-         fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false),
+         fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceEmitJSON(false),
          fOutputSlidable(false), fWarnWeakExports(false), 
          fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), 
          fDemangle(false), fTLVSupport(false), 
@@ -185,14 +186,15 @@ Options::Options(int argc, const char* argv[])
          fGenerateDtraceDOF(true), fAllowBranchIslands(true), fTraceSymbolLayout(false), 
          fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false),
          fSharedRegionEncodingV2(false), fUseDataConstSegment(false),
-         fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false),
+         fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false), fUseTextExecSegment(false),
          fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
-         fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
-         fIgnoreAutoLink(false), fAllowDeadDups(false), fBitcodeKind(kBitcodeProcess),
+         fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false),
+         fReverseMapPath(NULL), fLTOCodegenOnly(false),
+         fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fBitcodeKind(kBitcodeProcess),
          fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
-         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
+         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset),
          fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
-         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
+         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -210,8 +212,11 @@ Options::Options(int argc, const char* argv[])
 
 Options::~Options()
 {
-  if ( fDependencyFileDescriptor != -1 )
-       ::close(fDependencyFileDescriptor);
+       if ( fDependencyFileDescriptor != -1 )
+               ::close(fDependencyFileDescriptor);
+
+       if ( fTraceFileDescriptor != -1 )
+               ::close(fTraceFileDescriptor);
 }
 
 bool Options::errorBecauseOfWarnings() const
@@ -318,12 +323,15 @@ uint32_t Options::initialSegProtection(const char* segName) const
                        return it->init;
                }
        }
-       if ( strcmp(segName, "__PAGEZERO") == 0 ) {
-               return 0;
+       if ( strcmp(segName, "__TEXT") == 0 ) {
+               return ( fUseTextExecSegment ? VM_PROT_READ : (VM_PROT_READ | VM_PROT_EXECUTE) );
        }
-       else if ( strcmp(segName, "__TEXT") == 0 ) {
+       else if ( strcmp(segName, "__TEXT_EXEC") == 0 ) {
                return VM_PROT_READ | VM_PROT_EXECUTE;
        }
+       else if ( strcmp(segName, "__PAGEZERO") == 0 ) {
+               return 0;
+       }
        else if ( strcmp(segName, "__LINKEDIT") == 0 ) {
                return VM_PROT_READ;
        }
@@ -390,6 +398,9 @@ bool Options::hasCustomSectionAlignment(const char* segName, const char* sectNam
                if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
                        return true;
        }
+       if ( fEncryptable && (strcmp(sectName, "__oslogstring") == 0) && (strcmp(segName, "__TEXT") == 0) )
+               return true;
+
        return false;
 }
 
@@ -399,6 +410,9 @@ uint8_t Options::customSectionAlignment(const char* segName, const char* sectNam
                if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
                        return it->alignment;
        }
+       if ( fEncryptable && (strcmp(sectName, "__oslogstring") == 0) && (strcmp(segName, "__TEXT") == 0) )
+               return __builtin_ctz(fSegmentAlignment);
+
        return 0;
 }
 
@@ -603,7 +617,7 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::P
                        switch ( type ) {
                                case CPU_TYPE_I386:
                                case CPU_TYPE_X86_64:
-                                       if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) ) {
+                                       if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) && (fMacVersionMin == ld::macVersionUnset) ) {
                                #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
@@ -615,7 +629,7 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::P
                                        break;
                                case CPU_TYPE_ARM:
                                case CPU_TYPE_ARM64:
-                                       if ( (fPlatform == kPlatformiOS) && (fOutputKind != Options::kObjectFile) ) {
+                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (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);
@@ -712,9 +726,8 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) co
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
-                                               if ( checkForFile("%s/lib%s.tbd", dir, rootName, result) )
-                                                       return result;
-                                               if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+                                               auto path = std::string(dir) + "/lib" + rootName + ".dylib";
+                                               if ( findFile(path, {".tbd"}, result) )
                                                        return result;
                                        }
                                        for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
@@ -743,9 +756,8 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) co
                                         it != fLibrarySearchPaths.end();
                                         it++) {
                                        const char* dir = *it;
-                                       if ( lookForDylibs && checkForFile("%s/lib%s.tbd", dir, rootName, result) )
-                                               return result;
-                                       if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+                                       auto path = std::string(dir) + "/lib" + rootName + ".dylib";
+                                       if ( lookForDylibs && findFile(path, {".tbd"}, result) )
                                                return result;
                                        if ( lookForDylibs && checkForFile("%s/lib%s.so", dir, rootName, result) )
                                                return result;
@@ -785,15 +797,8 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                                possiblePath = std::string(realPath).append(suffix);
                }
         FileInfo result;
-               bool found = result.checkFileExists(*this, (possiblePath + ".tbd").c_str());
-               if ( !found )
-                       found = result.checkFileExists(*this, possiblePath.c_str());
-               if ( fTraceDylibSearching )
-                       printf("[Logging for XBS]%sfound framework: '%s'\n",
-                                  (found ? " " : " not "), possiblePath.c_str());
-               if ( found ) {
+               if ( findFile(possiblePath, {".tbd"}, result) )
                        return result;
-               }
        }
        // try without suffix
        if ( suffix != NULL )
@@ -802,75 +807,144 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                throwf("framework not found %s", rootName);
 }
 
-Options::FileInfo Options::findFile(const std::string &path) const
+static std::string replace_extension(const std::string &path, const std::string &ext)
+{
+       auto result = path;
+       auto lastSlashIdx = result.find_last_of('/');
+       auto lastDotIdx = result.find_last_of('.');
+       if (lastDotIdx != std::string::npos && lastDotIdx > lastSlashIdx)
+               result.erase(lastDotIdx, std::string::npos);
+       if ( ext.size() > 0 && ext[0] == '.' )
+               result.append(ext);
+       else
+               result.append('.' + ext);
+       return result;
+}
+
+bool Options::findFile(const std::string &path, const std::vector<std::string> &tbdExtensions, FileInfo& result) const
+{
+       FileInfo tbdInfo;
+       for ( const auto &ext : tbdExtensions ) {
+               auto newPath = replace_extension(path, ext);
+               bool found = tbdInfo.checkFileExists(*this, newPath.c_str());
+               if ( fTraceDylibSearching )
+                       printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), newPath.c_str());
+               if ( found )
+                       break;
+       }
+
+       FileInfo dylibInfo;
+       {
+               bool found = dylibInfo.checkFileExists(*this, path.c_str());
+               if ( fTraceDylibSearching )
+                       printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), path.c_str());
+       }
+
+       // There is only a text-based stub file or a dynamic library file.
+       if ( tbdInfo.missing() != dylibInfo.missing() ) {
+               result = tbdInfo.missing() ? dylibInfo : tbdInfo;
+       }
+       // There are both - a text-based stub file and a dynamic library file.
+       else if ( !tbdInfo.missing() && !dylibInfo.missing() ) {
+               // Check if we should prefer the text-based stub file (installapi).
+               if (tapi::LinkerInterfaceFile::shouldPreferTextBasedStubFile(tbdInfo.path)) {
+                       result = tbdInfo;
+               }
+               // If the files are still in sync we can use and should use the text-based stub file.
+               else if (tapi::LinkerInterfaceFile::areEquivalent(tbdInfo.path, dylibInfo.path)) {
+                       result = tbdInfo;
+               }
+               // Otherwise issue a warning and fall-back to the dynamic library file.
+               else {
+                       warning("text-based stub file %s and library file %s are out of sync. Falling back to library file for linking.", tbdInfo.path, dylibInfo.path);
+                       result = dylibInfo;
+               }
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+static bool startsWith(const std::string& str, const std::string& prefix)
+{
+       return (str.compare(0, prefix.length(), prefix) == 0);
+}
+
+static std::string getDirPath(const std::string& path)
+{
+       std::string::size_type lastSlashPos = path.find_last_of('/');
+       if ( lastSlashPos == std::string::npos )
+               return "./";
+       else
+               return path.substr(0, lastSlashPos+1);
+}
+
+Options::FileInfo Options::findFile(const std::string &path, const ld::dylib::File* fromDylib) const
 {
        FileInfo result;
 
        // if absolute path and not a .o file, then use SDK prefix
        if ( (path[0] == '/') && (strcmp(&path[path.size()-2], ".o") != 0) ) {
-               auto tbdFile = path;
-               auto lastSlashIdx = tbdFile.find_last_of('/');
-               auto lastDotIdx = tbdFile.find_last_of('.');
-               if (lastDotIdx != std::string::npos && lastDotIdx > lastSlashIdx)
-                       tbdFile.erase(lastDotIdx, std::string::npos);
-               tbdFile.append(".tbd");
-
                for (const auto* sdkPathDir : fSDKPaths) {
-                       auto possiblePath = std::string(sdkPathDir) + tbdFile;
-                       if ( result.checkFileExists(*this, possiblePath.c_str()) )
-                               return result;
-                       possiblePath = std::string(sdkPathDir) + path;
-                       if ( result.checkFileExists(*this, possiblePath.c_str()) )
+                       auto possiblePath = std::string(sdkPathDir) + path;
+                       if ( findFile(possiblePath, {".tbd"}, result) )
                                return result;
                }
        }
-       // try raw path
-       {
-               std::string file = path;
-               auto lastDotIdx = file.find_last_of('.');
-               if (lastDotIdx != std::string::npos)
-                       file.erase(lastDotIdx, std::string::npos);
-               if ( result.checkFileExists(*this, file.append(".tbd").c_str()) )
-                       return result;
-       }
-       if ( result.checkFileExists(*this, path.c_str()) ) {
-               return result;
-       }
 
-
-       // try @executable_path substitution
-       if ( (path.find("@executable_path/") == 0) && (fExecutablePath != nullptr) ) {
-               char newPath[strlen(fExecutablePath) + path.size()];
-               strcpy(newPath, fExecutablePath);
-               char* addPoint = strrchr(newPath,'/');
-               if ( addPoint != nullptr )
-                       strcpy(&addPoint[1], &path[17]);
-               else
-                       strcpy(newPath, &path[17]);
-
-               std::string file = newPath;
-               auto lastDotIdx = file.find_last_of('.');
-               if (lastDotIdx != std::string::npos)
-                       file.erase(lastDotIdx, std::string::npos);
-               if ( result.checkFileExists(*this, file.append(".tbd").c_str()) ) {
-                       return result;
+       // expand @ variables
+       if ( path[0] == '@' ) {
+               if ( startsWith(path, "@executable_path/") && (fExecutablePath != nullptr) ) {
+                       std::string exeBasedPath = getDirPath(fExecutablePath) + &path[17];
+                       if ( findFile(exeBasedPath, {".tbd"}, result) )
+                               return result;
                }
-               if ( result.checkFileExists(*this, newPath) ) {
-                       return result;
+               else if ( startsWith(path, "@loader_path/") && (fromDylib != nullptr) ) {
+                       char absPath[PATH_MAX];
+                       if ( realpath(fromDylib->path(), absPath) != NULL ) {
+                               std::string loaderBasedPath = getDirPath(fromDylib->path()) + &path[13];
+                               if ( findFile(loaderBasedPath, {".tbd"}, result) )
+                                       return result;
+                       }
+               }
+               else if ( startsWith(path, "@rpath/") ) {
+                       // first search any LC_RPATH supplied by dyld that re-exports dylib to be found
+                       if ( fromDylib != nullptr ) {
+                               for (const char* rp : fromDylib->rpaths() ) {
+                                       std::string rpath = rp;
+                                       // handle dylib that has LC_RPATH = @loader_path/blah
+                                       if ( startsWith(rpath, "@loader_path/") ) {
+                                               char absPath[PATH_MAX];
+                                               if ( realpath(fromDylib->path(), absPath) != NULL )
+                                                       rpath = getDirPath(absPath) + &rpath[13];
+                                               else
+                                                       rpath = getDirPath(fromDylib->path()) + &rpath[13];
+                                       }
+                                       std::string rpathBasedPath = rpath + "/" + &path[6];
+                                       if ( findFile(rpathBasedPath, {".tbd"}, result) )
+                                               return result;
+                               }
+                       }
                }
        }
 
+       // try raw path
+       if ( findFile(path, {".tbd"}, result) )
+               return result;
+
        // not found
        throwf("file not found: %s", path.c_str());
 }
 
-Options::FileInfo Options::findFileUsingPaths(const std::string &path) const
+// search for indirect dylib first using -F and -L paths first
+Options::FileInfo Options::findIndirectDylib(const std::string& installName, const ld::dylib::File* fromDylib) const
 {
        FileInfo result;
 
-       auto lastSlashPos = path.find_last_of('/');
+       auto lastSlashPos = installName.find_last_of('/');
        auto pos = ( lastSlashPos != std::string::npos ) ? lastSlashPos + 1 : 0;
-       auto leafName = path.substr(pos);
+       auto leafName = installName.substr(pos);
 
        // Is this in a framework?
        // /path/Foo.framework/Foo                                                      ==> true (Foo)
@@ -879,7 +953,7 @@ Options::FileInfo Options::findFileUsingPaths(const std::string &path) const
        bool isFramework = false;
        if ( lastSlashPos != std::string::npos ) {
                auto frameworkDir = std::string("/").append(leafName).append(".framework/");
-               if ( path.rfind(frameworkDir) != std::string::npos )
+               if ( installName.rfind(frameworkDir) != std::string::npos )
                        isFramework = true;
        }
        
@@ -888,14 +962,12 @@ Options::FileInfo Options::findFileUsingPaths(const std::string &path) const
        // don't need to try variations, just paths. We do need to add the additional bits
        // onto the framework path though.
        if ( isFramework ) {
-               auto endPos = path.rfind(".framework");
-               auto beginPos = path.find_last_of('/', endPos);
-               auto leafPath = path.substr(beginPos);
+               auto endPos = installName.rfind(".framework");
+               auto beginPos = installName.find_last_of('/', endPos);
+               auto leafPath = installName.substr(beginPos);
                for (const auto* dir : fFrameworkSearchPaths) {
                        auto possiblePath = dir + leafPath;
-                       if ( checkForFile("%s.%s", possiblePath.c_str(), "tbd", result) )
-                               return result;
-                       if ( checkForFile("%s", possiblePath.c_str(), "", result) )
+                       if ( findFile(possiblePath, {".tbd"}, result) )
                                return result;
                }
        } else {
@@ -903,20 +975,19 @@ Options::FileInfo Options::findFileUsingPaths(const std::string &path) const
                // <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard
                bool embeddedDylib = ( (leafName.size() > 6)
                                        && (leafName.find(".dylib", leafName.size()-6) != std::string::npos)
-                                       && (path.find(".framework/") != std::string::npos) );
+                                       && (installName.find(".framework/") != std::string::npos) );
                if ( !embeddedDylib ) {
                        for (const auto* dir : fLibrarySearchPaths) {
                                //fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName);
-                               if ( checkForFile("%s/%s", dir, std::string(leafName).append(".tbd").c_str(), result) )
-                                       return result;
-                               if ( checkForFile("%s/%s", dir, leafName.c_str(), result) )
+                               std::string possiblePath = dir + std::string("/") + leafName;
+                               if ( findFile(possiblePath, {".tbd"}, result) )
                                        return result;
                        }
                }
        }
 
        // If we didn't find it fall back to findFile.
-       return findFile(path);
+       return findFile(installName, fromDylib);
 }
 
 
@@ -1395,58 +1466,32 @@ Options::Treatment Options::parseTreatment(const char* treatment)
 
 void Options::setMacOSXVersionMin(const char* version)
 {
-       if ( version == NULL )
-               throw "-macosx_version_min argument missing";
-
-       if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
-               unsigned int minorVersion = 0;
-               for (int i=3; isdigit(version[i]); ++i) {
-                       minorVersion = minorVersion*10 + (version[i] - '0');
-               }
-               if ( minorVersion > 255 ) {
-                       warning("Mac OS X minor version > 255 in '%s'", version);
-                       minorVersion = 255;
-               }
-               fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
-               fPlatform = kPlatformOSX;
-       }
-       else {
-               warning("unknown option to -macosx_version_min, not 10.x");
+       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)
 {
-       if ( version == NULL )
-               throw "-ios_version_min argument missing";
-       if ( ! isdigit(version[0]) )
-               throw "-ios_version_min argument is not a number";
-       if ( version[1] != '.' )
-               throw "-ios_version_min argument is missing period as second character";
-       if ( ! isdigit(version[2]) )
-               throw "-ios_version_min argument is not a number";
-
-       unsigned int majorVersion = version[0] - '0';
-       unsigned int minorVersion = version[2] - '0';
-       fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
+       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)
 {
-       if ( version == NULL )
-               throw "-watchos_version_min argument missing";
-       if ( ! isdigit(version[0]) )
-               throw "-watchos_version_min argument is not a number";
-       if ( version[1] != '.' )
-               throw "-watchos_version_min argument is missing period as second character";
-       if ( ! isdigit(version[2]) )
-               throw "-watchos_version_min argument is not a number";
-
-       unsigned int majorVersion = version[0] - '0';
-       unsigned int minorVersion = version[2] - '0';
-       fWatchOSVersionMin = (ld::WatchOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
+       uint32_t value;
+       if ( !parsePackedVersion32(version, value) ) {
+               throwf("-watchos_version_min value malformed: '%s'", version);
+       }
+       fWatchOSVersionMin = (ld::WatchOSVersionMin)value;
        fPlatform = kPlatformWatchOS;
 }
 
@@ -1713,6 +1758,19 @@ void Options::parseOrderFile(const char* path, bool cstring)
        // order files override auto-ordering
        fAutoOrderInitializers = false;
 
+       // <rdar://problem/24856050> ld64 should prefer OrderFiles from the SDK over the ones in /
+       for (const char* sdkPath : fSDKPaths) {
+               char fullPath[PATH_MAX];
+               strlcpy(fullPath, sdkPath, PATH_MAX);
+               strlcat(fullPath, "/", PATH_MAX);
+               strlcat(fullPath, path, PATH_MAX);
+               struct stat statBuffer;
+               if ( stat(fullPath, &statBuffer) == 0 ) {
+                       path = strdup(fullPath);
+                       break;
+               }
+       }
+
        // read in whole file
        int fd = ::open(path, O_RDONLY, 0);
        if ( fd == -1 )
@@ -1779,6 +1837,12 @@ void Options::parseOrderFile(const char* path, bool cstring)
                                        else
                                                symbolStart = NULL;
                                }
+                               else if ( strncmp(symbolStart, "arm64:", 6) == 0 ) {
+                                       if ( fArchitecture == CPU_TYPE_ARM64 )
+                                               symbolStart = &symbolStart[6];
+                                       else
+                                               symbolStart = NULL;
+                               }
                                if ( symbolStart != NULL ) {
                                        char* objFileName = NULL;
                                        char* colon = strstr(symbolStart, ".o:");
@@ -2021,6 +2085,73 @@ std::string Options::getVersionString64(uint64_t ver) const
        return versionString.str();
 }
 
+// Convert X.Y[.Z] to 32-bit value xxxxyyzz
+bool Options::parsePackedVersion32(const std::string& versionStr, uint32_t &result)
+{
+       result = 0;
+
+       if ( versionStr.empty() )
+               return false;
+
+       size_t pos = versionStr.find('.');
+       if ( pos == std::string::npos )
+               return false;
+
+       std::string majorStr = versionStr.substr(0, pos);
+       std::string rest = versionStr.substr(pos+1);
+
+       try {
+               size_t majorEnd;
+               int majorValue = std::stoi(majorStr, &majorEnd);
+               if ( majorEnd != majorStr.size() )
+                       return false;
+               if ( majorValue < 0 )
+                       return false;
+               if ( majorValue > 65535 )
+                       return false;
+
+               std::string minorStr;
+               std::string microStr;
+               pos = rest.find('.');
+               if ( pos == std::string::npos ) {
+                       minorStr = rest;
+               }
+               else {
+                       minorStr = rest.substr(0, pos);
+                       microStr = rest.substr(pos+1);
+               }
+
+               size_t minorEnd;
+               int minorValue = std::stoi(minorStr, &minorEnd);
+               if ( minorEnd != minorStr.size() )
+                       return false;
+               if ( minorValue < 0 )
+                       return false;
+               if ( minorValue > 255 )
+                       return false;
+
+               int microValue = 0;
+               if ( !microStr.empty() ) {
+                       size_t microEnd;
+                       microValue = std::stoi(microStr, &microEnd);
+                       if ( microEnd != microStr.size() )
+                               return false;
+                       if ( microValue < 0 )
+                               return false;
+                       if ( microValue > 255 )
+                               return false;
+               }
+
+               result = (majorValue << 16) | (minorValue << 8) | microValue;
+
+               return true;
+       }
+       catch (...) {
+               // std::stoi() throws exception on malformed input
+               return false;
+       }
+}
+
 std::string Options::getSDKVersionStr() const
 {
        return getVersionString32(fSDKVersion);
@@ -2281,6 +2412,40 @@ void Options::parse(int argc, const char* argv[])
                                if ( fOverridePathlibLTO == NULL )
                                        throw "missing argument to -lto_library";
                        }
+                       else if ( strcmp(arg, "-cache_path_lto") == 0 ) {
+                               fLtoCachePath = argv[++i];
+                               if ( fLtoCachePath == NULL )
+                                       throw "missing argument to -cache_path_lto";
+                       }
+                       else if ( strcmp(arg, "-prune_interval_lto") == 0 ) {
+                               const char* value = argv[++i];
+                               if ( value == NULL )
+                                       throw "missing argument to -prune_interval_lto";
+                               char* endptr;
+                               fLtoPruneInterval = strtoul(value, &endptr, 10);
+                               if ( *endptr != '\0')
+                                       throw "invalid argument for -prune_interval_lto";
+                       }
+                       else if ( strcmp(arg, "-prune_after_lto") == 0 ) {
+                               const char* value = argv[++i];
+                               if ( value == NULL )
+                                       throw "missing argument to -prune_after_lto";
+                               char* endptr;
+                               fLtoPruneAfter = strtoul(value, &endptr, 10);
+                               if ( *endptr != '\0')
+                                       throw "invalid argument for -prune_after_lto";
+                       }
+                       else if ( strcmp(arg, "-max_relative_cache_size_lto") == 0 ) {
+                               const char* value = argv[++i];
+                               if ( value == NULL )
+                                       throw "missing argument to -max_relative_cache_size_lto";
+                               char* endptr;
+                               fLtoMaxCacheSize = strtoul(value, &endptr, 10);
+                               if ( *endptr != '\0')
+                                       throw "invalid argument for -max_relative_cache_size_lto";
+                               if (fLtoMaxCacheSize > 100)
+                                       throw "Expect a value between 0 and 100 for -max_relative_cache_size_lto";
+                       }
                        else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) {
                 snapshotArgCount = 0;
                                FileInfo info = findLibrary(&arg[2]);
@@ -2360,7 +2525,6 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-order_file") == 0 ) {
                 snapshotFileArgIndex = 1;
                                parseOrderFile(argv[++i], false);
-                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
                                fPrintOrderFileStatistics = true;
@@ -2452,7 +2616,6 @@ void Options::parse(int argc, const char* argv[])
                                        throw "can't use -unexported_symbols_list and -exported_symbols_list";
                                fExportMode = kDontExportSome;
                                loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
-                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-exported_symbol") == 0 ) {
                                if ( fExportMode == kDontExportSome )
@@ -2465,7 +2628,6 @@ void Options::parse(int argc, const char* argv[])
                                        throw "can't use -unexported_symbol and -exported_symbol";
                                fExportMode = kDontExportSome;
                                fDontExportSymbols.insert(argv[++i]);
-                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2692,7 +2854,10 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-segprot missing segName max-prot init-prot";
                                seg.max = parseProtection(argv[++i]);
                                seg.init = parseProtection(argv[++i]);
-                               fCustomSegmentProtections.push_back(seg);
+                               if ( strcmp(seg.name, "__LINKEDIT") == 0 )
+                                       warning("-segprot cannot be used to modify __LINKEDIT protections");
+                               else
+                                       fCustomSegmentProtections.push_back(seg);
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-pagezero_size") == 0 ) {
@@ -2718,9 +2883,6 @@ void Options::parse(int argc, const char* argv[])
                                 if ( size == NULL )
                                        throw "-stack_size missing <address>";
                                fStackSize = parseAddress(size);
-                               uint64_t temp = fStackSize & (-4096); // page align
-                               if ( (fStackSize != temp)  )
-                                       warning("-stack_size not page aligned, rounding down");
                        }
                        else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
                                fExecutableStack = true;
@@ -2763,6 +2925,8 @@ 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* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                                const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                                if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
@@ -2785,26 +2949,44 @@ void Options::parse(int argc, const char* argv[])
                                }
                        }
                        else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
-                               setIOSVersionMin(argv[++i]); 
+                               const char* vers = argv[++i];
+                               if ( vers == NULL )
+                                       throw "-ios_version_min missing version argument";
+                               setIOSVersionMin(vers);
                        }
                        else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
-                               setIOSVersionMin(argv[++i]);
+                               const char* vers = argv[++i];
+                               if ( vers == NULL )
+                                       throw "-ios_simulator_version_min missing version argument";
+                               setIOSVersionMin(vers);
                                fTargetIOSSimulator = true;
                        }
                        else if ( strcmp(arg, "-watchos_version_min") == 0 ) {
-                               setWatchOSVersionMin(argv[++i]);
+                               const char* vers = argv[++i];
+                               if ( vers == NULL )
+                                       throw "-watchos_version_min missing version argument";
+                               setWatchOSVersionMin(vers);
                        }
                        else if ( strcmp(arg, "-watchos_simulator_version_min") == 0 ) {
-                               setWatchOSVersionMin(argv[++i]);
+                               const char* vers = argv[++i];
+                               if ( vers == NULL )
+                                       throw "-watchos_simulator_version_min missing version argument";
+                               setWatchOSVersionMin(vers);
                                fTargetIOSSimulator = true;
                        }
        #if SUPPORT_APPLE_TV
                        else if ( strcmp(arg, "-tvos_version_min") == 0 ) {
-                               setIOSVersionMin(argv[++i]);
+                               const char* vers = argv[++i];
+                               if ( vers == NULL )
+                                       throw "-tvos_version_min missing version argument";
+                               setIOSVersionMin(vers);
                                fPlatform = kPlatform_tvOS;
                        }
                        else if ( strcmp(arg, "-tvos_simulator_version_min") == 0 ) {
-                               setIOSVersionMin(argv[++i]);
+                               const char* vers = argv[++i];
+                               if ( vers == NULL )
+                                       throw "-tvos_simulator_version_min missing version argument";
+                               setIOSVersionMin(vers);
                                fPlatform = kPlatform_tvOS;
                                fTargetIOSSimulator = true;
                        }
@@ -3061,13 +3243,9 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-bitcode_hide_symbols") == 0 ) {
                                fHideSymbols = true;
-                               if ( !fBundleBitcode )
-                                       warning("-bitcode_hide_symbols is ignored without -bitcode_bundle");
                        }
                        else if ( strcmp(arg, "-bitcode_verify") == 0 ) {
                                fVerifyBitcode = true;
-                               if ( !fBundleBitcode )
-                                       warning("-bitcode_verify is ignored without -bitcode_bundle");
                        }
                        else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
                                fReverseMapPath = argv[++i];
@@ -3628,6 +3806,45 @@ void Options::parse(int argc, const char* argv[])
                                fUseDataConstSegmentForceOff = true;
                                cannotBeUsedWithBitcode(arg);
                        }
+                       else if ( strcmp(arg, "-text_exec") == 0 ) {
+                               fUseTextExecSegment = true;
+                               cannotBeUsedWithBitcode(arg);
+                       }
+                       else if ( strcmp(arg, "-add_split_seg_info") == 0) {
+                               fSharedRegionEligible = true;
+                               cannotBeUsedWithBitcode(arg);
+                       }
+                       else if ( strcmp(arg, "-no_deduplicate") == 0 ) {
+                               fDeDupe = false;
+                       }
+                       else if ( strcmp(arg, "-verbose_deduplicate") == 0 ) {
+                               fVerboseDeDupe = true;
+                       }
+                       else if ( strcmp(arg, "-max_default_common_align") == 0 ) {
+                               const char* alignStr = argv[++i];
+                               if ( alignStr == NULL )
+                                       throw "-max_default_common_align missing <align-value>";
+                               // argument is a hexadecimal number
+                               char* endptr;
+                               unsigned long value = strtoul(alignStr, &endptr, 16);
+                               if ( *endptr != '\0')
+                                       throw "argument for -max_default_common_align is not a hexadecimal number";
+                               if ( value > 0x8000 )
+                                       throw "argument for -max_default_common_align must be less than or equal to 0x8000";
+                               if ( value == 0 ) {
+                                       warning("zero is not a valid -max_default_common_align");
+                                       value = 1;
+                               }
+                               // alignment is power of 2 
+                               uint8_t alignment = (uint8_t)__builtin_ctz(value);
+                               if ( (unsigned long)(1 << alignment) != value ) {
+                                       warning("alignment for -max_default_common_align is not a power of two, using 0x%X", 1 << alignment);
+                               }
+                               fMaxDefaultCommonAlign = alignment;
+                       }
+                       else if ( strcmp(argv[i], "-no_weak_imports") == 0 ) {
+                               fAllowWeakImports = false;
+                       }
                        // 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, ':');
@@ -3702,16 +3919,7 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        }
                        if ( libSearchDir[0] == '\0' ) 
                                throw "-L must be immediately followed by a directory path (no space)";
-                       struct stat statbuf;
-                       if ( stat(libSearchDir, &statbuf) == 0 ) {
-                               if ( statbuf.st_mode & S_IFDIR )
-                                       libraryPaths.push_back(libSearchDir);
-                               else
-                                       warning("path '%s' following -L not a directory", libSearchDir);
-                       }
-                       else {
-                               warning("directory not found for option '-L%s'", libSearchDir);
-                       }
+                       libraryPaths.push_back(libSearchDir);
                }
                else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) {
                        const char* frameworkSearchDir = &argv[i][2];
@@ -3725,16 +3933,7 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        }
                        if ( frameworkSearchDir[0] == '\0' ) 
                                throw "-F must be immediately followed by a directory path (no space)";
-                       struct stat statbuf;
-                       if ( stat(frameworkSearchDir, &statbuf) == 0 ) {
-                               if ( statbuf.st_mode & S_IFDIR )
-                                       frameworkPaths.push_back(frameworkSearchDir);
-                               else
-                                       warning("path '%s' following -F not a directory", frameworkSearchDir);
-                       }
-                       else {
-                               warning("directory not found for option '-F%s'", frameworkSearchDir);
-                       }
+                       frameworkPaths.push_back(frameworkSearchDir);
                }
                else if ( strcmp(argv[i], "-Z") == 0 )
                        addStandardLibraryDirectories = false;
@@ -3748,6 +3947,7 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                const char* ltoVers = lto::version();
                                if ( ltoVers != NULL )
                                        fprintf(stderr, "LTO support using: %s\n", ltoVers);
+                               fprintf(stderr, "TAPI support using: %s\n", tapi::Version::getFullVersionAsString().c_str());
                                exit(0);
                        }
                }
@@ -3821,8 +4021,13 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                strcat(newPath, libDir);
                                struct stat statBuffer;
                                if ( stat(newPath, &statBuffer) == 0 ) {
-                                       fLibrarySearchPaths.push_back(strdup(newPath));
-                                       sdkOverride = true;
+                                       if ( (statBuffer.st_mode & S_IFDIR) == 0 ) {
+                                               warning("-syslibroot and -L combined path '%s' is not a directory", newPath);
+                                       }
+                                       else {
+                                               fLibrarySearchPaths.push_back(strdup(newPath));
+                                               sdkOverride = true;
+                                       }
                                }
                        }
                }
@@ -3832,11 +4037,21 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                // if one SDK is specified and a standard library path is not in the SDK, don't use it
                        }
                        else {
-                               fLibrarySearchPaths.push_back(libDir);
+                               struct stat statBuffer;
+                               if ( stat(libDir, &statBuffer) == 0 ) {
+                                       if ( (statBuffer.st_mode & S_IFDIR) == 0 )
+                                               warning("-L path '%s' is not a directory", libDir);
+                                       else
+                                               fLibrarySearchPaths.push_back(libDir);
+                               }
+                               else if ( !addStandardLibraryDirectories || (strcmp(libDir, "/usr/local/lib") != 0) ) {
+                                       warning("directory not found for option '-L%s'", libDir);
+                               }
                        }
                }
        }
 
+
        // now merge sdk and framework paths to make real search paths
        fFrameworkSearchPaths.reserve(frameworkPaths.size()*(fSDKPaths.size()+1));
        int frameIndex = 0;
@@ -3860,8 +4075,13 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                strcat(newPath, frameworkDir);
                                struct stat statBuffer;
                                if ( stat(newPath, &statBuffer) == 0 ) {
-                                       fFrameworkSearchPaths.push_back(strdup(newPath));
-                                       sdkOverride = true;
+                                       if ( (statBuffer.st_mode & S_IFDIR) == 0 ) {
+                                               warning("-syslibroot and -F combined path '%s' is not a directory", newPath);
+                                       }
+                                       else {
+                                               fFrameworkSearchPaths.push_back(strdup(newPath));
+                                               sdkOverride = true;
+                                       }
                                }
                        }
                }
@@ -3871,7 +4091,16 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                // if one SDK is specified and a standard library path is not in the SDK, don't use it
                        }
                        else {
-                               fFrameworkSearchPaths.push_back(frameworkDir);
+                               struct stat statBuffer;
+                               if ( stat(frameworkDir, &statBuffer) == 0 ) {
+                                       if ( (statBuffer.st_mode & S_IFDIR) == 0 )
+                                               warning("-F path '%s' is not a directory", frameworkDir);
+                                       else
+                                               fFrameworkSearchPaths.push_back(frameworkDir);
+                               }
+                               else if ( !addStandardLibraryDirectories || (strcmp(frameworkDir, "/Library/Frameworks/") != 0) ) {
+                                       warning("directory not found for option '-F%s'", frameworkDir);
+                               }
                        }
                }
        }
@@ -3902,6 +4131,11 @@ void Options::parsePreCommandLineEnvironmentSettings()
            fTraceDylibs = true;
                fTraceIndirectDylibs = true;
        }
+       
+       if ((getenv("LD_TRACE_DEPENDENTS") != NULL)) {
+               
+               fTraceEmitJSON = true;
+       }
 
        if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) {
            fTraceDylibSearching = true;
@@ -3910,7 +4144,7 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_PRINT_OPTIONS") != NULL)
                fPrintOptions = true;
 
-       if (fTraceDylibs || fTraceArchives)
+       if (fTraceDylibs || fTraceArchives || fTraceEmitJSON)
                fTraceOutputFile = getenv("LD_TRACE_FILE");
 
        if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL)
@@ -3933,6 +4167,9 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL)
                fAllowCpuSubtypeMismatches = true;
        
+       if (getenv("LD_DYLIB_CPU_SUBTYPES_MUST_MATCH") != NULL)
+               fEnforceDylibSubtypesMatch = true;
+       
        sWarningsSideFilePath = getenv("LD_WARN_FILE");
        
        const char* customDyldPath = getenv("LD_DYLD_PATH");
@@ -4332,7 +4569,7 @@ void Options::reconfigureDefaults()
 
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
-               if ( minOS(ld::mac10_5, ld::iOS_3_1) )
+               if ( minOS(ld::mac10_5, ld::iOS_3_1) && !fTargetIOSSimulator )
                        if ( !fPrebind && !fSharedRegionEligibleForceOff )
                                if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
                                        || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
@@ -4354,6 +4591,12 @@ void Options::reconfigureDefaults()
        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) ) {
+               fUseDataConstSegment = true;
+               fUseTextExecSegment = true;
+               fSharedRegionEligible = true;
+       }
        if ( fUseDataConstSegment ) {
                addSectionRename("__DATA", "__got",                             "__DATA_CONST", "__got");
                addSectionRename("__DATA", "__la_symbol_ptr",   "__DATA_CONST", "__la_symbol_ptr");
@@ -4370,10 +4613,17 @@ void Options::reconfigureDefaults()
                addSectionRename("__DATA", "__objc_imageinfo",  "__DATA_CONST", "__objc_imageinfo");
                addSectionRename("__DATA", "__objc_const",          "__DATA_CONST", "__objc_const");
        }
+       if ( fUseTextExecSegment ) {
+               addSectionRename("__TEXT", "__text",                            "__TEXT_EXEC", "__text");
+               addSectionRename("__TEXT", "__stubs",                           "__TEXT_EXEC", "__stubs");
+       }
        
        // Use V2 shared cache info when targetting newer OSs
-       if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0)) {
+       if ( fSharedRegionEligible && minOS(ld::mac10_12, ld::iOS_9_0)) {
                fSharedRegionEncodingV2 = true;
+               // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
+               if ( (fPlatform == kPlatformOSX) && (strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) != 0) )
+                       fSharedRegionEncodingV2 = false;
                fIgnoreOptimizationHints = true;
        }
 
@@ -4465,7 +4715,8 @@ void Options::reconfigureDefaults()
                                fEncryptable = false;
                        break;
        }
-       if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
+       if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64)
+         )
                fEncryptable = false;
        if ( fEncryptableForceOn )
                fEncryptable = true;
@@ -4522,11 +4773,13 @@ void Options::reconfigureDefaults()
        // only ARM and x86_64 enforces that cpu-sub-types must match
        switch ( fArchitecture ) {
                case CPU_TYPE_ARM:
+                       break;
                case CPU_TYPE_X86_64:
+                       fEnforceDylibSubtypesMatch = false;
                        break;
                case CPU_TYPE_I386:
                case CPU_TYPE_ARM64:
-                       fAllowCpuSubtypeMismatches = true;
+                       fEnforceDylibSubtypesMatch = false;
                        break;
        }
                
@@ -4565,7 +4818,7 @@ void Options::reconfigureDefaults()
                fCanUseUpwardDylib = true;
                
        // MacOSX 10.7 defaults to PIE
-       if ( ((fArchitecture == CPU_TYPE_X86_64) || (fArchitecture == CPU_TYPE_I386))
+       if ( (fArchitecture == CPU_TYPE_I386)
                && (fOutputKind == kDynamicExecutable)
                && (fMacVersionMin >= ld::mac10_7) ) {
                        fPositionIndependentExecutable = true;
@@ -4579,6 +4832,10 @@ void Options::reconfigureDefaults()
                        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) )
+               fPositionIndependentExecutable = true;
+
        // Simulator defaults to PIE
        if ( fTargetIOSSimulator && (fOutputKind == kDynamicExecutable) )
                fPositionIndependentExecutable = true;
@@ -4588,8 +4845,12 @@ void Options::reconfigureDefaults()
                fPositionIndependentExecutable = false;
 
        // arm64 is always PIE
-       if ( (fArchitecture == CPU_TYPE_ARM64) && (fOutputKind == kDynamicExecutable) ) {
+       if ( ((fArchitecture == CPU_TYPE_ARM64)
+          )
+        && (fOutputKind == kDynamicExecutable) ) {
                fPositionIndependentExecutable = true;
+               if ( fDisablePositionIndependentExecutable )
+                       warning("-no_pie ignored for arm64");
        }
 
        // set fOutputSlidable
@@ -4616,12 +4877,20 @@ void Options::reconfigureDefaults()
        if ( fMacVersionMin >= ld::mac10_7 ) {
                fTLVSupport = true;
        }
-       else if ( (fArchitecture == CPU_TYPE_ARM64) && min_iOS(ld::iOS_8_0) ) {
+       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) ) {
+               fTLVSupport = true;
+       }
 
        // default to adding version load command for dynamic code, static code must opt-in
        switch ( fOutputKind ) {
@@ -4801,7 +5070,8 @@ void Options::reconfigureDefaults()
                        case Options::kDynamicLibrary:
                        case Options::kDynamicBundle:
                        case Options::kDyld:
-                               if ( (fArchitecture == CPU_TYPE_ARM64) 
+                               if ( ((fArchitecture == CPU_TYPE_ARM64)
+                     )
                                || ((fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_7_0)) ) {
                                        fSegmentAlignment = 4096*4;
                                }
@@ -4809,7 +5079,9 @@ void Options::reconfigureDefaults()
                        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)
+                     )
+                                   && min_iOS(ld::iOS_9_0) ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
@@ -4870,6 +5142,13 @@ void Options::reconfigureDefaults()
                }
        }
 
+       // <rdar://problem/20503811> Reduce the default alignment of structures/arrays to save memory in embedded systems
+       if ( fMaxDefaultCommonAlign == 0 ) {
+               if ( fOutputKind == Options::kPreload )
+                       fMaxDefaultCommonAlign = 8;
+               else
+                       fMaxDefaultCommonAlign = 15;
+       }
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -4877,9 +5156,24 @@ void Options::checkIllegalOptionCombinations()
        // check -undefined setting
        switch ( fUndefinedTreatment ) {
                case kUndefinedError:
-               case kUndefinedDynamicLookup:
                        // always legal
                        break;
+               case kUndefinedDynamicLookup:
+                       switch (fPlatform) {
+                               case kPlatformOSX:
+                                       break;
+                               case kPlatformiOS:
+                               case kPlatformWatchOS:
+               #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 kUndefinedWarning:
                case kUndefinedSuppress:
                        // requires flat namespace
@@ -4897,7 +5191,11 @@ void Options::checkIllegalOptionCombinations()
                        const char* lastSlash = strrchr(info.path, '/');
                        if ( lastSlash == NULL )
                                lastSlash = info.path - 1;
-                       if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) {
+                       std::string path(&lastSlash[1]);
+                       auto idx = path.find(".tbd", path.size() - 4);
+                       if (idx != std::string::npos)
+                               path.erase(idx);
+                       if ( path == subUmbrella ) {
                                info.options.fReExport = true;
                                found = true;
                 fLinkSnapshot.recordSubUmbrella(info.path);
@@ -4932,8 +5230,23 @@ void Options::checkIllegalOptionCombinations()
        }
 
        // sync reader options
-       if ( fNameSpace != kTwoLevelNameSpace )
+       if ( fNameSpace != kTwoLevelNameSpace ) {
                fFlatNamespace = true;
+               switch (fPlatform) {
+                       case kPlatformOSX:
+                               break;
+                       case kPlatformiOS:
+                       case kPlatformWatchOS:
+       #if SUPPORT_APPLE_TV
+                       case Options::kPlatform_tvOS:
+       #endif
+                               warning("-flat_namespace is deprecated on %s", platformName(fPlatform));
+                               break;
+                       default:
+                               break;
+               }
+       }
+
 
        // check -stack_addr
        if ( fStackAddr != 0 ) {
@@ -4957,37 +5270,54 @@ void Options::checkIllegalOptionCombinations()
        if ( fStackSize != 0 ) {
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
-                               if ( fStackSize > 0xFFFFFFFF )
-                                       throw "-stack_size must be < 4G for 32-bit processes";
-                               if ( fStackAddr == 0 ) {
-                                       fStackAddr = 0xC0000000;
+                               if ( fPlatform == kPlatformOSX ) {
+                                       if ( fStackSize > 0xFFFFFFFF )
+                                               throw "-stack_size must be < 4GB for 32-bit processes";
+                                       if ( fStackAddr == 0 )
+                                               fStackAddr = 0xC0000000;
+                                       if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000)  )
+                                               warning("custom stack placement overlaps and will disable shared region");
+                               }
+                               else {
+                                       if ( fStackSize > 0x1F000000 )
+                                               throw "-stack_size must be < 496MB";
+                                       if ( fStackAddr == 0 )
+                                               fStackAddr = 0xC0000000;
                                }
-                               if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000)  )
-                                       warning("custom stack placement overlaps and will disable shared region");
                                break;
             case CPU_TYPE_ARM:
-                               if ( fStackSize > 0x2F000000 )
-                                       throw "-stack_size must be < 752MB";
+                               if ( fStackSize > 0x1F000000 )
+                                       throw "-stack_size must be < 496MB";
                                if ( fStackAddr == 0 )
-                                       fStackAddr = 0x2F000000;
-                if ( fStackAddr > 0x30000000)
-                    throw "-stack_addr must be < 0x30000000 for arm";
+                                       fStackAddr = 0x1F000000;
+                if ( fStackAddr > 0x20000000)
+                    throw "-stack_addr must be < 0x20000000 for arm";
                                break;
                        case CPU_TYPE_X86_64:
-                               if ( fStackAddr == 0 ) {
-                                       fStackAddr = 0x00007FFF5C000000LL;
+                               if ( fPlatform == kPlatformOSX ) {
+                                       if ( fStackSize > 0x10000000000 )
+                                               throw "-stack_size must be <= 1TB";
+                                       if ( fStackAddr == 0 ) {
+                                               fStackAddr = 0x00007FFF5C000000LL;
+                                       }
+                               }
+                               else {
+                                       if ( fStackSize > 0x20000000 )
+                                               throw "-stack_size must be <= 512MB";
+                                       if ( fStackAddr == 0 ) {
+                                               fStackAddr = 0x120000000;
                                }
                                break;
                        case CPU_TYPE_ARM64:
                                if ( fStackSize > 0x20000000 )
-                                       throw "-stack_size must be < 512MB";
-                               if ( fStackAddr == 0 ) {
+                                       throw "-stack_size must be <= 512MB";
+                               if ( fStackAddr == 0 )
                                        fStackAddr = 0x120000000;
                                }
                                break;
                }
-               if ( (fStackSize & -4096) != fStackSize )
-                       throw "-stack_size must be multiples of 4K";
+               if ( (fStackSize & (-fSegmentAlignment)) != fStackSize )
+                       throwf("-stack_size must be multiple of segment alignment (%lldKB)", fSegmentAlignment/1024);
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
                        case Options::kStaticExecutable:
@@ -5187,7 +5517,7 @@ void Options::checkIllegalOptionCombinations()
                // zero page size not specified on command line, set default
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
-            case CPU_TYPE_ARM:
+                       case CPU_TYPE_ARM:
                                // first 4KB for 32-bit architectures
                                fZeroPageSize = 0x1000;
                                break;
@@ -5310,13 +5640,19 @@ void Options::checkIllegalOptionCombinations()
        if ( (fOutputKind != Options::kDynamicExecutable) && (fDyldEnvironExtras.size() != 0) )
                throw "-dyld_env can only used used when created main executables";
 
-       // -segment_order can only be used with -preload
-       if ( !fSegmentOrder.empty() && (fOutputKind != Options::kPreload) )
+       // -segment_order can only be used with -preload or -static
+       if ( !fSegmentOrder.empty() && ((fOutputKind != Options::kPreload) && (fOutputKind != kStaticExecutable)) )
                throw "-segment_order can only used used with -preload output";
 
-       if ( fBitcodeKind != kBitcodeProcess &&
-                fOutputKind != Options::kObjectFile ) {
-               throw "-bitcode_process_mode can only be used together with -r";
+       // warn about bitcode option combinations
+       if ( !fBundleBitcode ) {
+               if ( fVerifyBitcode )
+                       warning("-bitcode_verify is ignored without -bitcode_bundle");
+               else if ( fHideSymbols )
+                       warning("-bitcode_hide_symbols is ignored without -bitcode_bundle");
+       }
+       if ( fReverseMapPath != NULL && !fHideSymbols ) {
+               throw "-bitcode_symbol_map can only be used with -bitcode_hide_symbols";
        }
        // auto fix up the process type for strip -S.
        // when there is only one input and output type is object file, downgrade kBitcodeProcess to kBitcodeAsData.
@@ -5324,11 +5660,17 @@ void Options::checkIllegalOptionCombinations()
                fBitcodeKind = Options::kBitcodeAsData;
 
        // <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?
+       // <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 )
                        warning("embedded dylibs/frameworks only run on iOS 8 or later");
        }
+
+
+       // produce nicer error when no input
+       if ( fInputFiles.empty() ) {
+               throw "no object files specified";
+       }
 }      
 
 
@@ -5532,4 +5874,28 @@ void Options::dumpDependency(uint8_t opcode, const char* path) const
 }
 
 
+void Options::writeToTraceFile(const char* buffer, size_t len) const
+{
+       // one time open() of custom LD_TRACE_FILE
+       if ( fTraceFileDescriptor == -1 ) {
+               if ( fTraceOutputFile != NULL ) {
+                       fTraceFileDescriptor = open(fTraceOutputFile, O_WRONLY | O_APPEND | O_CREAT, 0666);
+                       if ( fTraceFileDescriptor == -1 )
+                               throwf("Could not open or create trace file (errno=%d): %s", errno, fTraceOutputFile);
+               }
+               else {
+                       fTraceFileDescriptor = fileno(stderr);
+               }
+       }
+
+       while (len > 0) {
+               ssize_t amountWritten = write(fTraceFileDescriptor, buffer, len);
+               if ( amountWritten == -1 )
+                       /* Failure to write shouldn't fail the build. */
+                       return;
+               buffer += amountWritten;
+               len -= amountWritten;
+       }
+}
+