]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/Options.cpp
ld64-274.1.tar.gz
[apple/ld64.git] / src / ld / Options.cpp
index 0f5985de5e3ea9832a0d3747c0a3d5144b83468e..faf9c169878445d50fdeabde1f4039a12a41bb75 100644 (file)
@@ -34,6 +34,7 @@
 #include <spawn.h>
 #include <cxxabi.h>
 #include <Availability.h>
+#include <tapi/tapi.h>
 
 #include <vector>
 #include <map>
@@ -125,6 +126,7 @@ bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
        }
        if ( options.dumpDependencyInfo() )
                options.dumpDependency(Options::depNotFound, p);
+//     fprintf(stderr, "not found: %s\n", p);
     return false;
 }
 
@@ -165,7 +167,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,16 +187,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), fDeDupe(true), fVerboseDeDupe(false),
          fReverseMapPath(NULL), fLTOCodegenOnly(false),
-         fIgnoreAutoLink(false), fAllowDeadDups(false), fBitcodeKind(kBitcodeProcess),
+         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), fMaxDefaultCommonAlign(0), fFilePreference(kModTime),
-         fForceTextBasedStub(false)
+         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fMaxDefaultCommonAlign(0)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -320,12 +321,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;
        }
@@ -392,6 +396,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;
 }
 
@@ -401,6 +408,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;
 }
 
@@ -605,7 +615,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);
@@ -617,7 +627,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);
@@ -817,52 +827,67 @@ bool Options::findFile(const std::string &path, const std::vector<std::string> &
                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 ) {
-                       if ( (fFilePreference == kTextBasedStub) || fForceTextBasedStub ) {
-                               result = tbdInfo;
-                               return true;
-                       } else {
-                               break;
-                       }
-               }
+               if ( found )
+                       break;
        }
 
+       // If we found a text-based stub file, check if it should be used.
+       if ( !tbdInfo.missing() ) {
+               if (tapi::LinkerInterfaceFile::shouldPreferTextBasedStubFile(tbdInfo.path)) {
+                       result = tbdInfo;
+                       return true;
+               }
+       }
        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());
-               if ( found &&  (fFilePreference == kMachO) ) {
-                       result = dylibInfo;
-                       return true;
-               }
        }
 
-       if ( !dylibInfo.missing() && tbdInfo.missing() ) {
-               result = dylibInfo;
+       // There is only a text-based stub file.
+       if ( !tbdInfo.missing() && dylibInfo.missing() ) {
+               result = tbdInfo;
                return true;
        }
-       else if ( dylibInfo.missing() && !tbdInfo.missing() ) {
-               result = tbdInfo;
+       // There is only a dynamic library file.
+       else if ( tbdInfo.missing() && !dylibInfo.missing() ) {
+               result = dylibInfo;
                return true;
        }
-       else if ( !dylibInfo.missing() && !tbdInfo.missing() ) {
-               if ( dylibInfo.modTime == tbdInfo.modTime ) {
+       // There are both - a text-based stub file and a dynamic library file.
+       else if ( !tbdInfo.missing() && !dylibInfo.missing() ) {
+               // If the files are still in synv we can use and should use the text-based stub file.
+               if (tapi::LinkerInterfaceFile::areEquivalent(tbdInfo.path, dylibInfo.path)) {
                        result = tbdInfo;
-                       return true;
                }
+               // Otherwise issue a warning and fall-back to the dynamic library file.
                else {
-                       // <rdar://problem/24459693> Disable false warning about out-of-sync .tbd files.
-                       //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);
+                       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;
-                       return true;
+
                }
+               return true;
        }
 
        return false;
 }
 
-Options::FileInfo Options::findFile(const std::string &path) const
+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;
 
@@ -874,35 +899,59 @@ Options::FileInfo Options::findFile(const std::string &path) const
                                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;
+               }
+               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;
 
-       // 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]);
-
-               if ( findFile(newPath, {".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)
@@ -911,7 +960,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;
        }
        
@@ -920,9 +969,9 @@ 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 ( findFile(possiblePath, {".tbd"}, result) )
@@ -933,7 +982,7 @@ 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);
@@ -945,7 +994,7 @@ Options::FileInfo Options::findFileUsingPaths(const std::string &path) const
        }
 
        // If we didn't find it fall back to findFile.
-       return findFile(path);
+       return findFile(installName, fromDylib);
 }
 
 
@@ -1716,6 +1765,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 )
@@ -2357,6 +2419,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]);
@@ -3717,6 +3813,14 @@ 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;
                        }
@@ -3745,14 +3849,8 @@ void Options::parse(int argc, const char* argv[])
                                }
                                fMaxDefaultCommonAlign = alignment;
                        }
-                       else if ( strcmp(arg, "-prefer-mod-time-check") == 0 ) {
-                               fFilePreference = kModTime;
-                       }
-                       else if ( strcmp(arg, "-prefer-text-based-stub-file") == 0 ) {
-                               fFilePreference = kTextBasedStub;
-                       }
-                       else if ( strcmp(arg, "-prefer-macho-file") == 0 ) {
-                               fFilePreference = kMachO;
+                       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 ) {
@@ -3856,6 +3954,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);
                        }
                }
@@ -4039,6 +4138,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;
@@ -4047,7 +4151,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)
@@ -4091,10 +4195,6 @@ void Options::parsePreCommandLineEnvironmentSettings()
     if (pipeFdString != NULL) {
                fPipelineFifo = pipeFdString;
     }
-
-       // Workaround for rdar://problem/24301175
-       if ((getenv("RC_XBS") != NULL) && !(getenv("RC_BUILDIT") != NULL))
-               fForceTextBasedStub = true;
 }
 
 
@@ -4476,7 +4576,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) )
@@ -4498,6 +4598,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");
@@ -4514,10 +4620,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;
        }
 
@@ -4609,7 +4722,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;
@@ -4673,7 +4787,6 @@ void Options::reconfigureDefaults()
                case CPU_TYPE_I386:
                case CPU_TYPE_ARM64:
                        fEnforceDylibSubtypesMatch = false;
-                       fAllowCpuSubtypeMismatches = true;
                        break;
        }
                
@@ -4712,7 +4825,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;
@@ -4726,6 +4839,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;
@@ -4735,8 +4852,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
@@ -4763,7 +4884,9 @@ 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) ) {
@@ -4954,7 +5077,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;
                                }
@@ -4962,7 +5086,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;
@@ -5398,7 +5524,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;
@@ -5521,8 +5647,8 @@ 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";
 
        // warn about bitcode option combinations
@@ -5550,6 +5676,12 @@ void Options::checkIllegalOptionCombinations()
                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";
+       }
 }